diff options
| author | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2026-07-07 04:59:59 -0400 |
|---|---|---|
| committer | Jonathan "Geenz" Goodman <geenz@geenzo.com> | 2026-07-07 04:59:59 -0400 |
| commit | 6622a5694b5ccd1da77e1564c6475eaf81095f5b (patch) | |
| tree | 3e2e3242a3f0d81843972e253e219a3208ba325d /indra/llrender/llimagegl.cpp | |
| parent | 3e756b57f42e61f6aad3991c7bfa0a581c894244 (diff) | |
Get some more wins for overall downrezzing and minimizing thrashing.
Also make sure that probes don't stamp - that creates thrashing when distant probes render. We're at a low enough resolution on those things that higher mips are likely to go unnoticed, and we bake them frequently enough that we can pick up lower mips when we actually need them.
Diffstat (limited to 'indra/llrender/llimagegl.cpp')
| -rw-r--r-- | indra/llrender/llimagegl.cpp | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 6bcc34938c..95575c009b 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -166,6 +166,8 @@ U64 LLImageGL::getTextureBytesAllocated() //statics U32 LLImageGL::sUniqueCount = 0; +std::atomic<U32> LLImageGL::sOOMErrorCount(0); +thread_local bool LLImageGL::sStampBindFrame = true; U32 LLImageGL::sBindCount = 0; S32 LLImageGL::sCount = 0; @@ -777,6 +779,7 @@ 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; + LLImageGLStampBypass no_stamp; // upload binds are not visibility const bool is_compressed = isCompressed(); @@ -1502,6 +1505,12 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt { free_cur_tex_image(); } + + // Drain stale GL errors so an OOM detected below belongs to this alloc. + // Otherwise a failed glTexImage2D is swallowed in release while + // alloc_tex_image still counts the bytes, inflating the used-VRAM figure. + while (glGetError() != GL_NO_ERROR) {} + const bool use_sub_image = should_stagger_image_set(compress); if (!use_sub_image) { @@ -1511,19 +1520,30 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt 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); - } + LL_PROFILE_ZONE_NAMED("glTexImage2D alloc"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, nullptr); + } - U8* src = (U8*)(pixels); - if (src) + if (glGetError() == GL_OUT_OF_MEMORY) + { + ++sOOMErrorCount; + LL_WARNS_ONCE("Texture") << "glTexImage2D failed with GL_OUT_OF_MEMORY (" + << width << "x" << height << " mip " << miplevel + << ") - not counting bytes" << LL_ENDL; + } + else + { + if (use_sub_image) { - LL_PROFILE_ZONE_NAMED("glTexImage2D copy"); - sub_image_lines(target, miplevel, 0, 0, width, height, pixformat, pixtype, src, width); + 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, intformat, 1); } - alloc_tex_image(width, height, intformat, 1); } stop_glerror(); } @@ -1668,6 +1688,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_PROFILE_GPU_ZONE("createGLTexture"); checkActiveThread(); + LLImageGLStampBypass no_stamp; // creation binds are not visibility bool main_thread = on_main_thread(); @@ -2090,12 +2111,21 @@ S32 LLImageGL::dimDerivedMaxDiscard(S32 width, S32 height) void LLImageGL::stampBound() const { - // Skip the store on same-frame re-binds - bindFast is per-draw and - // would dirty this cache line per bind per texture otherwise. + // Both stamps skip same-frame re-binds (bindFast runs per draw). They dedupe + // separately, so a non-camera pass touching the time stamp first doesn't stop + // a real camera bind from setting the frame stamp later the same frame. if (mLastBindTime != sLastFrameTime) { mLastBindTime = sLastFrameTime; } + if (sStampBindFrame) + { + const U32 frame = LLFrameTimer::getFrameCount(); + if (mLastBindFrame != frame) + { + mLastBindFrame = frame; + } + } } S64 LLImageGL::getBytes(S32 discard_level) const @@ -2520,6 +2550,10 @@ bool LLImageGL::scaleDown(S32 desired_discard) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + // Don't let eviction re-arm visibility: the glGenerateMipmap re-bind below + // would otherwise stamp mLastBindFrame and keep the texture fetch-eligible. + LLImageGLStampBypass no_stamp; + if (mTarget != GL_TEXTURE_2D || mFormatInternal == -1 // not initialized ) |
