diff options
Diffstat (limited to 'indra/llrender/llimagegl.cpp')
-rw-r--r-- | indra/llrender/llimagegl.cpp | 356 |
1 files changed, 221 insertions, 135 deletions
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index a9b47960b7..d0d55b8526 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -51,6 +51,7 @@ extern LL_COMMON_API bool on_main_thread(); //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; +const F32 CONVERSION_SCRATCH_BUFFER_GL_VERSION = 3.29f; //which power of 2 is i? //assumes i is a power of 2 > 0 @@ -67,12 +68,13 @@ static U64 sTextureBytes = 0; // track a texture alloc on the currently bound texture. // asserts that no currently tracked alloc exists -void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 pixformat) +void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count) { U32 texUnit = gGL.getCurrentTexUnitIndex(); llassert(texUnit == 0); // allocations should always be done on tex unit 0 U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); - U64 size = LLImageGL::dataFormatBytes(pixformat, width, height); + U64 size = LLImageGL::dataFormatBytes(intformat, width, height); + size *= count; llassert(size >= 0); @@ -159,6 +161,7 @@ S32 LLImageGL::sMaxCategories = 1 ; bool LLImageGL::sSkipAnalyzeAlpha; U32 LLImageGL::sScratchPBO = 0; U32 LLImageGL::sScratchPBOSize = 0; +U32* LLImageGL::sManualScratch = nullptr; //------------------------ @@ -256,8 +259,24 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz if (thread_texture_loads || thread_media_updates) { LLImageGLThread::createInstance(window); - LLImageGLThread::sEnabledTextures = thread_texture_loads; - LLImageGLThread::sEnabledMedia = thread_media_updates; + LLImageGLThread::sEnabledTextures = gGLManager.mGLVersion > 3.95f ? thread_texture_loads : false; + LLImageGLThread::sEnabledMedia = gGLManager.mGLVersion > 3.95f ? thread_media_updates : false; + } +} + +void LLImageGL::allocateConversionBuffer() +{ + if (gGLManager.mGLVersion < CONVERSION_SCRATCH_BUFFER_GL_VERSION) + { + try + { + sManualScratch = new U32[MAX_IMAGE_AREA]; + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate sManualScratch" << LL_ENDL; + } } } @@ -272,6 +291,8 @@ void LLImageGL::cleanupClass() sScratchPBO = 0; sScratchPBOSize = 0; } + + delete[] sManualScratch; } @@ -280,6 +301,27 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) { switch (dataformat) { +#if GL_VERSION_3_0 + case GL_COMPRESSED_RED: return 8; +#endif + case GL_COMPRESSED_RG: return 16; +#if GL_VERSION_1_3 + case GL_COMPRESSED_RGB: return 24; +#endif +#if GL_VERSION_2_1 + case GL_COMPRESSED_SRGB: return 32; +#endif +#if GL_VERSION_1_3 + case GL_COMPRESSED_RGBA: return 32; +#endif +#if GL_VERSION_2_1 + case GL_COMPRESSED_SRGB_ALPHA: return 32; +#endif +#if GL_VERSION_1_3 + case GL_COMPRESSED_LUMINANCE: return 8; + case GL_COMPRESSED_LUMINANCE_ALPHA: return 16; + case GL_COMPRESSED_ALPHA: return 8; +#endif #if GL_EXT_texture_compression_s3tc || GL_EXT_texture_compression_dxt1 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; @@ -291,25 +333,40 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8; #endif case GL_LUMINANCE: return 8; + case GL_LUMINANCE8: return 8; case GL_ALPHA: return 8; + case GL_ALPHA8: return 8; case GL_RED: return 8; + case GL_R8: return 8; #if GL_VERSION_1_1 case GL_COLOR_INDEX: return 8; #endif case GL_LUMINANCE_ALPHA: return 16; + case GL_LUMINANCE8_ALPHA8: return 16; + case GL_RG: return 16; + case GL_RG8: return 16; case GL_RGB: return 24; case GL_SRGB: return 24; case GL_RGB8: return 24; case GL_RGBA: return 32; + case GL_RGBA8: return 32; + case GL_RGB10_A2: return 32; #if GL_VERSION_2_1 case GL_SRGB_ALPHA: return 32; case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac #endif case GL_DEPTH_COMPONENT: return 24; + case GL_DEPTH_COMPONENT24: return 24; + case GL_R16F: return 16; + case GL_RG16F: return 32; case GL_RGB16F: return 48; case GL_RGBA16F: return 64; + case GL_R32F: return 32; + case GL_RG32F: return 64; + case GL_RGB32F: return 96; + case GL_RGBA32F: return 128; default: - LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; + LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL; return 0; } } @@ -361,6 +418,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) case GL_COLOR_INDEX: return 1; #endif case GL_LUMINANCE_ALPHA: return 2; + case GL_RG: return 2; case GL_RGB: return 3; case GL_SRGB: return 3; case GL_RGBA: return 4; @@ -369,7 +427,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac #endif default: - LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; + LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL; return 0; } } @@ -430,29 +488,29 @@ bool LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, b //---------------------------------------------------------------------------- -LLImageGL::LLImageGL(bool usemipmaps) +LLImageGL::LLImageGL(bool usemipmaps/* = true*/, bool allow_compression/* = true*/) : mSaveData(0), mExternalTexture(false) { - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(0, 0, 0); sImageList.insert(this); sCount++; } -LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps) +LLImageGL::LLImageGL(U32 width, U32 height, U8 components, bool usemipmaps/* = true*/, bool allow_compression/* = true*/) : mSaveData(0), mExternalTexture(false) { llassert( components <= 4 ); - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(width, height, components); sImageList.insert(this); sCount++; } -LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps) +LLImageGL::LLImageGL(const LLImageRaw* imageraw, bool usemipmaps/* = true*/, bool allow_compression/* = true*/) : mSaveData(0), mExternalTexture(false) { - init(usemipmaps); + init(usemipmaps, allow_compression); setSize(0, 0, 0); sImageList.insert(this); sCount++; @@ -469,7 +527,7 @@ LLImageGL::LLImageGL( LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode) { - init(false); + init(false, true); mTexName = texName; mTarget = target; mComponents = components; @@ -491,7 +549,7 @@ LLImageGL::~LLImageGL() } } -void LLImageGL::init(bool usemipmaps) +void LLImageGL::init(bool usemipmaps, bool allow_compression) { #if LL_IMAGEGL_THREAD_CHECK mActiveThread = LLThread::currentID(); @@ -521,7 +579,7 @@ void LLImageGL::init(bool usemipmaps) mHeight = 0; mCurrentDiscardLevel = -1; - mAllowCompression = true; + mAllowCompression = allow_compression; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; @@ -1059,15 +1117,47 @@ void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 w { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LL_PROFILE_ZONE_NUM(width); + LL_PROFILE_ZONE_NUM(height); + U32 components = LLImageGL::dataFormatComponents(pixformat); U32 type_width = type_width_from_pixtype(pixtype); const U32 line_width = data_width * components * type_width; const U32 y_offset_end = y_offset + height; - for (U32 y_pos = y_offset; y_pos < y_offset_end; ++y_pos) + + if (width == data_width && height % 32 == 0) { - glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); - src += line_width; + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("subimage - batched lines"); + + // full width, batch multiple lines at a time + // set batch size based on width + U32 batch_size = 32; + + if (width > 1024) + { + batch_size = 8; + } + else if (width > 512) + { + batch_size = 16; + } + + // full width texture, do 32 lines at a time + for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += batch_size) + { + glTexSubImage2D(target, miplevel, x_offset, y_pos, width, batch_size, pixformat, pixtype, src); + src += line_width * batch_size; + } + } + else + { + // partial width or strange height + for (U32 y_pos = y_offset; y_pos < y_offset_end; y_pos += 1) + { + glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); + src += line_width; + } } } @@ -1273,90 +1363,97 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - bool use_scratch = false; - U32* scratch = NULL; if (LLRender::sGLCoreProfile) { - if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_ALPHA is deprecated, convert to RGBA - if (pixels != nullptr) - { - use_scratch = true; - scratch = new(std::nothrow) U32[width * height]; - if (!scratch) - { - LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if (gGLManager.mGLVersion >= CONVERSION_SCRATCH_BUFFER_GL_VERSION) + { + if (pixformat == GL_ALPHA) + { //GL_ALPHA is deprecated, convert to RGBA + const GLint mask[] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RED; + intformat = GL_R8; + } - U32 pixel_count = (U32)(width * height); - for (U32 i = 0; i < pixel_count; i++) - { - U8* pix = (U8*)&scratch[i]; - pix[0] = pix[1] = pix[2] = 0; - pix[3] = ((U8*)pixels)[i]; - } + if (pixformat == GL_LUMINANCE) + { //GL_LUMINANCE is deprecated, convert to GL_RGBA + const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RED; + intformat = GL_R8; } - pixformat = GL_RGBA; - intformat = GL_RGBA8; + if (pixformat == GL_LUMINANCE_ALPHA) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + const GLint mask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, mask); + pixformat = GL_RG; + intformat = GL_RG8; + } } - - if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA - if (pixels != nullptr) - { - use_scratch = true; - scratch = new(std::nothrow) U32[width * height]; - if (!scratch) + else + { + if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_ALPHA is deprecated, convert to RGBA + if (pixels != nullptr) { - LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8* pix = (U8*)&sManualScratch[i]; + pix[0] = pix[1] = pix[2] = 0; + pix[3] = ((U8*)pixels)[i]; + } + + pixels = sManualScratch; } - U32 pixel_count = (U32)(width * height); - for (U32 i = 0; i < pixel_count; i++) + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } + + if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + if (pixels != nullptr) { - U8 lum = ((U8*)pixels)[i * 2 + 0]; - U8 alpha = ((U8*)pixels)[i * 2 + 1]; + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*)pixels)[i * 2 + 0]; + U8 alpha = ((U8*)pixels)[i * 2 + 1]; + + U8* pix = (U8*)&sManualScratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = alpha; + } - U8* pix = (U8*)&scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = alpha; + pixels = sManualScratch; } - } - pixformat = GL_RGBA; - intformat = GL_RGBA8; - } + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } - if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB - if (pixels != nullptr) - { - use_scratch = true; - scratch = new(std::nothrow) U32[width * height]; - if (!scratch) + if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB + if (pixels != nullptr) { - LLError::LLUserWarningMsg::showOutOfMemory(); - LL_ERRS() << "Failed to allocate " << (U32)(width * height * sizeof(U32)) - << " bytes for a manual image W" << width << " H" << height << LL_ENDL; - } + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*)pixels)[i]; - U32 pixel_count = (U32)(width * height); - for (U32 i = 0; i < pixel_count; i++) - { - U8 lum = ((U8*)pixels)[i]; + U8* pix = (U8*)&sManualScratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = 255; + } - U8* pix = (U8*)&scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = 255; + pixels = sManualScratch; } + pixformat = GL_RGBA; + intformat = GL_RGB8; } - pixformat = GL_RGBA; - intformat = GL_RGB8; } } @@ -1365,6 +1462,14 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { switch (intformat) { + case GL_RED: + case GL_R8: + intformat = GL_COMPRESSED_RED; + break; + case GL_RG: + case GL_RG8: + intformat = GL_COMPRESSED_RG; + break; case GL_RGB: case GL_RGB8: #if GL_VERSION_1_3 @@ -1413,14 +1518,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt intformat = GL_COMPRESSED_ALPHA; #endif break; - case GL_RED: - case GL_R8: -#if GL_VERSION_3_0 - intformat = GL_COMPRESSED_RED; -#endif - break; default: - LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL; + LL_WARNS() << "Could not compress format: " << std::hex << intformat << std::dec << LL_ENDL; break; } } @@ -1436,7 +1535,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (!use_sub_image) { LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy"); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, pixels); } else { @@ -1446,21 +1545,16 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr); } - U8* src = (U8*)(use_scratch ? scratch : pixels); + U8* src = (U8*)(pixels); if (src) { LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width); } } - alloc_tex_image(width, height, pixformat); + alloc_tex_image(width, height, intformat, 1); } stop_glerror(); - - if (use_scratch) - { - delete[] scratch; - } } //create an empty GL texture: just create a texture name @@ -2170,6 +2264,8 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) return ; } + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + U32 length = w * h; U32 alphatotal = 0; @@ -2183,13 +2279,13 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) // suffer the worst from aliasing when used as alpha masks. if (w >= 2 && h >= 2) { - llassert(w%2 == 0); - llassert(h%2 == 0); + llassert(w % 2 == 0); + llassert(h % 2 == 0); const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; - for (U32 y = 0; y < h; y+=2) + for (U32 y = 0; y < h; y += 2) { const GLubyte* current = rowstart; - for (U32 x = 0; x < w; x+=2) + for (U32 x = 0; x < w; x += 2) { const U32 s1 = current[0]; alphatotal += s1; @@ -2212,7 +2308,6 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) sample[asum/(16*4)] += 4; } - rowstart += 2 * w * mAlphaStride; } length *= 2; // we sampled everything twice, essentially @@ -2461,41 +2556,32 @@ bool LLImageGL::scaleDown(S32 desired_discard) if (gGLManager.mDownScaleMethod == 0) { // use an FBO to downscale the texture - // allocate new texture - U32 temp_texname = 0; - generateTextures(1, &temp_texname); - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, temp_texname, true); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glTexImage2D"); - glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL); - } - - // account for new texture getting created - alloc_tex_image(desired_width, desired_height, mFormatPrimary); - - // Use render-to-texture to scale down the texture - { - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glFramebufferTexture2D"); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mTarget, temp_texname, 0); - } - glViewport(0, 0, desired_width, desired_height); // draw a full screen triangle - gGL.getTexUnit(0)->bind(this); - glDrawArrays(GL_TRIANGLES, 0, 3); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + if (gGL.getTexUnit(0)->bind(this, true, true)) + { + glDrawArrays(GL_TRIANGLES, 0, 3); - // delete old texture and assign new texture name - deleteTextures(1, &mTexName); - mTexName = temp_texname; + free_tex_image(mTexName); + glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr); + glCopyTexSubImage2D(mTarget, 0, 0, 0, 0, 0, desired_width, desired_height); + alloc_tex_image(desired_width, desired_height, mFormatInternal, 1); - if (mHasMipMaps) - { // generate mipmaps if needed - LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap"); - gGL.getTexUnit(0)->bind(this); - glGenerateMipmap(mTarget); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + mTexOptionsDirty = true; + + if (mHasMipMaps) + { // generate mipmaps if needed + LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap"); + gGL.getTexUnit(0)->bind(this); + glGenerateMipmap(mTarget); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + } + else + { + LL_WARNS_ONCE("LLImageGL") << "Failed to bind texture for downscaling." << LL_ENDL; + return false; } } else @@ -2527,10 +2613,10 @@ bool LLImageGL::scaleDown(S32 desired_discard) glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, sScratchPBO); - glTexImage2D(mTarget, 0, mFormatPrimary, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr); + glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, nullptr); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - alloc_tex_image(desired_width, desired_height, mFormatPrimary); + alloc_tex_image(desired_width, desired_height, mFormatInternal, 1); if (mHasMipMaps) { |