From 34e79c8f4e251200496651f9ae2b5126a6f7faa3 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 11 Mar 2022 10:21:08 -0600 Subject: SL-17005 WIP Simplify what feeds texture loading bias to only pay attention to available memory according to OS and GL driver, not (broken) internal accounting (breaks intel GPUs, compatibility pass incoming). --- indra/llrender/llimagegl.cpp | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9bd3a0a6b0..c171f7051f 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -57,9 +57,6 @@ U32 wpo2(U32 i); U32 LLImageGL::sUniqueCount = 0; U32 LLImageGL::sBindCount = 0; -S32Bytes LLImageGL::sGlobalTextureMemory(0); -S32Bytes LLImageGL::sBoundTextureMemory(0); -S32Bytes LLImageGL::sCurBoundTextureMemory(0); S32 LLImageGL::sCount = 0; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; @@ -282,15 +279,6 @@ void LLImageGL::updateStats(F32 current_time) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sLastFrameTime = current_time; - sBoundTextureMemory = sCurBoundTextureMemory; - sCurBoundTextureMemory = S32Bytes(0); -} - -//static -S32 LLImageGL::updateBoundTexMem(const S32Bytes mem, const S32 ncomponents, S32 category) -{ - LLImageGL::sCurBoundTextureMemory += mem ; - return LLImageGL::sCurBoundTextureMemory.value(); } //---------------------------------------------------------------------------- @@ -623,7 +611,7 @@ void LLImageGL::forceUpdateBindStats(void) const mLastBindTime = sLastFrameTime; } -BOOL LLImageGL::updateBindStats(S32Bytes tex_mem) const +BOOL LLImageGL::updateBindStats() const { if (mTexName != 0) { @@ -635,7 +623,6 @@ BOOL LLImageGL::updateBindStats(S32Bytes tex_mem) const { // we haven't accounted for this texture yet this frame sUniqueCount++; - updateBoundTexMem(tex_mem, mComponents, mCategory); mLastBindTime = sLastFrameTime; return TRUE ; @@ -1599,11 +1586,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ // things will break if we don't unbind after creation gGL.getTexUnit(0)->unbind(mBindTarget); - if (old_texname != 0) - { - sGlobalTextureMemory -= mTextureMemory; - } - //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread if (!defer_copy) { @@ -1624,7 +1606,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel); - sGlobalTextureMemory += mTextureMemory; mTexelsInGLTexture = getWidth() * getHeight(); // mark this as bound at this point, so we don't throw it out immediately @@ -1857,7 +1838,6 @@ void LLImageGL::destroyGLTexture() { if(mTextureMemory != S32Bytes(0)) { - sGlobalTextureMemory -= mTextureMemory; mTextureMemory = (S32Bytes)0; } -- cgit v1.2.3 From e60024f0afecb6f92e383221084f1a7af02f8542 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 29 Mar 2022 15:41:00 -0500 Subject: SL-17005 WIP - Use D3D/DXGI to query for available VRAM on Windows --- indra/llrender/llimagegl.cpp | 52 -------------------------------------------- 1 file changed, 52 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c171f7051f..0a5d258b3a 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1615,51 +1615,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ return TRUE; } -void LLImageGLThread::updateClass() -{ - LL_PROFILE_ZONE_SCOPED; - - // update available vram one per second - static LLFrameTimer sTimer; - - if (sTimer.getElapsedSeconds() < 1.f) - { - return; - } - - sTimer.reset(); - - auto func = []() - { - if (gGLManager.mHasATIMemInfo) - { - S32 meminfo[4]; - glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - LLImageGLThread::sFreeVRAMMegabytes = meminfo[0]; - - } - else if (gGLManager.mHasNVXMemInfo) - { - S32 free_memory; - glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); - LLImageGLThread::sFreeVRAMMegabytes = free_memory / 1024; - } - }; - - - // post update to background thread if available, otherwise execute immediately - auto queue = LL::WorkQueue::getInstance("LLImageGL"); - if (sEnabled) - { - queue->post(func); - } - else - { - llassert(queue == nullptr); - func(); - } -} - void LLImageGL::syncToMainThread(LLGLuint new_tex_name) { LL_PROFILE_ZONE_SCOPED; @@ -2389,8 +2344,6 @@ void LLImageGL::checkActiveThread() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips); */ -std::atomic LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB - LLImageGLThread::LLImageGLThread(LLWindow* window) // We want exactly one thread, but a very large capacity: we never want // anyone, especially inner-loop render code, to have to block on post() @@ -2418,8 +2371,3 @@ void LLImageGLThread::run() mWindow->destroySharedContext(mContext); } -S32 LLImageGLThread::getFreeVRAMMegabytes() -{ - return sFreeVRAMMegabytes; -} - -- cgit v1.2.3 From b6841d75c2f259c84d5ab6b012bd2ae37d985451 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 15 Apr 2022 19:02:07 -0500 Subject: SL-17219 WIP - Texture pipeline overhaul --- indra/llrender/llimagegl.cpp | 50 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 0a5d258b3a..04974d9122 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1624,26 +1624,38 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) LL_PROFILE_ZONE_NAMED("cglt - sync"); if (gGLManager.mHasSync) { - // post a sync to the main thread (will execute before tex name swap lambda below) - // glFlush calls here are partly superstitious and partly backed by observation - // on AMD hardware - glFlush(); - auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - LL::WorkQueue::postMaybe( - mMainQueue, - [=]() - { - LL_PROFILE_ZONE_NAMED("cglt - wait sync"); - { - LL_PROFILE_ZONE_NAMED("glWaitSync"); - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - } + if (gGLManager.mIsNVIDIA) + { + // wait for texture upload to finish before notifying main thread + // upload is complete + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(sync); + } + else + { + // post a sync to the main thread (will execute before tex name swap lambda below) + // glFlush calls here are partly superstitious and partly backed by observation + // on AMD hardware + glFlush(); + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + LL::WorkQueue::postMaybe( + mMainQueue, + [=]() { - LL_PROFILE_ZONE_NAMED("glDeleteSync"); - glDeleteSync(sync); - } - }); + LL_PROFILE_ZONE_NAMED("cglt - wait sync"); + { + LL_PROFILE_ZONE_NAMED("glWaitSync"); + glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + } + { + LL_PROFILE_ZONE_NAMED("glDeleteSync"); + glDeleteSync(sync); + } + }); + } } else { -- cgit v1.2.3 From 3400e5fd302c0d9dea6386c4d5bf38876f2cc287 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 16 May 2022 17:21:08 +0000 Subject: SL-17284 Reflection probe tuning and optimization take 1 --- indra/llrender/llimagegl.cpp | 51 +++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9bd3a0a6b0..f2da859e23 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1688,26 +1688,38 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) LL_PROFILE_ZONE_NAMED("cglt - sync"); if (gGLManager.mHasSync) { - // post a sync to the main thread (will execute before tex name swap lambda below) - // glFlush calls here are partly superstitious and partly backed by observation - // on AMD hardware - glFlush(); - auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - LL::WorkQueue::postMaybe( - mMainQueue, - [=]() - { - LL_PROFILE_ZONE_NAMED("cglt - wait sync"); - { - LL_PROFILE_ZONE_NAMED("glWaitSync"); - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - } + if (gGLManager.mIsNVIDIA) + { + // wait for texture upload to finish before notifying main thread + // upload is complete + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(sync); + } + else + { + // post a sync to the main thread (will execute before tex name swap lambda below) + // glFlush calls here are partly superstitious and partly backed by observation + // on AMD hardware + glFlush(); + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + LL::WorkQueue::postMaybe( + mMainQueue, + [=]() { - LL_PROFILE_ZONE_NAMED("glDeleteSync"); - glDeleteSync(sync); - } - }); + LL_PROFILE_ZONE_NAMED("cglt - wait sync"); + { + LL_PROFILE_ZONE_NAMED("glWaitSync"); + glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + } + { + LL_PROFILE_ZONE_NAMED("glDeleteSync"); + glDeleteSync(sync); + } + }); + } } else { @@ -1726,6 +1738,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) }); } + void LLImageGL::syncTexName(LLGLuint texname) { if (texname != 0) -- cgit v1.2.3 From 6eaf8521abae0deeb1162f9c61747183110176b0 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 20 May 2022 19:05:28 -0500 Subject: SL-17287 Instrument and optimize cubemap render. Fix for cubemap snapshots doing a full resolution render instead of a 512x512 render. --- indra/llrender/llimagegl.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index f2da859e23..89dd68da76 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -812,6 +812,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 if (LLRender::sGLCoreProfile) { + LL_PROFILE_GPU_ZONE("generate mip map"); glGenerateMipmap(mTarget); } stop_glerror(); @@ -1519,6 +1520,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ // Call with void data, vmem is allocated but unitialized { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LL_PROFILE_GPU_ZONE("createGLTexture"); checkActiveThread(); bool main_thread = on_main_thread(); @@ -1736,6 +1738,8 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) syncTexName(new_tex_name); unref(); }); + + LL_PROFILER_GPU_COLLECT; } -- cgit v1.2.3 From 4261cbba783359e71b691d6e0e9477ce53f60251 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 1 Jun 2022 10:34:33 -0500 Subject: SL-17485 Add texture memory accounting for OS X --- indra/llrender/llimagegl.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 04974d9122..46f0e1d69e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -53,6 +53,88 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f; //assumes i is a power of 2 > 0 U32 wpo2(U32 i); + +#if LL_DARWIN +// texture memory accounting (for OS X) +static LLMutex sTexMemMutex; +static std::unordered_map sTextureAllocs; +static U64 sTextureBytes = 0; + +// track a texture alloc on the currently bound texture. +// asserts that no currently tracked alloc exists +static void alloc_tex_image(U32 width, U32 height, U32 pixformat) +{ + U32 texUnit = gGL.getCurrentTexUnitIndex(); + U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); + S32 size = LLImageGL::dataFormatBytes(pixformat, width, height); + + llassert(size >= 0); + + sTexMemMutex.lock(); + llassert(sTextureAllocs.find(texName) == sTextureAllocs.end()); + + sTextureAllocs[texName] = size; + sTextureBytes += size; + + sTexMemMutex.unlock(); +} + +// track texture free on given texName +static void free_tex_image(U32 texName) +{ + sTexMemMutex.lock(); + auto iter = sTextureAllocs.find(texName); + if (iter != sTextureAllocs.end()) + { + llassert(iter->second <= sTextureBytes); // sTextureBytes MUST NOT go below zero + + sTextureBytes -= iter->second; + + sTextureAllocs.erase(iter); + } + + sTexMemMutex.unlock(); +} + +// track texture free on given texNames +static void free_tex_images(U32 count, const U32* texNames) +{ + for (int i = 0; i < count; ++i) + { + free_tex_image(texNames[i]); + } +} + +// track texture free on currently bound texture +static void free_cur_tex_image() +{ + U32 texUnit = gGL.getCurrentTexUnitIndex(); + U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); + free_tex_image(texName); +} + +// static +U64 LLImageGL::getTextureBytesAllocated() +{ + return sTextureBytes; +} + +#else + +#define alloc_tex_image(width, height, pixformat) (void) width; (void) height; (void) pixformat; +#define free_tex_image(texName) (void) texName; +#define free_tex_images(count, texNames) (void) count; (void) texNames; +#define free_cur_tex_image() + +// static +U64 LLImageGL::getTextureBytesAllocated() +{ + // UNIMPLEMENTED OUTSIDE OF OS X, DO NOT CALL + llassert(false); + return 0; +} +#endif + //statics U32 LLImageGL::sUniqueCount = 0; @@ -217,6 +299,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_RGBA: 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; default: LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; return 0; @@ -1218,6 +1301,7 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) { if (gGLManager.mInited) { + free_tex_images(numTextures, textures); glDeleteTextures(numTextures, textures); } } @@ -1340,7 +1424,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt stop_glerror(); { LL_PROFILE_ZONE_NAMED("glTexImage2D"); + + free_cur_tex_image(); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + alloc_tex_image(width, height, pixformat); } stop_glerror(); -- cgit v1.2.3 From 276647789a7080c0d44ec8e4375daf0f42b73f17 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 9 Jun 2022 10:36:13 -0400 Subject: SL-17483: Simplify ThreadPool instantiations. Now that LL::ThreadPool's constructor has subsumed the work of discovering a runtime override width, LLAppViewer::initGeneralThread() can simply pass the compile-time default width instead of redundantly checking ThreadPoolSizes. Also the default ThreadPool capacity has been bumped up to what "General" and "LLImageGL" were requesting, so they need not pass that explicitly or explain in comments why they're doing it. But until we start throwing work at the "General" ThreadPool, configure it down to 1 thread in settings.xml. --- indra/llrender/llimagegl.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 9bd3a0a6b0..42460d23b8 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2412,10 +2412,8 @@ void LLImageGL::checkActiveThread() std::atomic LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB LLImageGLThread::LLImageGLThread(LLWindow* window) - // We want exactly one thread, but a very large capacity: we never want - // anyone, especially inner-loop render code, to have to block on post() - // because we're full. - : ThreadPool("LLImageGL", 1, 1024*1024) + // We want exactly one thread. + : ThreadPool("LLImageGL", 1) , mWindow(window) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -- cgit v1.2.3 From 9bee2a92d2eb1f48f8ca0061e546c5e9df38fe79 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 26 Aug 2022 10:51:42 -0500 Subject: SL-17997 Follow up from beta breakers results. --- indra/llrender/llimagegl.cpp | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ae10142e7a..7ba0cc2fde 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -54,7 +54,6 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f; U32 wpo2(U32 i); -#if LL_DARWIN // texture memory accounting (for OS X) static LLMutex sTexMemMutex; static std::unordered_map sTextureAllocs; @@ -119,22 +118,6 @@ U64 LLImageGL::getTextureBytesAllocated() return sTextureBytes; } -#else - -#define alloc_tex_image(width, height, pixformat) (void) width; (void) height; (void) pixformat; -#define free_tex_image(texName) (void) texName; -#define free_tex_images(count, texNames) (void) count; (void) texNames; -#define free_cur_tex_image() - -// static -U64 LLImageGL::getTextureBytesAllocated() -{ - // UNIMPLEMENTED OUTSIDE OF OS X, DO NOT CALL - llassert(false); - return 0; -} -#endif - //statics U32 LLImageGL::sUniqueCount = 0; -- cgit v1.2.3 From 2082443220fe344bb027c3acbf50fea0a99159c3 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 1 Sep 2022 10:58:27 -0700 Subject: SL-17967 - Git rid of ARB that is in core --- indra/llrender/llimagegl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 6215727de0..d8e312106c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -794,7 +794,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 if (is_compressed) { S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + glCompressedTexImage2D(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } else @@ -990,7 +990,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 if (is_compressed) { S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); - glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); + glCompressedTexImage2D(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } else @@ -1838,7 +1838,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return FALSE ; } - glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); + glGetCompressedTexImage(mTarget, gl_discard, (GLvoid*)(imageraw->getData())); //stop_glerror(); } else -- cgit v1.2.3 From 8dc59e5ef37836b15d478fb0d04e3043a9f986de Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 16 Sep 2022 16:25:26 -0500 Subject: SL-18128 Clear out much OpenGL cruft and switch to core profile on AMD --- indra/llrender/llimagegl.cpp | 110 +++++++++++++------------------------------ 1 file changed, 33 insertions(+), 77 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index d8e312106c..6eb7da302f 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -352,7 +352,7 @@ void LLImageGL::updateStats(F32 current_time) //static void LLImageGL::destroyGL(BOOL save_state) { - for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++) + for (S32 stage = 0; stage < gGLManager.mNumTextureImageUnits; stage++) { gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE); } @@ -520,7 +520,6 @@ void LLImageGL::init(BOOL usemipmaps) mPickMaskHeight = 0; mUseMipMaps = usemipmaps; mHasExplicitFormat = FALSE; - mAutoGenMips = FALSE; mIsMask = FALSE; mNeedsAlphaAndPickMask = TRUE ; @@ -1069,30 +1068,12 @@ BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image) mFormatType = GL_UNSIGNED_BYTE; break; case 3: -#if USE_SRGB_DECODE - if (gGLManager.mHasTexturesRGBDecode) - { - mFormatInternal = GL_SRGB8; - } - else -#endif - { - mFormatInternal = GL_RGB8; - } + mFormatInternal = GL_RGB8; mFormatPrimary = GL_RGB; mFormatType = GL_UNSIGNED_BYTE; break; case 4: -#if USE_SRGB_DECODE - if (gGLManager.mHasTexturesRGBDecode) - { - mFormatInternal = GL_SRGB8_ALPHA8; - } - else -#endif - { - mFormatInternal = GL_RGBA8; - } + mFormatInternal = GL_RGBA8; mFormatPrimary = GL_RGBA; mFormatType = GL_UNSIGNED_BYTE; break; @@ -1525,30 +1506,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S mFormatType = GL_UNSIGNED_BYTE; break; case 3: - #if USE_SRGB_DECODE - if (gGLManager.mHasTexturesRGBDecode) - { - mFormatInternal = GL_SRGB8; - } - else - #endif - { - mFormatInternal = GL_RGB8; - } + mFormatInternal = GL_RGB8; mFormatPrimary = GL_RGB; mFormatType = GL_UNSIGNED_BYTE; break; case 4: - #if USE_SRGB_DECODE - if (gGLManager.mHasTexturesRGBDecode) - { - mFormatInternal = GL_SRGB8_ALPHA8; - } - else - #endif - { - mFormatInternal = GL_RGBA8; - } + mFormatInternal = GL_RGBA8; mFormatPrimary = GL_RGBA; mFormatType = GL_UNSIGNED_BYTE; break; @@ -1637,7 +1600,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ if (mUseMipMaps) { - mAutoGenMips = gGLManager.mHasMipMapGeneration; + mAutoGenMips = true; } mCurrentDiscardLevel = discard_level; @@ -1694,44 +1657,37 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name) { LL_PROFILE_ZONE_NAMED("cglt - sync"); - if (gGLManager.mHasSync) + if (gGLManager.mIsNVIDIA) { - if (gGLManager.mIsNVIDIA) - { - // wait for texture upload to finish before notifying main thread - // upload is complete - auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(sync); - } - else - { - // post a sync to the main thread (will execute before tex name swap lambda below) - // glFlush calls here are partly superstitious and partly backed by observation - // on AMD hardware - glFlush(); - auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - glFlush(); - LL::WorkQueue::postMaybe( - mMainQueue, - [=]() - { - LL_PROFILE_ZONE_NAMED("cglt - wait sync"); - { - LL_PROFILE_ZONE_NAMED("glWaitSync"); - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - } - { - LL_PROFILE_ZONE_NAMED("glDeleteSync"); - glDeleteSync(sync); - } - }); - } + // wait for texture upload to finish before notifying main thread + // upload is complete + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + glDeleteSync(sync); } else { - glFinish(); + // post a sync to the main thread (will execute before tex name swap lambda below) + // glFlush calls here are partly superstitious and partly backed by observation + // on AMD hardware + glFlush(); + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + LL::WorkQueue::postMaybe( + mMainQueue, + [=]() + { + LL_PROFILE_ZONE_NAMED("cglt - wait sync"); + { + LL_PROFILE_ZONE_NAMED("glWaitSync"); + glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + } + { + LL_PROFILE_ZONE_NAMED("glDeleteSync"); + glDeleteSync(sync); + } + }); } } -- cgit v1.2.3 From fc424a0db90fd2d2e44e85a19750ad6eaa57b28a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 9 Dec 2022 13:21:45 -0500 Subject: SL-18809: Add WorkSchedule; remove timestamps from WorkQueue. For work queues that don't need timestamped tasks, eliminate the overhead of a priority queue ordered by timestamp. Timestamped task support moves to WorkSchedule. WorkQueue is a simpler queue that just waits for work. Both WorkQueue and WorkSchedule can be accessed via new WorkQueueBase API. Of course the WorkQueueBase API doesn't deal with timestamps, but a WorkSchedule can be accessed directly to post timestamped tasks and then handled normally (e.g. by ThreadPool) to run them. Most ThreadPool functionality migrates to new ThreadPoolBase class, with template subclass ThreadPoolUsing or ThreadPoolUsing depending on need. ThreadPool is now an alias for ThreadPoolUsing. Importantly, ThreadPoolUsing::getQueue() delivers a reference to the specific queue subclass type, so you can post timestamped tasks on a queue retrieved from ThreadPoolUsing::getQueue(). Since ThreadPool is no longer a simple class but an alias for a particular template specialization, introduce threadpool_fwd.h to forward-declare it. Recast workqueue_test.cpp to exercise WorkSchedule, since some of the tests are time-based. A future todo would be to exercise each applicable test with both WorkQueue and WorkSchedule. --- indra/llrender/llimagegl.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index d16757d0ed..7162134c92 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -2404,7 +2404,7 @@ void LLImageGL::checkActiveThread() LLImageGLThread::LLImageGLThread(LLWindow* window) // We want exactly one thread. - : ThreadPool("LLImageGL", 1) + : LL::ThreadPool("LLImageGL", 1) , mWindow(window) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -2412,7 +2412,7 @@ LLImageGLThread::LLImageGLThread(LLWindow* window) mFinished = false; mContext = mWindow->createSharedContext(); - ThreadPool::start(); + LL::ThreadPool::start(); } void LLImageGLThread::run() @@ -2422,7 +2422,7 @@ void LLImageGLThread::run() // WorkQueue, likewise cleanup afterwards. mWindow->makeContextCurrent(mContext); gGL.init(false); - ThreadPool::run(); + LL::ThreadPool::run(); gGL.shutdown(); mWindow->destroySharedContext(mContext); } -- cgit v1.2.3 From 8b39e0e1a6787ae374287dc62064af8576149e86 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 19 Jan 2023 11:33:11 -0600 Subject: SL-18869 Followup -- leverage "small commands" and time slicing to get rid of frame stalls on main thread without the need for multithreaded GL --- indra/llrender/llimagegl.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 7162134c92..db17f812bd 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1404,9 +1404,53 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt stop_glerror(); { LL_PROFILE_ZONE_NAMED("glTexImage2D"); + LL_PROFILE_ZONE_NUM(width); + LL_PROFILE_ZONE_NUM(height); free_cur_tex_image(); +#if 0 glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); +#else + // break up calls to a manageable size for the GL command buffer + { + LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr); + } + + U8* src = (U8*)(use_scratch ? scratch : pixels); + if (src) + { + LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); + U32 components = dataFormatComponents(pixformat); + U32 type_width = 0; + + switch (pixtype) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + type_width = 1; + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + type_width = 2; + break; + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + type_width = 4; + break; + default: + LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; + } + + U32 line_width = width * components * type_width; + for (U32 y = 0; y < height; ++y) + { + glTexSubImage2D(target, miplevel, 0, y, width, 1, pixformat, pixtype, src); + src += line_width; + } + } +#endif alloc_tex_image(width, height, pixformat); } stop_glerror(); -- cgit v1.2.3 From d8cdfaa645e68a496f7c5957602a28cbc2db5f53 Mon Sep 17 00:00:00 2001 From: Brad Linden Date: Thu, 19 Jan 2023 14:25:14 -0800 Subject: Fix for SL-19010 mac crash in LLManipTranslartge::restoreGL(). Attempt to simplify and avoid use of GL_UNSIGNED_INT_8_8_8_8_REV where not needed --- indra/llrender/llimagegl.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index db17f812bd..b3b79bd6c4 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1428,6 +1428,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { case GL_UNSIGNED_BYTE: case GL_BYTE: + case GL_UNSIGNED_INT_8_8_8_8_REV: type_width = 1; break; case GL_UNSIGNED_SHORT: -- cgit v1.2.3 From 46b2c0660a091f5b3596084a71f63c8145bfac68 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Sat, 25 Feb 2023 22:24:46 -0800 Subject: Hammering on more mac optimizations. SL-18563 --- indra/llrender/llimagegl.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index b3b79bd6c4..50d4532fa7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1408,8 +1408,11 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt LL_PROFILE_ZONE_NUM(height); free_cur_tex_image(); -#if 0 - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); +#if LL_DARWIN + { + LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + } #else // break up calls to a manageable size for the GL command buffer { -- cgit v1.2.3 From 6c486e485372a6f79e632839a7217c5208a09d0c Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 8 Mar 2023 12:40:45 -0800 Subject: SL-19338: (WIP) Test disabling new use of glTexSubImage2D and see if the bug still repros --- indra/llrender/llimagegl.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 50d4532fa7..7bb98be84a 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1408,7 +1408,9 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt LL_PROFILE_ZONE_NUM(height); free_cur_tex_image(); -#if LL_DARWIN +// TODO: Revert +//#if LL_DARWIN +#if 1 { LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); -- cgit v1.2.3 From 3773bac6b441d103ab553b86eb34d3ec6f288a2a Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 8 Mar 2023 14:21:44 -0800 Subject: Revert "SL-19338: (WIP) Test disabling new use of glTexSubImage2D and see if the bug still repros" This reverts commit 6c486e485372a6f79e632839a7217c5208a09d0c. --- indra/llrender/llimagegl.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 7bb98be84a..50d4532fa7 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1408,9 +1408,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt LL_PROFILE_ZONE_NUM(height); free_cur_tex_image(); -// TODO: Revert -//#if LL_DARWIN -#if 1 +#if LL_DARWIN { LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); -- cgit v1.2.3 From f3eaf390fe34a8ddb130e64cf2fb72e29085b01d Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 8 Mar 2023 16:22:06 -0800 Subject: SL-19338: Don't use glTexSubImage2D on compressed textures --- indra/llrender/llimagegl.cpp | 77 ++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 50d4532fa7..b5c36ea35e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1409,52 +1409,59 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt free_cur_tex_image(); #if LL_DARWIN - { - LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); - } + const bool use_sub_image = false; #else - // break up calls to a manageable size for the GL command buffer + // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 + const bool use_sub_image = !allow_compression; +#endif + if (!use_sub_image) { LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); } - - U8* src = (U8*)(use_scratch ? scratch : pixels); - if (src) + else { - LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); - U32 components = dataFormatComponents(pixformat); - U32 type_width = 0; - - switch (pixtype) + // break up calls to a manageable size for the GL command buffer { - case GL_UNSIGNED_BYTE: - case GL_BYTE: - case GL_UNSIGNED_INT_8_8_8_8_REV: - type_width = 1; - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - type_width = 2; - break; - case GL_UNSIGNED_INT: - case GL_INT: - case GL_FLOAT: - type_width = 4; - break; - default: - LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; + LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr); } - U32 line_width = width * components * type_width; - for (U32 y = 0; y < height; ++y) + U8* src = (U8*)(use_scratch ? scratch : pixels); + if (src) { - glTexSubImage2D(target, miplevel, 0, y, width, 1, pixformat, pixtype, src); - src += line_width; + LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); + U32 components = dataFormatComponents(pixformat); + U32 type_width = 0; + + switch (pixtype) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_UNSIGNED_INT_8_8_8_8_REV: + type_width = 1; + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + type_width = 2; + break; + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + type_width = 4; + break; + default: + LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; + } + + U32 line_width = width * components * type_width; + for (U32 y = 0; y < height; ++y) + { + glTexSubImage2D(target, miplevel, 0, y, width, 1, pixformat, pixtype, src); + src += line_width; + } } } -#endif alloc_tex_image(width, height, pixformat); } stop_glerror(); -- cgit v1.2.3 From c734602592d271204c7ac1debbc10a23c74b5b64 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Fri, 10 Mar 2023 17:29:49 -0800 Subject: SL-19389: Fix textures not being optimally queued after the fix in SL-19338 In the future, some uses of glTexSubImage2D should be better vetted, ex: media prims --- indra/llrender/llimagegl.cpp | 80 ++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 32 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index b5c36ea35e..7c1cf2ba33 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1113,6 +1113,45 @@ void LLImageGL::postAddToAtlas() stop_glerror(); } +// Equivalent to calling glSetSubImage2D(target, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, src) +// However, instead there are multiple calls to glSetSubImage2D on smaller slices of the image +void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + U32 components = LLImageGL::dataFormatComponents(pixformat); + U32 type_width = 0; + + switch (pixtype) + { + case GL_UNSIGNED_BYTE: + case GL_BYTE: + case GL_UNSIGNED_INT_8_8_8_8_REV: + type_width = 1; + break; + case GL_UNSIGNED_SHORT: + case GL_SHORT: + type_width = 2; + break; + case GL_UNSIGNED_INT: + case GL_INT: + case GL_FLOAT: + type_width = 4; + break; + default: + LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; + } + + const U32 line_width = width * components * type_width; + const U32 y_offset_end = y_offset + height; + for (U32 y = y_offset; y < y_offset_end; ++y) + { + const S32 y_pos = y + y_offset; + glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); + src += line_width; + } +} + BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -1193,6 +1232,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); + // *TODO: glTexSubImage2D may not work on a subset of the texture if + // the texture is compressed. Make sure the image isn't compressed + // when using this function, then it's safe to replace this call with + // subImageLines, when it is performant to do so (see setManualImage) glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1359,7 +1402,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt } } - if (LLImageGL::sCompressTextures && allow_compression) + const bool compress = LLImageGL::sCompressTextures && allow_compression; + if (compress) { switch (intformat) { @@ -1412,11 +1456,11 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt const bool use_sub_image = false; #else // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 - const bool use_sub_image = !allow_compression; + const bool use_sub_image = !compress; #endif if (!use_sub_image) { - LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); + LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy"); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); } else @@ -1431,35 +1475,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (src) { LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); - U32 components = dataFormatComponents(pixformat); - U32 type_width = 0; - - switch (pixtype) - { - case GL_UNSIGNED_BYTE: - case GL_BYTE: - case GL_UNSIGNED_INT_8_8_8_8_REV: - type_width = 1; - break; - case GL_UNSIGNED_SHORT: - case GL_SHORT: - type_width = 2; - break; - case GL_UNSIGNED_INT: - case GL_INT: - case GL_FLOAT: - type_width = 4; - break; - default: - LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; - } - - U32 line_width = width * components * type_width; - for (U32 y = 0; y < height; ++y) - { - glTexSubImage2D(target, miplevel, 0, y, width, 1, pixformat, pixtype, src); - src += line_width; - } + subImageLines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src); } } alloc_tex_image(width, height, pixformat); -- cgit v1.2.3 From 4319ba5edcfeb066d712cdb5a851f155a87ed71b Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 13 Mar 2023 16:46:39 -0700 Subject: SL-19331: Improve performance of setSubImage (ex: media updates) --- indra/llrender/llimagegl.cpp | 59 ++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 19 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 7c1cf2ba33..c42688e95b 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -732,21 +732,8 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - bool is_compressed = false; - switch (mFormatPrimary) - { - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - is_compressed = true; - break; - default: - break; - } + const bool is_compressed = isCompressed(); if (mUseMipMaps) { @@ -1232,11 +1219,23 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); - // *TODO: glTexSubImage2D may not work on a subset of the texture if - // the texture is compressed. Make sure the image isn't compressed - // when using this function, then it's safe to replace this call with - // subImageLines, when it is performant to do so (see setManualImage) - glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); +#if LL_DARWIN + const bool use_sub_image = false; +#else + const bool use_sub_image = !isCompressed(); +#endif + if (!use_sub_image) + { + // *TODO: Why does this work here, in setSubImage, but not in + // setManualImage? Maybe because it only gets called with the + // dimensions of the full image? Or because the image is never + // compressed? + glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + } + else + { + subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + } gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1456,6 +1455,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt const bool use_sub_image = false; #else // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 + // *TODO: Small chance that glCompressedTexImage2D/glCompressedTexSubImage2D may work better here const bool use_sub_image = !compress; #endif if (!use_sub_image) @@ -2296,6 +2296,27 @@ void LLImageGL::freePickMask() mPickMaskWidth = mPickMaskHeight = 0; } +bool LLImageGL::isCompressed() +{ + llassert(mFormatPrimary != 0); + // *NOTE: Not all compressed formats are included here. + bool is_compressed = false; + switch (mFormatPrimary) + { + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + is_compressed = true; + break; + default: + break; + } + return is_compressed; +} + //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { -- cgit v1.2.3 From 084ef5173fb79644ce2fd3e640c241a05529db70 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 21 Mar 2023 09:29:44 -0500 Subject: SL-19434 Temporary fix for minimap breakage. --- indra/llrender/llimagegl.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c42688e95b..f4b580c490 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1219,12 +1219,12 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); -#if LL_DARWIN - const bool use_sub_image = false; -#else - const bool use_sub_image = !isCompressed(); -#endif - if (!use_sub_image) +//#if LL_DARWIN +// const bool use_sub_image = false; +//#else +// const bool use_sub_image = !isCompressed(); +//#endif + //if (!use_sub_image) { // *TODO: Why does this work here, in setSubImage, but not in // setManualImage? Maybe because it only gets called with the @@ -1232,10 +1232,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 // compressed? glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); } - else - { - subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); - } + //else + //{ + // subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + //} gGL.getTexUnit(0)->disable(); stop_glerror(); -- cgit v1.2.3 From 7d97008ebaa08212fd4e3dcb9a01861b4adff728 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Tue, 21 Mar 2023 14:27:37 -0700 Subject: Revert "SL-19434 Temporary fix for minimap breakage." This reverts commit 084ef5173fb79644ce2fd3e640c241a05529db70. --- indra/llrender/llimagegl.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index f4b580c490..c42688e95b 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1219,12 +1219,12 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); -//#if LL_DARWIN -// const bool use_sub_image = false; -//#else -// const bool use_sub_image = !isCompressed(); -//#endif - //if (!use_sub_image) +#if LL_DARWIN + const bool use_sub_image = false; +#else + const bool use_sub_image = !isCompressed(); +#endif + if (!use_sub_image) { // *TODO: Why does this work here, in setSubImage, but not in // setManualImage? Maybe because it only gets called with the @@ -1232,10 +1232,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 // compressed? glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); } - //else - //{ - // subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); - //} + else + { + subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + } gGL.getTexUnit(0)->disable(); stop_glerror(); -- cgit v1.2.3 From a218eed9a6bffd61e7fea38d145a6751faf780aa Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Mon, 20 Mar 2023 17:00:30 -0700 Subject: SL-19434: Fix texture issues with minimap, but keep performance from SL-19331 --- indra/llrender/llimagegl.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c42688e95b..5b0690bc79 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1100,15 +1100,9 @@ void LLImageGL::postAddToAtlas() stop_glerror(); } -// Equivalent to calling glSetSubImage2D(target, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, src) -// However, instead there are multiple calls to glSetSubImage2D on smaller slices of the image -void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src) +U32 type_width_from_pixtype(U32 pixtype) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - - U32 components = LLImageGL::dataFormatComponents(pixformat); U32 type_width = 0; - switch (pixtype) { case GL_UNSIGNED_BYTE: @@ -1128,12 +1122,22 @@ void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 wid default: LL_ERRS() << "Unknown type: " << pixtype << LL_ENDL; } + return type_width; +} + +// Equivalent to calling glSetSubImage2D(target, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, src), assuming the total width of the image is data_width +// However, instead there are multiple calls to glSetSubImage2D on smaller slices of the image +void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src, S32 data_width) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + U32 components = LLImageGL::dataFormatComponents(pixformat); + U32 type_width = type_width_from_pixtype(pixtype); - const U32 line_width = width * components * type_width; + const U32 line_width = data_width * components * type_width; const U32 y_offset_end = y_offset + height; - for (U32 y = y_offset; y < y_offset_end; ++y) + for (U32 y_pos = y_offset; y_pos < y_offset_end; ++y_pos) { - const S32 y_pos = y + y_offset; glTexSubImage2D(target, miplevel, x_offset, y_pos, width, 1, pixformat, pixtype, src); src += line_width; } @@ -1213,7 +1217,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 stop_glerror(); } - datap += (y_pos * data_width + x_pos) * getComponents(); + const U8* sub_datap = datap + (y_pos * data_width + x_pos) * getComponents(); // Update the GL texture BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name); if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; @@ -1230,11 +1234,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 // setManualImage? Maybe because it only gets called with the // dimensions of the full image? Or because the image is never // compressed? - glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, sub_datap); } else { - subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); + subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, sub_datap, data_width); } gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1475,7 +1479,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (src) { LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); - subImageLines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src); + subImageLines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width); } } alloc_tex_image(width, height, pixformat); -- cgit v1.2.3 From d6d634d29ff351450306e211982a98a0050f1b42 Mon Sep 17 00:00:00 2001 From: cosmic-linden <111533034+cosmic-linden@users.noreply.github.com> Date: Wed, 5 Apr 2023 09:55:33 -0700 Subject: SL-19331: Move media updates off-thread on select hardware (#153) * SL-19331: Have media updates on the LLImageGL thread even when texture updates are on the main thread. Add config. Off-thread media updates seem work best performance-wise when using glTexImage2D, not sub_image_lines. Otherwise, there are lots of main thread stalls. * SL-19331: Bump featuretable * SL-19331: Cleanup, annotate comment --- indra/llrender/llimagegl.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 5b0690bc79..3e3a3095e3 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -42,6 +42,8 @@ #include "llwindow.h" #include "llframetimer.h" +extern LL_COMMON_API bool on_main_thread(); + #if !LL_IMAGEGL_THREAD_CHECK #define checkActiveThread() #endif @@ -132,7 +134,8 @@ bool LLImageGL::sCompressTextures = false; std::set LLImageGL::sImageList; -bool LLImageGLThread::sEnabled = false; +bool LLImageGLThread::sEnabledTextures = false; +bool LLImageGLThread::sEnabledMedia = false; //**************************************************************************************************** //The below for texture auditing use only @@ -242,14 +245,16 @@ BOOL is_little_endian() } //static -void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */) +void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool thread_texture_loads /* = false */, bool thread_media_updates /* = false */) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sSkipAnalyzeAlpha = skip_analyze_alpha; - if (multi_threaded) + if (thread_texture_loads || thread_media_updates) { LLImageGLThread::createInstance(window); + LLImageGLThread::sEnabledTextures = thread_texture_loads; + LLImageGLThread::sEnabledMedia = thread_media_updates; } } @@ -260,6 +265,7 @@ void LLImageGL::cleanupClass() LLImageGLThread::deleteSingleton(); } + //static S32 LLImageGL::dataFormatBits(S32 dataformat) { @@ -1125,9 +1131,20 @@ U32 type_width_from_pixtype(U32 pixtype) return type_width; } +bool should_stagger_image_set(bool compressed) +{ +#if LL_DARWIN + return false; +#else + // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 + // Setting media textures off-thread seems faster when not using sub_image_lines (Nvidia/Windows 10) -Cosmic,2023-03-31 + return !compressed && on_main_thread(); +#endif +} + // Equivalent to calling glSetSubImage2D(target, miplevel, x_offset, y_offset, width, height, pixformat, pixtype, src), assuming the total width of the image is data_width // However, instead there are multiple calls to glSetSubImage2D on smaller slices of the image -void subImageLines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src, S32 data_width) +void sub_image_lines(U32 target, S32 miplevel, S32 x_offset, S32 y_offset, S32 width, S32 height, U32 pixformat, U32 pixtype, const U8* src, S32 data_width) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -1223,11 +1240,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); -#if LL_DARWIN - const bool use_sub_image = false; -#else - const bool use_sub_image = !isCompressed(); -#endif + const bool use_sub_image = should_stagger_image_set(isCompressed()); if (!use_sub_image) { // *TODO: Why does this work here, in setSubImage, but not in @@ -1238,7 +1251,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 } else { - subImageLines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, sub_datap, data_width); + sub_image_lines(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, sub_datap, data_width); } gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1455,13 +1468,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt LL_PROFILE_ZONE_NUM(height); free_cur_tex_image(); -#if LL_DARWIN - const bool use_sub_image = false; -#else - // glTexSubImage2D doesn't work with compressed textures on select tested Nvidia GPUs on Windows 10 -Cosmic,2023-03-08 - // *TODO: Small chance that glCompressedTexImage2D/glCompressedTexSubImage2D may work better here - const bool use_sub_image = !compress; -#endif + const bool use_sub_image = should_stagger_image_set(compress); if (!use_sub_image) { LL_PROFILE_ZONE_NAMED("glTexImage2D alloc + copy"); @@ -1479,7 +1486,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (src) { LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); - subImageLines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width); + sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width); } } alloc_tex_image(width, height, pixformat); @@ -2504,7 +2511,6 @@ LLImageGLThread::LLImageGLThread(LLWindow* window) , mWindow(window) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; - sEnabled = true; mFinished = false; mContext = mWindow->createSharedContext(); -- cgit v1.2.3 From a4c2eab969b1971389408de5a3927f87d74a6d6d Mon Sep 17 00:00:00 2001 From: Rye Mutt Date: Thu, 28 Sep 2023 16:05:37 -0400 Subject: Fix integer overflow when framebuffers are extremely high resolution resulting in INT_MAX texture bias (#393) --- indra/llrender/llimagegl.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index b77f98d65e..c6fd824c4e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -58,7 +58,7 @@ U32 wpo2(U32 i); // texture memory accounting (for OS X) static LLMutex sTexMemMutex; -static std::unordered_map sTextureAllocs; +static std::unordered_map sTextureAllocs; static U64 sTextureBytes = 0; // track a texture alloc on the currently bound texture. @@ -67,7 +67,7 @@ static void alloc_tex_image(U32 width, U32 height, U32 pixformat) { U32 texUnit = gGL.getCurrentTexUnitIndex(); U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); - S32 size = LLImageGL::dataFormatBytes(pixformat, width, height); + U64 size = LLImageGL::dataFormatBytes(pixformat, width, height); llassert(size >= 0); @@ -296,7 +296,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) } //static -S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) +S64 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) { switch (dataformat) { @@ -312,8 +312,8 @@ S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height) default: break; } - S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3); - S32 aligned = (bytes+3)&~3; + S64 bytes (((S64)width * (S64)height * (S64)dataFormatBits(dataformat)+7)>>3); + S64 aligned = (bytes+3)&~3; return aligned; } @@ -518,7 +518,7 @@ void LLImageGL::init(BOOL usemipmaps) // so that it is obvious by visual inspection if we forgot to // init a field. - mTextureMemory = (S32Bytes)0; + mTextureMemory = S64Bytes(0); mLastBindTime = 0.f; mPickMask = NULL; @@ -1744,7 +1744,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ } - mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel); + mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel); mTexelsInGLTexture = getWidth() * getHeight(); // mark this as bound at this point, so we don't throw it out immediately @@ -1938,9 +1938,9 @@ void LLImageGL::destroyGLTexture() if (mTexName != 0) { - if(mTextureMemory != S32Bytes(0)) + if(mTextureMemory != S64Bytes(0)) { - mTextureMemory = (S32Bytes)0; + mTextureMemory = (S64Bytes)0; } LLImageGL::deleteTextures(1, &mTexName); @@ -2036,7 +2036,7 @@ S32 LLImageGL::getWidth(S32 discard_level) const return width; } -S32 LLImageGL::getBytes(S32 discard_level) const +S64 LLImageGL::getBytes(S32 discard_level) const { if (discard_level < 0) { @@ -2049,7 +2049,7 @@ S32 LLImageGL::getBytes(S32 discard_level) const return dataFormatBytes(mFormatPrimary, w, h); } -S32 LLImageGL::getMipBytes(S32 discard_level) const +S64 LLImageGL::getMipBytes(S32 discard_level) const { if (discard_level < 0) { @@ -2057,7 +2057,7 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const } S32 w = mWidth>>discard_level; S32 h = mHeight>>discard_level; - S32 res = dataFormatBytes(mFormatPrimary, w, h); + S64 res = dataFormatBytes(mFormatPrimary, w, h); if (mUseMipMaps) { while (w > 1 && h > 1) -- cgit v1.2.3 From 78ce375dda587cbc86ade15a4d564a469e6db9d3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 3 Jan 2024 22:57:28 +0200 Subject: SL-17896 Don't crash silently if files are missing or out of memory Under debug LL_ERRS will show a message as well, but release won't show anything and will quit silently so show a notification when applicable. --- indra/llrender/llimagegl.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/llrender/llimagegl.cpp') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c6fd824c4e..56a12b07b1 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1353,6 +1353,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt 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; } @@ -1378,6 +1379,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt 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; } @@ -1406,6 +1408,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt 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; } -- cgit v1.2.3