diff options
author | Brad Linden <brad@lindenlab.com> | 2024-10-29 15:43:21 -0700 |
---|---|---|
committer | Brad Linden <brad@lindenlab.com> | 2024-10-29 15:43:21 -0700 |
commit | 74b0c86e48387e2154cb2acf03f626ca11229bce (patch) | |
tree | 0c74138a6d0c60eb5dffcc745464b58a6b315036 /indra/llrender/llimagegl.cpp | |
parent | 9598e2f4cedd3dc36d447086273e0ed97967bbf9 (diff) | |
parent | 1a7909517368206d54407e54b9332aed1e4c9863 (diff) |
Merge brad/2549-downrez-controls into release/2024.09-ExtraFPS (#2864)
Diffstat (limited to 'indra/llrender/llimagegl.cpp')
-rw-r--r-- | indra/llrender/llimagegl.cpp | 293 |
1 files changed, 189 insertions, 104 deletions
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index e4b176ff69..26e6aad770 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; //------------------------ @@ -261,6 +264,22 @@ void LLImageGL::initClass(LLWindow* window, S32 num_catagories, bool skip_analyz } } +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; + } + } +} + //static void LLImageGL::cleanupClass() { @@ -272,6 +291,8 @@ void LLImageGL::cleanupClass() sScratchPBO = 0; sScratchPBOSize = 0; } + + delete[] sManualScratch; } @@ -280,6 +301,15 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) { switch (dataformat) { + case GL_COMPRESSED_RED: return 8; + case GL_COMPRESSED_RG: return 16; + case GL_COMPRESSED_RGB: return 24; + case GL_COMPRESSED_SRGB: return 32; + case GL_COMPRESSED_RGBA: return 32; + case GL_COMPRESSED_SRGB_ALPHA: return 32; + case GL_COMPRESSED_LUMINANCE: return 8; + case GL_COMPRESSED_LUMINANCE_ALPHA: return 16; + case GL_COMPRESSED_ALPHA: return 8; case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return 4; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: return 4; case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return 8; @@ -287,21 +317,35 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return 8; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8; 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; case GL_COLOR_INDEX: return 8; 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_SRGB_ALPHA: return 32; case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac 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; } } @@ -344,13 +388,14 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) case GL_RED: return 1; case GL_COLOR_INDEX: return 1; 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; case GL_SRGB_ALPHA: return 4; case GL_BGRA: return 4; // Used for QuickTime media textures on the Mac default: - LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; + LL_ERRS() << "LLImageGL::Unknown format: " << std::hex << dataformat << std::dec << LL_ENDL; return 0; } } @@ -411,29 +456,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++; @@ -450,7 +495,7 @@ LLImageGL::LLImageGL( LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode) { - init(false); + init(false, true); mTexName = texName; mTarget = target; mComponents = components; @@ -472,7 +517,7 @@ LLImageGL::~LLImageGL() } } -void LLImageGL::init(bool usemipmaps) +void LLImageGL::init(bool usemipmaps, bool allow_compression) { #if LL_IMAGEGL_THREAD_CHECK mActiveThread = LLThread::currentID(); @@ -502,7 +547,7 @@ void LLImageGL::init(bool usemipmaps) mHeight = 0; mCurrentDiscardLevel = -1; - mAllowCompression = true; + mAllowCompression = allow_compression; mTarget = GL_TEXTURE_2D; mBindTarget = LLTexUnit::TT_TEXTURE; @@ -1020,15 +1065,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) + { + 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 { - glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); - src += line_width; + // 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; + } } } @@ -1230,90 +1307,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; } } @@ -1322,6 +1406,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: intformat = GL_COMPRESSED_RGB; @@ -1350,12 +1442,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt case GL_ALPHA8: intformat = GL_COMPRESSED_ALPHA; break; - case GL_RED: - case GL_R8: - intformat = GL_COMPRESSED_RED; - 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; } } @@ -1371,7 +1459,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 { @@ -1381,21 +1469,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 @@ -2083,6 +2166,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; @@ -2094,15 +2179,15 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) // this will mid-skew the data (and thus increase the chances of not // being used as a mask) from high-frequency alpha maps which // suffer the worst from aliasing when used as alpha masks. - if (w >= 2 && h >= 2) + if (w >= 4 && h >= 4) { - llassert(w%2 == 0); - llassert(h%2 == 0); + llassert(w%4 == 0); + llassert(h%4 == 0); const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset; - for (U32 y = 0; y < h; y+=2) + for (U32 y = 0; y < h; y+=4) { const GLubyte* current = rowstart; - for (U32 x = 0; x < w; x+=2) + for (U32 x = 0; x < w; x+=4) { const U32 s1 = current[0]; alphatotal += s1; @@ -2126,7 +2211,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h) } - rowstart += 2 * w * mAlphaStride; + rowstart += 4 * w * mAlphaStride; } length *= 2; // we sampled everything twice, essentially } @@ -2374,11 +2459,11 @@ bool LLImageGL::scaleDown(S32 desired_discard) 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); + glTexImage2D(mTarget, 0, mFormatInternal, desired_width, desired_height, 0, mFormatPrimary, mFormatType, NULL); } // account for new texture getting created - alloc_tex_image(desired_width, desired_height, mFormatPrimary); + alloc_tex_image(desired_width, desired_height, mFormatInternal, 1); // Use render-to-texture to scale down the texture { @@ -2432,10 +2517,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) { |