summaryrefslogtreecommitdiff
path: root/indra/llrender/llimagegl.cpp
diff options
context:
space:
mode:
authorBrad Linden <brad@lindenlab.com>2024-10-29 15:43:21 -0700
committerBrad Linden <brad@lindenlab.com>2024-10-29 15:43:21 -0700
commit74b0c86e48387e2154cb2acf03f626ca11229bce (patch)
tree0c74138a6d0c60eb5dffcc745464b58a6b315036 /indra/llrender/llimagegl.cpp
parent9598e2f4cedd3dc36d447086273e0ed97967bbf9 (diff)
parent1a7909517368206d54407e54b9332aed1e4c9863 (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.cpp293
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)
{