summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@geenzo.com>2026-07-22 00:40:35 -0400
committerJonathan "Geenz" Goodman <geenz@geenzo.com>2026-07-22 00:40:35 -0400
commit55e94847b4270d7f71016fe651800ef9e43b4bc5 (patch)
treef06e62aed146c666cfa933b40ea7fe4fc8357f05
parent6b9f0f0bf43250f984631032a3f3b41d245907a9 (diff)
Revert "Merge pull request #5829 from secondlife/geenz/texture-quality"
This reverts commit 6b4e3f3288ec1e9917cecd862a7a52945e5b4db2, reversing changes made to 99ab6316b4ae9058f22d9f57d21e795ca45797fd.
-rw-r--r--indra/llimage/llimagej2c.cpp34
-rw-r--r--indra/llimage/llimagej2c.h5
-rw-r--r--indra/llimagej2coj/llimagej2coj.cpp29
-rw-r--r--indra/llimagej2coj/llimagej2coj.h19
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp30
-rw-r--r--indra/llkdu/llimagej2ckdu.h2
-rw-r--r--indra/llkdu/tests/llimagej2ckdu_test.cpp2
-rw-r--r--indra/llrender/llimagegl.cpp96
-rw-r--r--indra/llrender/llimagegl.h17
-rw-r--r--indra/llrender/llrender.cpp29
-rw-r--r--indra/newview/app_settings/settings.xml326
-rw-r--r--indra/newview/featuretable.txt31
-rw-r--r--indra/newview/featuretable_mac.txt31
-rw-r--r--indra/newview/lldrawpoolwater.cpp8
-rw-r--r--indra/newview/llface.cpp30
-rw-r--r--indra/newview/llface.h7
-rw-r--r--indra/newview/llfeaturemanager.cpp24
-rw-r--r--indra/newview/llsurface.cpp14
-rw-r--r--indra/newview/llsurface.h6
-rw-r--r--indra/newview/lltexturefetch.cpp12
-rw-r--r--indra/newview/lltexturefetch.h3
-rw-r--r--indra/newview/lltextureview.cpp8
-rw-r--r--indra/newview/llviewercontrol.cpp43
-rw-r--r--indra/newview/llviewertexture.cpp536
-rw-r--r--indra/newview/llviewertexture.h62
-rw-r--r--indra/newview/llviewertexturelist.cpp236
-rw-r--r--indra/newview/llviewertexturelist.h9
-rw-r--r--indra/newview/llvlcomposition.cpp18
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml32
29 files changed, 289 insertions, 1410 deletions
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 8099a18045..5a941dc958 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -268,11 +268,35 @@ S32 LLImageJ2C::calcHeaderSizeJ2C()
//static
S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate)
{
- // Dispatch to the linked impl so OpenJPEG (block-aligned, needs
- // over-allocation) and KDU (packet-aligned, lean) each return what
- // their decoder actually needs.
- static std::unique_ptr<LLImageJ2CImpl> s_estimator(fallbackCreateLLImageJ2CImpl());
- return s_estimator->estimateDataSize(w, h, comp, discard_level, rate);
+ // Note: This provides an estimation for the first to last quality layer of a given discard level
+ // This is however an efficient approximation, as the true discard level boundary would be
+ // in general too big for fast fetching.
+ // For details about the equation used here, see https://wiki.lindenlab.com/wiki/THX1138_KDU_Improvements#Byte_Range_Study
+
+ // Estimate the number of layers. This is consistent with what's done for j2c encoding in LLImageJ2CKDU::encodeImpl().
+ constexpr S32 precision = 8; // assumed bitrate per component channel, might change in future for HDR support
+ constexpr S32 max_components = 4; // assumed the file has four components; three color and alpha
+ // Use MAX_IMAGE_SIZE_DEFAULT (currently 2048) if either dimension is unknown (zero)
+ S32 width = (w > 0) ? w : 2048;
+ S32 height = (h > 0) ? h : 2048;
+ S32 max_dimension = llmax(width, height); // Find largest dimension
+ S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE; // Calculated initial block area from established max block size (currently 64)
+ S32 max_layers = (S32)llmax(llround(log2f((float)max_dimension) - log2f((float)MAX_BLOCK_SIZE)), 4); // Find number of powers of two between extents and block size to a minimum of 4
+ block_area *= llmax(max_layers, 1); // Adjust initial block area by max number of layers
+ S32 totalbytes = (S32) (MIN_LAYER_SIZE * max_components * precision); // Start estimation with a minimum reasonable size
+ S32 block_layers = 0;
+ while (block_layers <= max_layers) // Walk the layers
+ {
+ if (block_layers <= (5 - discard_level)) // Walk backwards from discard 5 to required discard layer.
+ totalbytes += (S32) (block_area * max_components * precision * rate); // Add each block layer reduced by assumed compression rate
+ block_layers++; // Move to next layer
+ block_area *= 4; // Increase block area by power of four
+ }
+
+ totalbytes /= 8; // to bytes
+ totalbytes += calcHeaderSizeJ2C(); // header
+
+ return totalbytes;
}
S32 LLImageJ2C::calcHeaderSize()
diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h
index 81b24cc0b3..19744a7f87 100644
--- a/indra/llimage/llimagej2c.h
+++ b/indra/llimage/llimagej2c.h
@@ -106,11 +106,6 @@ class LLImageJ2CImpl
{
public:
virtual ~LLImageJ2CImpl();
-
- // Estimate the byte size of a J2C codestream sufficient to decode the
- // given discard level. KDU uses a packet-by-packet impl; OpenJPEG
- // overrides with a more conservative block-aligned estimate.
- virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const = 0;
protected:
// Find out the image size and number of channels.
// Return value:
diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp
index 488c07e1c9..7cfadb889d 100644
--- a/indra/llimagej2coj/llimagej2coj.cpp
+++ b/indra/llimagej2coj/llimagej2coj.cpp
@@ -919,32 +919,3 @@ bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)
base.setSize(width, height, components);
return true;
}
-
-
-// OpenJPEG-tuned byte estimator. Conservative pyramid walk that accounts for
-// OJ's whole-code-block decode behavior (even with strict mode off). Larger
-// images get a per-resolution multiplier so the byte range lands inside the
-// last needed code-block boundary.
-S32 LLImageJ2COJ::estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const
-{
- constexpr S32 precision = 8;
- constexpr S32 max_components = 4;
- S32 width = (w > 0) ? w : 2048;
- S32 height = (h > 0) ? h : 2048;
- S32 max_dimension = llmax(width, height);
- S32 block_area = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE;
- S32 max_layers = (S32)llmax(llround(log2f((float)max_dimension) - log2f((float)MAX_BLOCK_SIZE)), 4);
- block_area *= llmax(max_layers, 1);
- S32 totalbytes = (S32)(MIN_LAYER_SIZE * max_components * precision);
- S32 block_layers = 0;
- while (block_layers <= max_layers)
- {
- if (block_layers <= (5 - discard_level))
- totalbytes += (S32)(block_area * max_components * precision * rate);
- block_layers++;
- block_area *= 4;
- }
- totalbytes /= 8;
- totalbytes += LLImageJ2C::calcHeaderSizeJ2C();
- return totalbytes;
-}
diff --git a/indra/llimagej2coj/llimagej2coj.h b/indra/llimagej2coj/llimagej2coj.h
index 0cc8d5c34c..da49597302 100644
--- a/indra/llimagej2coj/llimagej2coj.h
+++ b/indra/llimagej2coj/llimagej2coj.h
@@ -35,20 +35,15 @@ class LLImageJ2COJ : public LLImageJ2CImpl
{
public:
LLImageJ2COJ();
- virtual ~LLImageJ2COJ() override;
+ virtual ~LLImageJ2COJ();
protected:
- virtual bool getMetadata(LLImageJ2C &base) override;
- virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count) override;
+ virtual bool getMetadata(LLImageJ2C &base);
+ virtual bool decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
virtual bool encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, const char* comment_text, F32 encode_time=0.0,
- bool reversible = false) override;
- virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL) override;
- virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0) override;
- virtual std::string getEngineInfo() const override;
-public:
- // OpenJPEG decodes whole code-blocks even with strict mode off, so the
- // lean packet-walk under-allocates and clips quality. Keep the older
- // conservative pyramid-with-multiplier estimate here.
- virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const override;
+ bool reversible = false);
+ virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
+ virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
+ virtual std::string getEngineInfo() const;
};
#endif
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 74aaffbd65..cf45f93168 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -1551,33 +1551,3 @@ void kdc_flow_control::process_components()
}
}
}
-
-// Layer-factored byte estimator. Walks the resolution pyramid to count
-// layers, weights by layer_factor, then picks between a sqrt-based "new"
-// estimate and a raw-dimensions "old" estimate per TextureNewByteRange.
-// Reference: https://wiki.lindenlab.com/wiki/THX1138_KDU_Improvements#Byte_Range_Study
-S32 LLImageJ2CKDU::estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const
-{
- S32 width = (w > 0) ? w : 2048;
- S32 height = (h > 0) ? h : 2048;
- S32 nb_layers = 1;
- S32 surface = width * height;
- S32 s = MAX_BLOCK_SIZE * MAX_BLOCK_SIZE;
- while (surface > s)
- {
- nb_layers++;
- s *= 4;
- }
- F32 layer_factor = 3.0f * (7 - llclamp(nb_layers, 1, 6));
-
- width >>= discard_level;
- height >>= discard_level;
- width = llmax(width, 1);
- height = llmax(height, 1);
-
- S32 new_bytes = (S32)(sqrtf((F32)(width * height)) * (F32)comp * rate * 1000.f / layer_factor);
- S32 old_bytes = (S32)((F32)(width * height * comp) * rate);
- S32 bytes = (LLImage::useNewByteRange() && (new_bytes < old_bytes)) ? new_bytes : old_bytes;
- bytes = llmax(bytes, LLImageJ2C::calcHeaderSizeJ2C());
- return bytes;
-}
diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h
index 6079585948..c9aa0c5250 100644
--- a/indra/llkdu/llimagej2ckdu.h
+++ b/indra/llkdu/llimagej2ckdu.h
@@ -67,8 +67,6 @@ protected:
virtual bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, int discard_level = -1, int* region = NULL);
virtual bool initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int blocks_size = -1, int precincts_size = -1, int levels = 0);
virtual std::string getEngineInfo() const;
-public:
- virtual S32 estimateDataSize(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) const;
private:
bool initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, ECodeStreamMode mode, S32 first_channel, S32 max_channel_count, int discard_level = -1, int* region = NULL);
diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp
index 6be2d3a078..bc52a15c4a 100644
--- a/indra/llkdu/tests/llimagej2ckdu_test.cpp
+++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp
@@ -83,8 +83,6 @@ void LLImageBase::setSize(S32 , S32 , S32 ) { }
bool LLImageBase::isBufferInvalid() const { return false; }
LLImageJ2CImpl::~LLImageJ2CImpl() { }
-bool LLImage::sUseNewByteRange = false;
-S32 LLImageJ2C::calcHeaderSizeJ2C() { return 0; }
LLImageFormatted::LLImageFormatted(S8 ) { }
LLImageFormatted::~LLImageFormatted() { }
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 6bcc34938c..4a3d32c7ff 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -66,8 +66,8 @@ static LLMutex sTexMemMutex;
static std::unordered_map<U32, U64> sTextureAllocs;
static U64 sTextureBytes = 0;
-// Per-mip upload paths call this once per level; only free_tex_image
-// removes a texture's accounting entirely.
+// 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 intformat, U32 count)
{
U32 texUnit = gGL.getCurrentTexUnitIndex();
@@ -80,43 +80,12 @@ void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32
sTexMemMutex.lock();
- auto iter = sTextureAllocs.find(texName);
- if (iter != sTextureAllocs.end())
- {
- iter->second += size;
- }
- else
- {
- sTextureAllocs[texName] = size;
- }
- sTextureBytes += size;
-
- sTexMemMutex.unlock();
-}
+ // it is a precondition that no existing allocation exists for this texture
+ llassert(sTextureAllocs.find(texName) == sTextureAllocs.end());
-// Add mip 1..N bytes to existing accounting. Use after glGenerateMipmap.
-void LLImageGLMemory::account_extra_mip_bytes(U32 base_width, U32 base_height, U32 intformat)
-{
- U64 extra = 0;
- U32 w = base_width;
- U32 h = base_height;
- while (w > 1 || h > 1)
- {
- w = w > 1 ? w >> 1 : 1;
- h = h > 1 ? h >> 1 : 1;
- extra += LLImageGL::dataFormatBytes(intformat, w, h);
- }
-
- U32 texUnit = gGL.getCurrentTexUnitIndex();
- U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture();
+ sTextureAllocs[texName] = size;
+ sTextureBytes += size;
- sTexMemMutex.lock();
- auto iter = sTextureAllocs.find(texName);
- if (iter != sTextureAllocs.end())
- {
- iter->second += extra;
- sTextureBytes += extra;
- }
sTexMemMutex.unlock();
}
@@ -715,10 +684,7 @@ void LLImageGL::dump()
//----------------------------------------------------------------------------
void LLImageGL::forceUpdateBindStats(void) const
{
- // Intentionally a no-op: mLastBindTime is written only by real bind
- // paths so the staleness signal reflects actual GPU use. Callers that
- // still invoke this (avatar "keep alive" sites, deleted-texture
- // fallback) no longer falsely refresh staleness.
+ mLastBindTime = sLastFrameTime;
}
bool LLImageGL::updateBindStats() const
@@ -872,7 +838,7 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
mMipLevels = wpo2(llmax(w, h));
//use legacy mipmap generation mode (note: making this condional can cause rendering issues)
- // - but making it not conditional triggers deprecation warnings when core profile is enabled
+ // -- but making it not conditional triggers deprecation warnings when core profile is enabled
// (some rendering issues while core profile is enabled are acceptable at this point in time)
if (!LLRender::sGLCoreProfile)
{
@@ -898,7 +864,6 @@ bool LLImageGL::setImage(const U8* data_in, bool data_hasmips /* = false */, S32
{
LL_PROFILE_GPU_ZONE("generate mip map");
glGenerateMipmap(mTarget);
- account_extra_mip_bytes(w, h, mFormatInternal);
}
stop_glerror();
}
@@ -1496,12 +1461,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt
LL_PROFILE_ZONE_NUM(width);
LL_PROFILE_ZONE_NUM(height);
- // Release prior accounting only on the base mip; per-mip iteration
- // accumulates the rest via the additive alloc_tex_image.
- if (miplevel == 0)
- {
- free_cur_tex_image();
- }
+ free_cur_tex_image();
const bool use_sub_image = should_stagger_image_set(compress);
if (!use_sub_image)
{
@@ -1653,6 +1613,7 @@ bool LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
{
destroyGLTexture();
mCurrentDiscardLevel = discard_level;
+ mLastBindTime = sLastFrameTime;
mGLTextureCreated = false;
return true ;
}
@@ -1768,7 +1729,9 @@ bool LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, bool data_
mTextureMemory = (S64Bytes)getMipBytes(mCurrentDiscardLevel);
- mGLCreateTime = sLastFrameTime;
+
+ // mark this as bound at this point, so we don't throw it out immediately
+ mLastBindTime = sLastFrameTime;
checkActiveThread();
return true;
@@ -1895,7 +1858,7 @@ bool LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
LLGLint is_compressed = 0;
if (compressed_ok)
{
- glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
+ glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
}
//-----------------------------------------------------------------------------------------------
@@ -2076,28 +2039,6 @@ S32 LLImageGL::getWidth(S32 discard_level) const
return width;
}
-// static
-S32 LLImageGL::dimDerivedMaxDiscard(S32 width, S32 height)
-{
- if (width <= 0 || height <= 0)
- {
- return 0;
- }
- // max(w,h) - min() caps short on rectangular textures
- // (1024x512 reaches 1x1 at discard 10, not 9).
- return (S32)floorf(log2f((F32)llmax(width, 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.
- if (mLastBindTime != sLastFrameTime)
- {
- mLastBindTime = sLastFrameTime;
- }
-}
-
S64 LLImageGL::getBytes(S32 discard_level) const
{
if (discard_level < 0)
@@ -2527,12 +2468,7 @@ bool LLImageGL::scaleDown(S32 desired_discard)
return false;
}
- // GL pyramid reaches 1x1 regardless of codec levels;
- // mMaxDiscardLevel is hardcapped at MAX_DISCARD_LEVEL.
- S32 dim_max_discard = (mWidth > 0 && mHeight > 0)
- ? dimDerivedMaxDiscard(mWidth, mHeight)
- : (S32)mMaxDiscardLevel;
- desired_discard = llmin(desired_discard, dim_max_discard);
+ desired_discard = llmin(desired_discard, mMaxDiscardLevel);
if (desired_discard <= mCurrentDiscardLevel)
{
@@ -2565,7 +2501,6 @@ bool LLImageGL::scaleDown(S32 desired_discard)
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
gGL.getTexUnit(0)->bind(this);
glGenerateMipmap(mTarget);
- account_extra_mip_bytes(desired_width, desired_height, mFormatInternal);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
}
@@ -2611,7 +2546,6 @@ bool LLImageGL::scaleDown(S32 desired_discard)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("scaleDown - glGenerateMipmap");
glGenerateMipmap(mTarget);
- account_extra_mip_bytes(desired_width, desired_height, mFormatInternal);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 0c85446b84..6b4492c09e 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -51,11 +51,6 @@ class LLWindow;
namespace LLImageGLMemory
{
void alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count);
-
- // Add mip 1..N bytes to existing accounting. Call after glGenerateMipmap
- // when only the base mip was accounted; without this the bytes counter
- // undercounts mipmap-generated textures by ~25%.
- void account_extra_mip_bytes(U32 base_width, U32 base_height, U32 intformat);
void free_tex_image(U32 texName);
void free_tex_images(U32 count, const U32* texNames);
void free_cur_tex_image();
@@ -156,15 +151,6 @@ public:
S32 getDiscardLevel() const { return mCurrentDiscardLevel; }
S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; }
- // floor(log2(max(w, h))) - deepest GL pyramid level (down to 1x1).
- // Returns 0 for non-positive inputs.
- static S32 dimDerivedMaxDiscard(S32 width, S32 height);
-
- // Record the wall-clock bind time - every bind path that touches a
- // streaming-managed texture must call this, or the staleness signal
- // sees the texture as never-bound and ramps it toward eviction.
- void stampBound() const;
-
// override the current discard level
// should only be used for local textures where you know exactly what you're doing
void setDiscardLevel(S32 level) { mCurrentDiscardLevel = level; }
@@ -238,8 +224,7 @@ public:
public:
// Various GL/Rendering options
S64Bytes mTextureMemory;
- mutable F32 mLastBindTime = 0.f; // wall-clock time at last stampBound; drives streaming staleness
- F32 mGLCreateTime = 0.f; // wall-clock time the GL texture was created; staleness fallback for never-bound textures
+ mutable F32 mLastBindTime; // last time this was bound, by discard level
private:
U32 createPickMask(S32 pWidth, S32 pHeight);
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 5e845fbcce..57be8570af 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -197,10 +197,6 @@ void LLTexUnit::bindFast(LLTexture* texture)
glActiveTexture(GL_TEXTURE0 + mIndex);
gGL.mCurrTextureUnitIndex = mIndex;
mCurrTexture = gl_tex->getTexName();
- mCurrTexType = gl_tex->getTarget();
- // bindFast bypasses updateBindStats(); stamp directly so the staleness
- // signal sees per-frame use of batched textures.
- gl_tex->stampBound();
if (!mCurrTexture)
{
LL_PROFILE_ZONE_NAMED("MISSING TEXTURE");
@@ -253,17 +249,11 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
setTextureFilteringOption(gl_tex->mFilterOption);
}
}
- else
- {
- // Already current - still being used, keep it fresh.
- gl_tex->stampBound();
- }
}
else
{
//if deleted, will re-generate it immediately
texture->forceImmediateUpdate() ;
- gl_tex->stampBound();
gl_tex->forceUpdateBindStats() ;
return texture->bindDefaultImage(mIndex);
@@ -335,11 +325,6 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32
stop_glerror();
}
}
- else
- {
- // Already current - still being used, keep it fresh.
- texture->stampBound();
- }
stop_glerror();
@@ -1733,16 +1718,7 @@ LLVertexBuffer* LLRender::genBuffer(U32 attribute_mask, S32 count)
LLVertexBuffer * vb = new LLVertexBuffer(attribute_mask);
vb->allocateBuffer(count, 0);
- // Non-Apple path uses glBufferSubData inside setXxxData, so the VBO
- // must already be bound. On Apple, the VBO is lazily created in
- // _unmapBuffer (LLAppleVBOPool); calling setBuffer() here would bind
- // mGLBuffer == 0 and then setupVertexBuffer would issue
- // glVertexAttribIPointer with a non-null offset against no bound
- // GL_ARRAY_BUFFER -> GL_INVALID_OPERATION in core profile.
- if (!gGLManager.mIsApple)
- {
- vb->setBuffer();
- }
+ vb->setBuffer();
vb->setPositionData(mVerticesp.get());
@@ -1757,9 +1733,6 @@ LLVertexBuffer* LLRender::genBuffer(U32 attribute_mask, S32 count)
}
#if LL_DARWIN
- // unmapBuffer creates the GL buffer, uploads, and leaves it bound,
- // drawBuffer's later setBuffer() then runs setupVertexBuffer against
- // a valid VBO.
vb->unmapBuffer();
#endif
vb->unbind();
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 81299a5b71..1ac4583dd3 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -8049,7 +8049,7 @@
<key>RenderMaxTextureResolution</key>
<map>
<key>Comment</key>
- <string>Maximum texture resolution to download for non-boosted textures. Driven by RenderTextureQuality.</string>
+ <string>Maximum texture resolution to download for non-boosted textures.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -8057,17 +8057,6 @@
<key>Value</key>
<integer>2048</integer>
</map>
- <key>RenderTextureQuality</key>
- <map>
- <key>Comment</key>
- <string>Texture quality preset: 0=Low, 1=Medium, 2=High, 3=Ultra. Drives RenderMaxTextureResolution, the four TextureChannel* exponents, and TextureDistanceDiscardPower.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>U32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
<key>RenderDownScaleMethod</key>
<map>
<key>Comment</key>
@@ -9265,7 +9254,7 @@
<key>RenderReflectionDetail</key>
<map>
<key>Comment</key>
- <string>DEPRECATED - use RenderTransparentWater and RenderReflectionProbeDetail - Detail of reflection render pass.</string>
+ <string>DEPRECATED -- use RenderTransparentWater and RenderReflectionProbeDetail -- Detail of reflection render pass.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -11871,316 +11860,33 @@
<key>Value</key>
<real>20.0</real>
</map>
- <key>TextureChannelNormal</key>
+ <key>TextureChannelPriority</key>
<map>
<key>Comment</key>
- <string>Per-channel discard exponent for normal maps. 1.0 = baseline; lower = more aggressive. Driven by the RenderTextureQuality preset.</string>
+ <string>Per-channel texture streaming aggressiveness. X=normals, Y=diffuse, Z=specular/metallic, W=emissive. 1.0=baseline, higher=more aggressive downrez.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>F32</string>
+ <string>Vector4</string>
<key>Value</key>
- <real>1.0</real>
- </map>
- <key>TextureChannelBaseColor</key>
- <map>
- <key>Comment</key>
- <string>Per-channel discard exponent for base color / diffuse. 1.0 = baseline; lower = more aggressive. Driven by the RenderTextureQuality preset.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.75</real>
- </map>
- <key>TextureChannelSpecular</key>
- <map>
- <key>Comment</key>
- <string>Per-channel discard exponent for specular / metallic-roughness. 1.0 = baseline; lower = more aggressive. Driven by the RenderTextureQuality preset.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureChannelEmissive</key>
- <map>
- <key>Comment</key>
- <string>Per-channel discard exponent for emissive. 1.0 = baseline; lower = more aggressive. Driven by the RenderTextureQuality preset.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.75</real>
+ <array>
+ <real>5</real>
+ <real>7.5</real>
+ <real>20</real>
+ <real>7.5</real>
+ </array>
</map>
- <key>TextureMaxDiscardOverride</key>
+ <key>TextureCameraBoost</key>
<map>
<key>Comment</key>
- <string>When non-zero, overrides the per-texture codec-derived max discard cap. 0 = use codec-reported levels. Higher lets the streaming math push past the codec ceiling; scaleDown handles the GL side.</string>
+ <string>Amount to boost resolution of textures that are important to the camera.</string>
<key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
<integer>0</integer>
- </map>
- <key>TextureMemoryHighWaterMark</key>
- <map>
- <key>Comment</key>
- <string>Fraction of budget (0..1) at which the pressure controller bypasses smoothing and slams to cap. Last-ditch min-discard also creeps without waiting for mult_progress.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.8</real>
- </map>
- <key>TextureMemoryPressureBackoffStart</key>
- <map>
- <key>Comment</key>
- <string>Fraction of the VRAM target at which the pressure ramp starts (0..1). Lower = earlier headroom-building; 1.0 disables backoff (ramp only above target).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.85</real>
- </map>
- <key>TextureMemoryPressureMaxMultiplier</key>
- <map>
- <key>Comment</key>
- <string>Upper bound on the VRAM-pressure distance multiplier (&gt;= 1). Mostly defensive -- at mult=64 the streaming ramp collapses to ~ramp_range/64, already extreme. Higher allows even more aggressive compression in tight-budget scenes.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>64.0</real>
- </map>
- <key>TextureLastDitchEngageProgress</key>
- <map>
- <key>Comment</key>
- <string>mult_progress (0..1) at which the last-ditch floor starts creeping up. The floor only advances when mult is at or above this fraction of its cap AND prediction is still over budget. Decays back toward 0 whenever prediction is under budget.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.95</real>
- </map>
- <key>TextureLastDitchRampRate</key>
- <map>
- <key>Comment</key>
- <string>Rate (discard levels/sec) at which sLastDitchMinDiscard creeps up while engaged. 0.5 = takes ~2 sec to add one discard level. Mirrors sDesiredDiscardBias ramp shape.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureLastDitchDecayRate</key>
- <map>
- <key>Comment</key>
- <string>Rate (discard levels/sec) at which sLastDitchMinDiscard decays back to 0 when prediction is under budget.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureLastDitchMinDiscardMax</key>
- <map>
- <key>Comment</key>
- <string>Hard ceiling on sLastDitchMinDiscard. At 13 the floor can climb all the way to the deepest meaningful mip; lower values cap how aggressive the last-ditch escalation can get before we are simply out of discards.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>13.0</real>
- </map>
- <key>TextureMemoryPressurePredictionGain</key>
- <map>
- <key>Comment</key>
- <string>Power exponent mapping predicted-over-budget ratio to target multiplier. target_mult = pred_over^gain. Higher gain saturates faster.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>10.0</real>
- </map>
- <key>TextureMemoryPressureSmoothingRate</key>
- <map>
- <key>Comment</key>
- <string>Lerp rate (1/sec) at which the pressure multiplier converges to its prediction-driven target. Higher = faster response, lower = smoother. Default 4 reaches ~63% in 0.25s.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>4.0</real>
- </map>
- <key>TextureTerrainDistanceFloor</key>
- <map>
- <key>Comment</key>
- <string>Minimum distance factor for BOOST_TERRAIN textures. Keeps combined &gt; 0 so VRAM pressure can evict terrain. Lower = higher idle quality, less pressure response.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.01</real>
- </map>
- <key>TextureTerrainCoverageFraction</key>
- <map>
- <key>Comment</key>
- <string>Synthetic on-screen coverage fraction for BOOST_TERRAIN textures (no faces are registered). Higher = higher idle quality, less pressure response.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.99</real>
- </map>
- <key>TextureAgentAvatarBoost</key>
- <map>
- <key>Comment</key>
- <string>Quality boost (0..1) for textures on the agent's avatar (rigged mesh / animated objects). Lower = higher quality. Preference, not exemption - pressure can still evict.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureBackgroundFactorRatePerSec</key>
- <map>
- <key>Comment</key>
- <string>Per-second ramp rate of the background-window discard floor (0..1). Snaps to 0 in foreground. Default 0.011 ~ 90s to saturate.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.011</real>
- </map>
- <key>TextureBackgroundDiscardOffset</key>
- <map>
- <key>Comment</key>
- <string>Backgrounded textures will only discard up to (dim_max - offset). e.g. a 2048 texture (dim_max 11) with offset 2 caps the background floor at discard 9. 0 disables the cap (background can drive to max discard).</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>S32</string>
- <key>Value</key>
- <integer>2</integer>
- </map>
-
- <key>TextureCloseBubbleMeters</key>
- <map>
- <key>Comment</key>
- <string>Close-camera bubble (meters). Faces inside this distance get dist_factor = 0 (no discard contribution); the ramp to 1 spans (bubble, draw_distance]. Shrinks toward TextureCloseBubbleMinMeters as VRAM pressure ramps the multiplier toward its cap.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>TextureCloseBubbleMinMeters</key>
- <map>
- <key>Comment</key>
- <string>Floor (meters) for the close-camera bubble under maximum VRAM pressure. At sMemoryPressureMultiplier = TextureMemoryPressureMaxMultiplier the bubble collapses to this value, allowing eviction of even close textures when nothing else fits.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>3.0</real>
- </map>
- <key>TextureCloseBubbleShrinkThreshold</key>
- <map>
- <key>Comment</key>
- <string>Bubble stays at full size until mult_progress exceeds this fraction (0..1) of its range to the cap. Above that, bubble lerps from full to TextureCloseBubbleMinMeters. Keeps the bubble out of the normal feedback loop.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.8</real>
- </map>
- <key>TextureCloseBubbleTrackRate</key>
- <map>
- <key>Comment</key>
- <string>Rate (1/sec) at which the actual bubble tracks its target. Lower = smoother, slower to react. Damps short-term multiplier swings so close textures don't yo-yo.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureDistanceDiscardPower</key>
- <map>
- <key>Comment</key>
- <string>Exponent on the distance factor (face_distance / draw_distance). 1.0 = linear; lower = textures hit max discard sooner with distance. Default 0.5 = sqrt.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>0.5</real>
- </map>
- <key>TextureSizeDiscardPower</key>
- <map>
- <key>Comment</key>
- <string>Exponent on the on-screen size factor (1 - coverage). 1.0 = linear; lower = small-on-screen textures attenuate sooner.</string>
- <key>Persist</key>
- <integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>1.0</real>
- </map>
- <key>TextureStalenessIntervalSeconds</key>
- <map>
- <key>Comment</key>
- <string>Seconds per staleness step. Per-interval increment is 1/max_discard so any texture saturates after interval * max_discard seconds idle.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>TextureBindDecaySeconds</key>
- <map>
- <key>Comment</key>
- <string>Grace seconds after a bind during which the staleness factor stays at 0. Prevents intermittently-bound textures from ramping. 0 disables the grace period.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>5.0</real>
- </map>
- <key>TextureFetchPressureScale</key>
- <map>
- <key>Comment</key>
- <string>Pending-fetch divisor for the bias floor: bias floor = 1 + clamp(pending / scale, 0, 3). Lower = bias rises sooner under load floods.</string>
- <key>Persist</key>
- <integer>1</integer>
- <key>Type</key>
- <string>F32</string>
- <key>Value</key>
- <real>1000.0</real>
+ <real>8.0</real>
</map>
-
<key>TextureDecodeDisabled</key>
<map>
<key>Comment</key>
@@ -16544,7 +16250,7 @@
<key>EmulateCoreCount</key>
<map>
<key>Comment</key>
- <string>For debugging - number of cores to restrict the main process to, or 0 for no limit. Requires restart.</string>
+ <string>For debugging -- number of cores to restrict the main process to, or 0 for no limit. Requires restart.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@@ -16698,7 +16404,7 @@
<key>MultiModeDoubleClickFolder</key>
<map>
<key>Comment</key>
- <string>Sets the action for Double-click on folder in multi-folder view (0 - expands and collapses folder, 1 - opens a new window, 2 - stays in current floater but switches to SFV)</string>
+ <string>Sets the action for Double-click on folder in multi-folder view (0 - expands and collapses folder, 1 - opens a new window, 2 – stays in current floater but switches to SFV)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index f05f77c222..1090dd8ffb 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -1,4 +1,4 @@
-version 76
+version 74
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@@ -85,7 +85,7 @@ RenderExposure 1 4
RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
-RenderTextureQuality 1 3
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -128,6 +128,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
+RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
@@ -170,6 +171,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
+RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
@@ -211,6 +213,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
@@ -252,6 +255,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
@@ -293,6 +297,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
@@ -334,6 +339,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -375,6 +381,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -393,24 +400,6 @@ list VRAMGT512
RenderCompressTextures 1 0
//
-// VRAM 4GB to 8GB
-//
-list VRAMLT8GB
-RenderTextureQuality 1 2
-
-//
-// VRAM 2GB to 4GB
-//
-list VRAMLT4GB
-RenderTextureQuality 1 1
-
-//
-// VRAM 2GB and under
-//
-list VRAMLT2GB
-RenderTextureQuality 1 0
-
-//
// "Default" setups for safe, low, medium, high
//
list safe
@@ -426,7 +415,7 @@ RenderShadowDetail 0 0
RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
RenderDisableVintageMode 1 0
-RenderTextureQuality 1 2
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list Intel
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index b11fa28c48..c3e2dd0c41 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -1,4 +1,4 @@
-version 75
+version 73
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@@ -85,7 +85,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderDownScaleMethod 1 0
-RenderTextureQuality 1 3
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -128,6 +128,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
+RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
@@ -170,6 +171,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
+RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
@@ -211,6 +213,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
@@ -252,6 +255,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
@@ -293,6 +297,7 @@ RenderCASSharpness 1 0
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
@@ -334,6 +339,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -375,6 +381,7 @@ RenderCASSharpness 1 0.4
RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
@@ -394,24 +401,6 @@ list VRAMGT512
RenderCompressTextures 1 0
//
-// VRAM 4GB to 8GB
-//
-list VRAMLT8GB
-RenderTextureQuality 1 2
-
-//
-// VRAM 2GB to 4GB
-//
-list VRAMLT4GB
-RenderTextureQuality 1 1
-
-//
-// VRAM 2GB and under
-//
-list VRAMLT2GB
-RenderTextureQuality 1 0
-
-//
// "Default" setups for safe, low, medium, high
//
list safe
@@ -425,7 +414,7 @@ RenderDeferredSSAO 0 0
RenderShadowDetail 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
-RenderTextureQuality 1 2
+RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list TexUnit8orLess
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index fbecaa1583..cdf3244389 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -204,22 +204,22 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass)
if (tex_a && (!tex_b || (tex_a == tex_b)))
{
- tex_a->setFilteringOption(filter_mode);
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
+ tex_a->setFilteringOption(filter_mode);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b && !tex_a)
{
- tex_b->setFilteringOption(filter_mode);
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_b);
+ tex_b->setFilteringOption(filter_mode);
blend_factor = 0; // only one tex provided, no blending
}
else if (tex_b != tex_a)
{
- tex_a->setFilteringOption(filter_mode);
- tex_b->setFilteringOption(filter_mode);
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a);
+ tex_a->setFilteringOption(filter_mode);
shader->bindTexture(LLViewerShaderMgr::BUMP_MAP2, tex_b);
+ tex_b->setFilteringOption(filter_mode);
}
shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index e34bea63ef..018d4c4bba 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1577,7 +1577,7 @@ bool LLFace::getGeometryVolume(const LLVolume& volume,
skin = mSkinInfo;
}
- //TODO - cache this (check profile marker above)?
+ //TODO -- cache this (check profile marker above)?
glm::mat4 m = glm::make_mat4((F32*)skin->mBindShapeMatrix.getF32ptr());
m = glm::transpose(glm::inverse(m));
mat_normal.loadu(glm::value_ptr(m));
@@ -2265,18 +2265,7 @@ F32 LLFace::getTextureVirtualSize()
face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
}
- // Diffuse source area as the dim-aware hint for adjustPixelArea.
- S32 source_area = 0;
- if (mTexture[LLRender::DIFFUSE_MAP].notNull())
- {
- S32 sw = mTexture[LLRender::DIFFUSE_MAP]->getFullWidth();
- S32 sh = mTexture[LLRender::DIFFUSE_MAP]->getFullHeight();
- if (sw > 0 && sh > 0)
- {
- source_area = sw * sh;
- }
- }
- face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area, source_area);
+ face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area);
if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
{
if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage())
@@ -2400,7 +2389,6 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
F32 dist = lookAt.getLength3().getF32();
dist = llmax(dist-size.getLength3().getF32(), 0.001f);
- mDistanceToCamera = dist;
lookAt.normalize3fast() ;
@@ -2525,16 +2513,8 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
}
//static
-F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area, S32 source_area)
+F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area)
{
- // Dim-aware floor: source_area/256 lowers the "large but unimportant"
- // clamp proportionally so smaller sources can be pushed past discard 4.
- F32 large_floor = (F32)LLViewerTexture::sMinLargeImageSize;
- if (source_area > 0)
- {
- large_floor = llmin(large_floor, (F32)source_area / 256.f);
- }
-
if(pixel_area > LLViewerTexture::sMaxSmallImageSize)
{
if(importance < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
@@ -2542,11 +2522,11 @@ F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area, S32 source_area)
static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
pixel_area = llmin(pixel_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
}
- else if(pixel_area > large_floor) //if is large image, shrink face_area by considering the partial overlapping.
+ else if(pixel_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
{
if(importance < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
{
- pixel_area = large_floor ;
+ pixel_area = (F32)LLViewerTexture::sMinLargeImageSize ;
}
}
}
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 71ba3d0f2f..6e9d23c3a2 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -242,9 +242,7 @@ private:
bool calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
public:
static F32 calcImportanceToCamera(F32 to_view_dir, F32 dist);
- // source_area > 0 lowers the "large but unimportant" floor for
- // moderate sources; 0 keeps the legacy sMinLargeImageSize floor.
- static F32 adjustPixelArea(F32 importance, F32 pixel_area, S32 source_area = 0) ;
+ static F32 adjustPixelArea(F32 importance, F32 pixel_area) ;
public:
@@ -253,9 +251,6 @@ public:
LLVector2 mTexExtents[2];
F32 mDistance;
- // Camera-to-face distance, cached by calcPixelArea; read by the
- // streaming math's distance signal.
- F32 mDistanceToCamera = 0.f;
F32 mLastUpdateTime;
F32 mLastSkinTime;
F32 mLastMoveTime;
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index aab2865ef7..c8692224f1 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -752,29 +752,9 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("VRAMGT512");
}
-
- // Texture quality is driven by detected VRAM. Feature masks take the MIN
- // of applied values, so cascading lower tiers downgrade RenderTextureQuality:
- // <= 2GB -> Low(0), <= 4GB -> Medium(1), < 8GB -> High(2), >= 8GB -> Ultra(3).
- // When VRAM cannot be detected (mVRAM == 0, common on Linux) fall back to Medium.
- if (gGLManager.mVRAM == 0)
+ if (gGLManager.mVRAM < 2048)
{
- maskFeatures("VRAMLT4GB");
- }
- else
- {
- if (gGLManager.mVRAM < 8192)
- {
- maskFeatures("VRAMLT8GB");
- }
- if (gGLManager.mVRAM <= 4096)
- {
- maskFeatures("VRAMLT4GB");
- }
- if (gGLManager.mVRAM <= 2048)
- {
- maskFeatures("VRAMLT2GB");
- }
+ maskFeatures("VRAMLT2GB");
}
if (gGLManager.mGLVersion < 3.99f)
{
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index fe77d585c8..64359b6cbe 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -57,8 +57,6 @@ namespace
LLColor4U MAX_WATER_COLOR(0, 48, 96, 240);
S32 LLSurface::sTextureSize = 256;
-F32 LLSurface::sNearestVisiblePatchDistance = FLT_MAX;
-U32 LLSurface::sNearestVisiblePatchFrame = 0;
// ---------------- LLSurface:: Public Members ---------------
@@ -124,7 +122,7 @@ LLSurface::~LLSurface()
else if (poolp->mReferences.empty())
{
gPipeline.removePool(poolp);
- // Don't enable this until we blitz the draw pool for it as well. - djs
+ // Don't enable this until we blitz the draw pool for it as well. -- djs
mSTexturep = nullptr;
}
else
@@ -585,13 +583,6 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent)
LLSurfacePatch *patchp;
- // Reset the cross-region accumulator at the start of each frame.
- if (sNearestVisiblePatchFrame != gFrameCount)
- {
- sNearestVisiblePatchDistance = FLT_MAX;
- sNearestVisiblePatchFrame = gFrameCount;
- }
-
mVisiblePatchCount = 0;
for (S32 i=0; i<mNumberOfPatches; i++)
{
@@ -602,7 +593,6 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent)
{
mVisiblePatchCount++;
patchp->updateCameraDistanceRegion(pos_region);
- sNearestVisiblePatchDistance = llmin(sNearestVisiblePatchDistance, patchp->getDistance());
}
}
}
@@ -971,7 +961,7 @@ std::ostream& operator<<(std::ostream &s, const LLSurface &S)
void LLSurface::createPatchData()
{
// Assumes mGridsPerEdge, mGridsPerPatchEdge, and mPatchesPerEdge have been properly set
- // TODO - check for create() called when surface is not empty
+ // TODO -- check for create() called when surface is not empty
S32 i, j;
LLSurfacePatch *patchp;
diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h
index 4bdb90b102..a599019ca5 100644
--- a/indra/newview/llsurface.h
+++ b/indra/newview/llsurface.h
@@ -163,12 +163,6 @@ public:
F32 mDetailTextureScale; // Number of times to repeat detail texture across this surface
- // Closest visible patch distance across all surfaces this frame
- // (meters), or FLT_MAX if none visible. Drives BOOST_TERRAIN
- // streaming - terrain has no faces registered with its texture.
- static F32 sNearestVisiblePatchDistance;
- static U32 sNearestVisiblePatchFrame;
-
private:
void createSTexture();
void initTextures();
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 574c200eb4..51ade60827 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -542,7 +542,6 @@ private:
S32 mRequestedDiscard;
S32 mLoadedDiscard;
S32 mDecodedDiscard;
- S32 mCodecLevels = 0;
LLFrameTimer mRequestedDeltaTimer;
LLFrameTimer mFetchDeltaTimer;
LLTimer mCacheReadTimer;
@@ -1844,10 +1843,6 @@ bool LLTextureFetchWorker::doWork(S32 param)
else
{
llassert_always(mRawImage.notNull());
- if (mFormattedImage.notNull())
- {
- mCodecLevels = (S32)mFormattedImage->getLevels();
- }
LL_DEBUGS(LOG_TXT) << mID << ": Decoded. Discard: " << mDecodedDiscard
<< " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
setState(WRITE_TO_CACHE);
@@ -2779,12 +2774,10 @@ LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
// Threads: T*
bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, S32& worker_state,
LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
- LLCore::HttpStatus& last_http_get_status,
- S32& codec_levels)
+ LLCore::HttpStatus& last_http_get_status)
{
LL_PROFILE_ZONE_SCOPED;
bool res = false;
- codec_levels = 0;
LLTextureFetchWorker* worker = getWorker(id);
if (worker)
{
@@ -2816,9 +2809,6 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, S3
discard_level = worker->mDecodedDiscard;
raw = worker->mRawImage;
aux = worker->mAuxImage;
- // Cached on the worker so the value survives mFormattedImage
- // clears (cache-retry, decode-abort, write-to-cache complete).
- codec_levels = worker->mCodecLevels;
decode_time = worker->mDecodeTime;
fetch_time = worker->mFetchTime;
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index d75e16ab7c..851d6c11a0 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -106,8 +106,7 @@ public:
// keep in mind that if fetcher isn't done, it still might need original raw image
bool getRequestFinished(const LLUUID& id, S32& discard_level, S32& worker_state,
LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux,
- LLCore::HttpStatus& last_http_get_status,
- S32& codec_levels);
+ LLCore::HttpStatus& last_http_get_status);
// Threads: T*
bool updateRequestPriority(const LLUUID& id, F32 priority);
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 470a133fa7..cbe2dac52a 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -572,13 +572,9 @@ void LLGLTexMemBar::draw()
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*8,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
- text = llformat("Images: %d Raw: %d (%.2f MB) Saved: %d (%.2f MB) Aux: %d (%.2f MB) Bubble: %.1fm PressMult: %.1fx LDMin: %.1f",
- image_count, raw_image_count, raw_image_bytes_MB,
+ text = llformat("Images: %d Raw: %d (%.2f MB) Saved: %d (%.2f MB) Aux: %d (%.2f MB)", image_count, raw_image_count, raw_image_bytes_MB,
saved_raw_image_count, saved_raw_image_bytes_MB,
- aux_raw_image_count, aux_raw_image_bytes_MB,
- LLViewerTextureList::sCurrentBubbleMeters,
- LLViewerTexture::sMemoryPressureMultiplier,
- LLViewerTexture::sLastDitchMinDiscard);
+ aux_raw_image_count, aux_raw_image_bytes_MB);
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height * 7,
text_color, LLFontGL::LEFT, LLFontGL::TOP);
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a4a7f1fd20..0c93b24751 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -112,48 +112,6 @@ static bool handleRenderAvatarMouselookChanged(const LLSD& newvalue)
return true;
}
-static bool handleRenderTextureQualityChanged(const LLSD& newvalue)
-{
- // 0=Low, 1=Medium, 2=High, 3=Ultra. Drives RenderMaxTextureResolution,
- // the four TextureChannel* exponents (Normal/BaseColor/Spec/Emissive),
- // and TextureDistanceDiscardPower.
- U32 quality = (U32)newvalue.asInteger();
- U32 max_res = 2048;
- F32 ch_normal = 1.0f;
- F32 ch_basecolor = 0.75f;
- F32 ch_specular = 0.5f;
- F32 ch_emissive = 0.75f;
- F32 distance_power = 0.5f;
- switch (quality)
- {
- case 0: // Low
- max_res = 1024;
- ch_normal = 0.5f; ch_basecolor = 0.75f; ch_specular = 0.1f; ch_emissive = 0.5f;
- distance_power = 0.15f;
- break;
- case 1: // Medium
- ch_normal = 0.75f; ch_basecolor = 0.75f; ch_specular = 0.3f; ch_emissive = 0.75f;
- distance_power = 0.25f;
- break;
- case 2: // High
- // channel defaults above
- distance_power = 0.35f;
- break;
- case 3: // Ultra
- default:
- ch_normal = 1.f; ch_basecolor = 1.f; ch_specular = 1.f; ch_emissive = 1.f;
- distance_power = 0.5f;
- break;
- }
- gSavedSettings.setU32("RenderMaxTextureResolution", max_res);
- gSavedSettings.setF32("TextureChannelNormal", ch_normal);
- gSavedSettings.setF32("TextureChannelBaseColor", ch_basecolor);
- gSavedSettings.setF32("TextureChannelSpecular", ch_specular);
- gSavedSettings.setF32("TextureChannelEmissive", ch_emissive);
- gSavedSettings.setF32("TextureDistanceDiscardPower", distance_power);
- return true;
-}
-
static bool handleRenderFarClipChanged(const LLSD& newvalue)
{
if (LLStartUp::getStartupState() >= STATE_STARTED)
@@ -857,7 +815,6 @@ void settings_setup_listeners()
{
LL_PROFILE_ZONE_SCOPED;
setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged);
- setting_setup_signal_listener(gSavedSettings, "RenderTextureQuality", handleRenderTextureQualityChanged);
setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainScale", handleTerrainScaleChanged);
setting_setup_signal_listener(gSavedSettings, "RenderTerrainPBRScale", handlePBRTerrainScaleChanged);
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index ac8bb1d0c5..0f23596c9a 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -87,17 +87,6 @@ S32 LLViewerTexture::sRawCount = 0;
S32 LLViewerTexture::sAuxCount = 0;
LLFrameTimer LLViewerTexture::sEvaluationTimer;
F32 LLViewerTexture::sDesiredDiscardBias = 0.f;
-F32 LLViewerTexture::sBackgroundFactor = 0.f;
-F32 LLViewerTexture::sMemoryPressureMultiplier = 1.f;
-F32 LLViewerTexture::sLastDitchMinDiscard = 0.f;
-
-//static
-F32 LLViewerTexture::getMemoryPressureProgress()
-{
- static LLCachedControl<F32> max_mult(gSavedSettings, "TextureMemoryPressureMaxMultiplier", 64.f);
- F32 cap = llmax((F32)max_mult, 1.0001f);
- return llclampf((sMemoryPressureMultiplier - 1.f) / (cap - 1.f));
-}
U32 LLViewerTexture::sBiasTexturesUpdated = 0;
S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size
@@ -108,13 +97,12 @@ constexpr S32 DEFAULT_ICON_DIMENSIONS = 32;
constexpr S32 DEFAULT_THUMBNAIL_DIMENSIONS = 256;
U32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256.
U32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA;
+bool LLViewerTexture::sFreezeImageUpdates = false;
F32 LLViewerTexture::sCurrentTime = 0.0f;
constexpr F32 MEMORY_CHECK_WAIT_TIME = 1.0f;
constexpr F32 MIN_VRAM_BUDGET = 768.f;
F32 LLViewerTexture::sFreeVRAMMegabytes = MIN_VRAM_BUDGET;
-F32 LLViewerTexture::sWindowPixelArea = 1.f;
-F32 LLViewerTexture::sSysMemoryFactor = 1.f;
LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF;
@@ -132,7 +120,7 @@ LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb,
LLViewerFetchedTexture* target,
bool pause)
: mCallback(cb),
- mLastUsedDiscard(S32_MAX),
+ mLastUsedDiscard(MAX_DISCARD_LEVEL+1),
mDesiredDiscard(discard_level),
mNeedsImageRaw(need_imageraw),
mUserData(userdata),
@@ -491,26 +479,12 @@ void LLViewerTexture::initClass()
LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture();
}
-S32Megabytes get_render_free_main_memory_treshold()
-{
- static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
- const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
- return MIN_FREE_MAIN_MEMORY;
-}
-
//static
void LLViewerTexture::updateClass()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
sCurrentTime = gFrameTimeSeconds;
- if (gViewerWindow)
- {
- F32 w = (F32)gViewerWindow->getWindowWidthRaw();
- F32 h = (F32)gViewerWindow->getWindowHeightRaw();
- sWindowPixelArea = llmax(w * h, 1.f);
- }
-
LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName);
if (tester)
{
@@ -531,213 +505,29 @@ void LLViewerTexture::updateClass()
// get an estimate of how much video memory we're using
// NOTE: our metrics miss about half the vram we use, so this biases high but turns out to typically be within 5% of the real number
- F32 vram_used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc);
+ F32 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc);
// For debugging purposes, it's useful to be able to set the VRAM budget manually.
// But when manual control is not enabled, use the VRAM divisor.
// While we're at it, assume we have 1024 to play with at minimum when the divisor is in use. Works more elegantly with the logic below this.
// -Geenz 2025-03-21
- F32 vram_budget = max_vram_budget == 0 ? llmax(1024, (F32)gGLManager.mVRAM / tex_vram_divisor) : (F32)max_vram_budget;
+ F32 budget = max_vram_budget == 0 ? llmax(1024, (F32)gGLManager.mVRAM / tex_vram_divisor) : (F32)max_vram_budget;
// Try to leave at least half a GB for everyone else and for bias,
// but keep at least 768MB for ourselves
// Viewer can 'overshoot' target when scene changes, if viewer goes over budget it
// can negatively impact performance, so leave 20% of a breathing room for
// 'bias' calculation to kick in.
- F32 vram_target = llmax(llmin(vram_budget - 512.f, vram_budget * 0.8f), MIN_VRAM_BUDGET);
- sFreeVRAMMegabytes = vram_target - vram_used;
- const S32Megabytes free_sys_mem = getFreeSystemMemory();
+ F32 target = llmax(llmin(budget - 512.f, budget * 0.8f), MIN_VRAM_BUDGET);
+ sFreeVRAMMegabytes = target - used;
- F32 over_pct = (vram_used - vram_target) / vram_target;
-
- // Predicted-VRAM pressure controller. Eviction is fast, refetch is slow,
- // so feedback on instantaneous `used` sawtooths; feeding `used +
- // in_flight_delta` lets mult converge to equilibrium instead of cycling.
- {
- static LLCachedControl<F32> backoff_start(gSavedSettings, "TextureMemoryPressureBackoffStart", 0.85f);
- static LLCachedControl<F32> max_mult(gSavedSettings, "TextureMemoryPressureMaxMultiplier", 64.f);
- static LLCachedControl<F32> prediction_gain(gSavedSettings, "TextureMemoryPressurePredictionGain", 10.f);
- static LLCachedControl<F32> smoothing_rate(gSavedSettings, "TextureMemoryPressureSmoothingRate", 4.f);
-
- F32 backoff_target = vram_target * llclamp((F32)backoff_start, 0.05f, 1.f);
- F32 cap = llmax((F32)max_mult, 1.0001f);
- F32 dt = (F32)gFrameIntervalSeconds;
-
- // Skip the full-list iteration when there is no pressure to react to:
- // mult already at baseline, last-ditch at zero, and used well clear of
- // the backoff target. Worst case the controller picks up the spike one
- // frame later, from `used` alone.
- bool need_predict = sMemoryPressureMultiplier > 1.001f
- || sLastDitchMinDiscard > 0.f
- || vram_used > backoff_target * 0.5f;
-
- S64 pending_bytes_increase = 0;
- S64 pending_bytes_decrease = 0;
- if (need_predict)
- {
- LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vt - in-flight predict");
- for (auto& imagep : gTextureList)
- {
- if (imagep.isNull()) continue;
- // Cheap inline checks first so the virtual getDiscardLevel()
- // call only fires when there is a real chance of contribution.
- S32 desired = imagep->getDesiredDiscardLevel();
- if (desired < 0) continue;
- S32 fw = imagep->getFullWidth();
- S32 fh = imagep->getFullHeight();
- if (fw <= 0 || fh <= 0) continue;
- S32 current = imagep->getDiscardLevel();
- if (current < 0 || desired == current) continue;
-
- S32 wd = llmax(1, fw >> desired);
- S32 hd = llmax(1, fh >> desired);
- S32 wc = llmax(1, fw >> current);
- S32 hc = llmax(1, fh >> current);
- // bpp=4, mip pyramid overhead 4/3
- S64 size_d = (S64)wd * hd * 4 * 4 / 3;
- S64 size_c = (S64)wc * hc * 4 * 4 / 3;
-
- if (desired < current)
- pending_bytes_increase += (size_d - size_c);
- else
- pending_bytes_decrease += (size_c - size_d);
- }
- }
-
- // 1024 * 512 = 524288: matches the unit reduction at line 513.
- constexpr F32 BYTES_TO_USED_UNITS = 1.f / 524288.f;
- F32 predicted_used = vram_used
- + (F32)pending_bytes_increase * BYTES_TO_USED_UNITS
- - (F32)pending_bytes_decrease * BYTES_TO_USED_UNITS;
- F32 predicted_over = predicted_used / llmax(backoff_target, 1.f);
-
- // High water mark: when used crosses budget * high_water, skip the
- // smoothed convergence and slam the controller into hard-cap state.
- // Recovers the historical 90% behavior - immediate aggressive
- // response instead of waiting for the lerp to chase the target.
- static LLCachedControl<F32> high_water(gSavedSettings, "TextureMemoryHighWaterMark", 0.8f);
- bool above_high_water = vram_used >= vram_budget * llclamp((F32)high_water, 0.5f, 1.f);
-
- F32 target_mult = llclamp(powf(llmax(predicted_over, 1.f), llmax((F32)prediction_gain, 0.0001f)), 1.f, cap);
- if (above_high_water)
- {
- target_mult = cap;
- sMemoryPressureMultiplier = cap;
- }
- else
- {
- // ~63% convergence in 1/smoothing_rate seconds (default 0.25s).
- F32 alpha = 1.f - expf(-llmax(dt, 0.f) * llmax((F32)smoothing_rate, 0.f));
- sMemoryPressureMultiplier += (target_mult - sMemoryPressureMultiplier) * alpha;
- }
- sMemoryPressureMultiplier = llclamp(sMemoryPressureMultiplier, 1.f, cap);
-
- F32 progress = getMemoryPressureProgress();
-
- {
- static LLCachedControl<F32> ld_engage(gSavedSettings, "TextureLastDitchEngageProgress", 0.95f);
- static LLCachedControl<F32> ld_ramp(gSavedSettings, "TextureLastDitchRampRate", 0.5f);
- static LLCachedControl<F32> ld_decay(gSavedSettings, "TextureLastDitchDecayRate", 0.5f);
- static LLCachedControl<F32> ld_max(gSavedSettings, "TextureLastDitchMinDiscardMax", 13.f);
- // Above the high water mark, last-ditch creeps regardless of
- // mult_progress: by definition we are out of normal headroom.
- bool engage = above_high_water || progress >= llclampf((F32)ld_engage);
- if (engage && predicted_over > 1.f)
- {
- sLastDitchMinDiscard += llmax((F32)ld_ramp, 0.f) * dt;
- }
- else if (!above_high_water && predicted_over < 1.f)
- {
- sLastDitchMinDiscard -= llmax((F32)ld_decay, 0.f) * dt;
- }
- sLastDitchMinDiscard = llclamp(sLastDitchMinDiscard, 0.f, llmax((F32)ld_max, 0.f));
- }
-
- // 1 Hz pressure log.
- static LLFrameTimer s_pressure_log_timer;
- if (s_pressure_log_timer.getElapsedTimeF32() > 1.f)
- {
- s_pressure_log_timer.reset();
- F32 over = vram_used / llmax(backoff_target, 1.f);
- LL_INFOS("TextureStream") << "pressure"
- << " mult=" << sMemoryPressureMultiplier
- << " target_mult=" << target_mult
- << " progress=" << progress
- << " used=" << vram_used
- << " predicted=" << predicted_used
- << " target=" << vram_target
- << " over=" << over
- << " pred_over=" << predicted_over
- << " in+=" << (S32)(pending_bytes_increase / 1024 / 1024)
- << "MB in-=" << (S32)(pending_bytes_decrease / 1024 / 1024)
- << "MB bias=" << sDesiredDiscardBias
- << " ldmin=" << sLastDitchMinDiscard
- << " dsq=" << (S32)gTextureList.mDownScaleQueue.size()
- << LL_ENDL;
- }
- }
+ F32 over_pct = (used - target) / target;
bool is_sys_low = isSystemMemoryLow();
- bool is_sys_critically_low = isSystemMemoryCritical();
bool is_low = is_sys_low || over_pct > 0.f;
static bool was_low = false;
- static bool sys_was_low = false;
-
- // System memory factor
- // sSysMemoryFactor affects draw distance
- //
- // We only decrement when more than 406MB is free, but increment
- // when below 256MB free. This should provide a stable value
- // in the 256-406MB range to avoid draw range fluctuations.
- //
- // Draw range reduction is a last resort, texture bias is supposed
- // to free at least some memory before we get here.
- // Note: textures were mostly moved to vram, we might want to
- // detach texture bias from system memory.
- if (is_sys_critically_low)
- {
- const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() / 2);
- // debt is a negative value since MIN_FREE_MAIN_MEMORY > free memory.
- S32 sys_budget_debt = free_sys_mem - MIN_FREE_MAIN_MEMORY;
-
- // Leave some padding, otherwise we will crash out of memory before hitting factor 2.
- const S32Megabytes PAD_BUFFER(32);
- S32Megabytes budget_target = MIN_FREE_MAIN_MEMORY - PAD_BUFFER;
- if (!sys_was_low)
- {
- // Result should range from 1 at 0 debt to 2 at -224 debt, 2.14 at -256MB
- F32 new_factor = 1.f - (F32)sys_budget_debt / (F32)budget_target;
- sSysMemoryFactor = llmax(sSysMemoryFactor, new_factor);
- }
- else
- {
- // Slowly ramp up factor to free memory (increasing factor decreases draw range)
- constexpr F32 MAX_INCREMENT = 0.05f;
- F32 increment = MAX_INCREMENT * llmax(-(F32)sys_budget_debt / (F32)budget_target, 0.f);
- sSysMemoryFactor += increment * gFrameIntervalSeconds;
- }
- sSysMemoryFactor = llclamp(sSysMemoryFactor, 1.f, 2.f);
- }
- else
- {
- const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() / 2);
- // Only start ramping down when we have breathing room.
- // This should be under the value of isSystemMemoryLow to not throw texture
- // bias into 1.5+ territory each time we fluctuate around isSystemMemoryLow's
- // treshold.
- const S32Megabytes MEM_THRESHOLD = MIN_FREE_MAIN_MEMORY + S32Megabytes(150);
- if (free_sys_mem > MEM_THRESHOLD && sSysMemoryFactor > 1.f)
- {
- // Ramp down factor over time.
- constexpr F32 DECREMENT = 0.02f;
- sSysMemoryFactor -= DECREMENT * gFrameIntervalSeconds;
- sSysMemoryFactor = llclamp(sSysMemoryFactor, 1.f, 2.f);
- }
- }
- sys_was_low = is_sys_critically_low;
- // VRAM memory bias
if (is_low && !was_low)
{
if (is_sys_low)
@@ -779,18 +569,14 @@ void LLViewerTexture::updateClass()
// don't execute above until the slam to 1.5 has a chance to take effect
sEvaluationTimer.reset();
- // Don't decay bias while downscale is still draining - those bytes
- // are about to free and the loop would oscillate.
- bool eviction_in_flight = !gTextureList.mDownScaleQueue.empty();
-
// lower discard bias over time when at least 10% of budget is free
constexpr F32 FREE_PERCENTAGE_TRESHOLD = -0.1f;
- constexpr U32 FREE_SYS_MEM_THRESHOLD = 100; // 100MB more than isSystemMemoryLow to avoid fluctuations.
- const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() + S32Megabytes(FREE_SYS_MEM_THRESHOLD));
+ constexpr U32 FREE_SYS_MEM_TRESHOLD = 100;
+ static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
+ const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory() + FREE_SYS_MEM_TRESHOLD);
if (sDesiredDiscardBias > 1.f
&& over_pct < FREE_PERCENTAGE_TRESHOLD
- && free_sys_mem > MIN_FREE_MAIN_MEMORY
- && !eviction_in_flight)
+ && getFreeSystemMemory() > MIN_FREE_MAIN_MEMORY)
{
static LLCachedControl<F32> high_mem_discard_decrement(gSavedSettings, "RenderHighMemMinDiscardDecrement", .1f);
@@ -836,33 +622,6 @@ void LLViewerTexture::updateClass()
}
}
- // Background-window ramp: 0 -> 1 at rate per second while backgrounded,
- // snaps to 0 in foreground. Default 0.011 ~ 90s to saturate.
- {
- static LLCachedControl<F32> bg_factor_rate(gSavedSettings, "TextureBackgroundFactorRatePerSec", 0.011f);
- if (in_background)
- {
- sBackgroundFactor += (F32)bg_factor_rate * gFrameIntervalSeconds;
- sBackgroundFactor = llclampf(sBackgroundFactor);
- }
- else
- {
- sBackgroundFactor = 0.f;
- }
- }
-
- // Fetch-queue depth as a one-way bias floor (decay path still drops
- // bias when the queue drains). Pushes bias up before VRAM overflows
- // during teleport/scene-change floods.
- if (LLTextureFetch* fetcher = LLAppViewer::getTextureFetch())
- {
- S32 pending = fetcher->getNumRequests();
- static LLCachedControl<F32> fetch_pressure_scale(gSavedSettings, "TextureFetchPressureScale", 1000.f);
- F32 scale = llmax((F32)fetch_pressure_scale, 1.f);
- F32 fetch_pressure = llclamp((F32)pending / scale, 0.f, 3.f);
- sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.f + fetch_pressure);
- }
-
sDesiredDiscardBias = llclamp(sDesiredDiscardBias, 1.f, 4.f);
if (last_texture_update_count_bias < sDesiredDiscardBias)
{
@@ -879,6 +638,8 @@ void LLViewerTexture::updateClass()
// a problem.
last_texture_update_count_bias = sDesiredDiscardBias;
}
+
+ LLViewerTexture::sFreezeImageUpdates = false;
}
//static
@@ -899,6 +660,13 @@ U32Megabytes LLViewerTexture::getFreeSystemMemory()
return physical_res;
}
+S32Megabytes get_render_free_main_memory_treshold()
+{
+ static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
+ const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
+ return MIN_FREE_MAIN_MEMORY;
+}
+
//static
bool LLViewerTexture::isSystemMemoryLow()
{
@@ -911,10 +679,18 @@ bool LLViewerTexture::isSystemMemoryCritical()
return getFreeSystemMemory() < get_render_free_main_memory_treshold() / 2;
}
-// static
F32 LLViewerTexture::getSystemMemoryBudgetFactor()
{
- return sSysMemoryFactor;
+ const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() / 2);
+ S32 free_budget = (S32Megabytes)getFreeSystemMemory() - MIN_FREE_MAIN_MEMORY;
+ if (free_budget < 0)
+ {
+ // Leave some padding, otherwise we will crash out of memory before hitting factor 2.
+ const S32Megabytes PAD_BUFFER(32);
+ // Result should range from 1 at 0 free budget to 2 at -224 free budget, 2.14 at -256MB
+ return 1.f - free_budget / (MIN_FREE_MAIN_MEMORY - PAD_BUFFER);
+ }
+ return 1.f;
}
//end of static functions
@@ -1380,10 +1156,8 @@ void LLViewerFetchedTexture::init(bool firstinit)
mRequestedDownloadPriority = 0.f;
mFullyLoaded = false;
mCanUseHTTP = true;
- mDesiredDiscardLevel = S8_MAX;
- // S8_MAX = no cap. setMinDiscardLevel takes min(current, new), so
- // explicit caps from terrain / avatar self / thumbnails still apply.
- mMinDesiredDiscardLevel = S8_MAX;
+ mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
+ mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
mDecodingAux = false;
@@ -2203,10 +1977,21 @@ bool LLViewerFetchedTexture::processFetchResults(S32& desired_discard, S32 curre
setIsMissingAsset();
desired_discard = -1;
}
- // Transient failure (decoder OOM, network blip): don't latch
- // mMinDiscardLevel - that would block all future fetches via
- // the make_request gate. Permanent failures are caught above
- // (getDiscardLevel()<0 -> setIsMissingAsset).
+ else
+ {
+ //LL_WARNS() << mID << ": Setting min discard to " << current_discard << LL_ENDL;
+ if (current_discard >= 0)
+ {
+ mMinDiscardLevel = current_discard;
+ //desired_discard = current_discard;
+ }
+ else
+ {
+ S32 dis_level = getDiscardLevel();
+ mMinDiscardLevel = dis_level;
+ //desired_discard = dis_level;
+ }
+ }
destroyRawImage();
}
else if (mRawImage.notNull())
@@ -2287,18 +2072,8 @@ bool LLViewerFetchedTexture::updateFetch()
if (mRawImage.notNull()) sRawCount--;
if (mAuxRawImage.notNull()) sAuxCount--;
// keep in mind that fetcher still might need raw image, don't modify original
- S32 codec_levels = 0;
bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mFetchState, mRawImage, mAuxRawImage,
- mLastHttpGetStatus, codec_levels);
- if (codec_levels > 0)
- {
- mCodecMaxDiscardLevel = (S8)llmin(codec_levels, (S32)S8_MAX);
- if (codec_levels > 5)
- {
- LL_DEBUGS("TextureStream") << "Texture " << mID << " codec-reported max discard "
- << codec_levels << " (above the historical hardcoded cap of 5)" << LL_ENDL;
- }
- }
+ mLastHttpGetStatus);
if (mRawImage.notNull()) sRawCount++;
if (mAuxRawImage.notNull())
{
@@ -2333,9 +2108,7 @@ bool LLViewerFetchedTexture::updateFetch()
}
}
- // Clamp the fetch request to what the codestream encodes; deeper
- // discards are served from the GL mip pyramid via scaleDown.
- desired_discard = llmin(desired_discard, (S32)mCodecMaxDiscardLevel);
+ desired_discard = llmin(desired_discard, getMaxDiscardLevel());
bool make_request = true;
if (decode_priority <= 0)
@@ -2343,13 +2116,9 @@ bool LLViewerFetchedTexture::updateFetch()
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - priority <= 0");
make_request = false;
}
- else if (mDesiredDiscardLevel > (S32)mCodecMaxDiscardLevel &&
- current_discard >= 0)
+ else if (mDesiredDiscardLevel > getMaxDiscardLevel())
{
- // Desired is past codec_max. Only scaleDown can satisfy it.
- // Applies even when current is also past codec_max (post-scaleDown);
- // re-fetching at codec_max then scaleDown-ing again is pure thrash.
- LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - desired > codec max");
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - desired > max");
make_request = false;
}
else if (mNeedsCreateTexture || mIsMissingAsset)
@@ -2801,21 +2570,20 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
S32 gl_discard = getDiscardLevel();
- // S32_MAX is the "no data" sentinel; real discards can now exceed
- // MAX_DISCARD_LEVEL via dimDerivedMaxDiscard.
+ // If we don't have a legit GL image, set it to be lower than the worst discard level
if (gl_discard == -1)
{
- gl_discard = S32_MAX;
+ gl_discard = MAX_DISCARD_LEVEL + 1;
}
//
// Determine the quality levels of textures that we can provide to callbacks
// and whether we need to do decompression/readback to get it
//
- S32 current_raw_discard = S32_MAX; // We can always do a readback to get a raw discard
+ S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard
S32 best_raw_discard = gl_discard; // Current GL quality level
- S32 current_aux_discard = S32_MAX;
- S32 best_aux_discard = S32_MAX;
+ S32 current_aux_discard = MAX_DISCARD_LEVEL + 1;
+ S32 best_aux_discard = MAX_DISCARD_LEVEL + 1;
LLImageRaw *current_raw_image = nullptr;
if (mIsRawImageValid)
@@ -2915,7 +2683,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
//
// Run raw/auxiliary data callbacks
//
- if (run_raw_callbacks && current_raw_image != nullptr && current_raw_discard != S32_MAX)
+ if (run_raw_callbacks && current_raw_image != nullptr && (current_raw_discard <= getMaxDiscardLevel()))
{
// Do callbacks which require raw image data.
//LL_INFOS() << "doLoadedCallbacks raw for " << getID() << LL_ENDL;
@@ -2955,7 +2723,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
//
// Run GL callbacks
//
- if (run_gl_callbacks && gl_discard != S32_MAX)
+ if (run_gl_callbacks && (gl_discard <= getMaxDiscardLevel()))
{
//LL_INFOS() << "doLoadedCallbacks GL for " << getID() << LL_ENDL;
@@ -3258,6 +3026,11 @@ S8 LLViewerLODTexture::getType() const
return LLViewerTexture::LOD_TEXTURE;
}
+bool LLViewerLODTexture::isUpdateFrozen()
+{
+ return LLViewerTexture::sFreezeImageUpdates;
+}
+
// This is gauranteed to get called periodically for every texture
//virtual
void LLViewerLODTexture::processTextureStats()
@@ -3283,15 +3056,18 @@ void LLViewerLODTexture::processTextureStats()
{
mDesiredDiscardLevel = 0;
}
- // HUD/UI/preview and mDontDiscard textures bypass streaming - no
- // face_distance signal applies, they need native resolution.
- else if (mBoostLevel >= LLGLTexture::BOOST_HIGH
- || mDontDiscard
- || !mUseMipMaps)
+ // Generate the request priority and render priority
+ else if (mDontDiscard || !mUseMipMaps)
{
mDesiredDiscardLevel = 0;
if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
- mDesiredDiscardLevel = 1; // 4096^2 source can't be loaded full res
+ mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096
+ }
+ else if (mBoostLevel < LLGLTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f)
+ {
+ // If the image has not been significantly visible in a while, we don't want it
+ mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1));
+ mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S32)mLoadedCallbackDesiredDiscardLevel);
}
else if (!mFullWidth || !mFullHeight)
{
@@ -3300,104 +3076,28 @@ void LLViewerLODTexture::processTextureStats()
}
else
{
- F32 discard_level = 0.f;
+ //static const F64 log_2 = log(2.0);
+ static const F64 log_4 = log(4.0);
- // floor(log2(max(w, h))) - both the multiplier on the normalized
- // factor and the cap clamp at the bottom of this function.
- S32 dim_max_for_image_i = (mFullWidth > 0 && mFullHeight > 0)
- ? LLImageGL::dimDerivedMaxDiscard(mFullWidth, mFullHeight)
- : (S32)mCodecMaxDiscardLevel;
- F32 dim_max_for_image = (F32)dim_max_for_image_i;
+ F32 discard_level = 0.f;
+ // If we know the output width and height, we can force the discard
+ // level to the correct value, and thus not decode more texture
+ // data than we need to.
if (mKnownDrawWidth && mKnownDrawHeight)
{
- // UI-pinned target dimensions - use pixel-area math.
- static const F64 log_4 = log(4.0);
S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
draw_texels = llclamp(draw_texels, MIN_IMAGE_AREA, MAX_IMAGE_AREA);
+
+ // Use log_4 because we're in square-pixel space, so an image
+ // with twice the width and twice the height will have mTexelsPerImage
+ // 4 * draw_size
discard_level = (F32)(log(mTexelsPerImage / draw_texels) / log_4);
}
else
{
- // Two 0..1 signals composed multiplicatively:
- // discard = distance_factor * size_factor * max_discard
- // distance_factor: face_dist / draw_dist, shaped by
- // TextureDistanceDiscardPower (default 0.5 = sqrt).
- // size_factor: 1 - (mMaxOnScreenSize / window_pixels), shaped
- // by TextureSizeDiscardPower.
- // Either factor near 0 keeps the result fine - both have to
- // be high for the texture to go deep.
- static LLCachedControl<F32> distance_power(gSavedSettings, "TextureDistanceDiscardPower", 0.5f);
- F32 power = llmax((F32)distance_power, 0.0001f);
- F32 distance_factor = (power == 1.f) ? mMinDistanceFactor : powf(mMinDistanceFactor, power);
-
- static LLCachedControl<F32> size_power(gSavedSettings, "TextureSizeDiscardPower", 1.f);
- F32 sz_power = llmax((F32)size_power, 0.0001f);
- F32 coverage = llclampf(mMaxOnScreenSize / sWindowPixelArea);
- F32 inv_cov = 1.f - coverage;
- F32 size_factor = (sz_power == 1.f) ? inv_cov : powf(inv_cov, sz_power);
-
- F32 combined = distance_factor * size_factor;
-
- // VRAM pressure: multiply the combined signal and clamp to 0..1.
- // Compresses the effective draw range and picks up close-coverage
- // textures (small combined) too. Applied before the channel
- // exponent so subsequent transforms see a normalized 0..1 value.
- // Avatar bakes exempt.
- if (!isAgentAvatarBoost(mBoostLevel) && sMemoryPressureMultiplier > 1.f)
- {
- combined = llmin(combined * sMemoryPressureMultiplier, 1.f);
- }
-
- // Per-channel exponent. 1.0 = baseline; <1.0 pushes combined
- // toward 1 (max attenuation) faster. Edges are preserved:
- // pow(0, p) = 0, pow(1, p) = 1.
- // mPriorityChannel order: 0=Normal, 1=BaseColor, 2=Specular, 3=Emissive.
- S32 priority_channel = (mPriorityChannel >= 0 && mPriorityChannel < 4) ? (S32)mPriorityChannel : 1;
- static LLCachedControl<F32> channel_normal (gSavedSettings, "TextureChannelNormal", 1.0f);
- static LLCachedControl<F32> channel_basecolor(gSavedSettings, "TextureChannelBaseColor", 0.75f);
- static LLCachedControl<F32> channel_specular (gSavedSettings, "TextureChannelSpecular", 0.5f);
- static LLCachedControl<F32> channel_emissive (gSavedSettings, "TextureChannelEmissive", 0.75f);
- const F32 channels[4] = {
- (F32)channel_normal,
- (F32)channel_basecolor,
- (F32)channel_specular,
- (F32)channel_emissive,
- };
- F32 channel_power = llmax(channels[priority_channel], 0.0001f);
- if (channel_power != 1.f)
- {
- combined = powf(combined, channel_power);
- }
-
- // Own-avatar boost: shave combined for rigged/animated faces
- // on gAgentAvatarp. Preference, not exemption - applied
- // before the staleness/background/pressure floors so heavy
- // pressure can still evict.
- if (mOnAgentAvatar)
- {
- static LLCachedControl<F32> agent_avatar_boost(gSavedSettings, "TextureAgentAvatarBoost", 0.5f);
- combined *= llclampf((F32)agent_avatar_boost);
- }
-
- // Staleness / background floors. Avatar bakes exempt from
- // background to avoid the universal-cloud bug when re-foregrounding.
- combined = llmax(combined, mStalenessFactor);
- if (!isAgentAvatarBoost(mBoostLevel))
- {
- // Background floor capped at (dim_max - offset) so we can
- // keep some baseline quality while backgrounded.
- static LLCachedControl<S32> bg_offset(gSavedSettings, "TextureBackgroundDiscardOffset", 2);
- F32 bg = sBackgroundFactor;
- if ((S32)bg_offset > 0 && dim_max_for_image > 0.f)
- {
- F32 cap = llmax(dim_max_for_image - (F32)(S32)bg_offset, 0.f) / dim_max_for_image;
- bg = llmin(bg, cap);
- }
- combined = llmax(combined, bg);
- }
-
- discard_level = combined * dim_max_for_image;
+ // Calculate the required scale factor of the image using pixels per texel
+ discard_level = (F32)(log(mTexelsPerImage / mMaxVirtualSize) / log_4);
}
discard_level = floorf(discard_level);
@@ -3406,43 +3106,12 @@ void LLViewerLODTexture::processTextureStats()
if (mFullWidth > max_tex_res || mFullHeight > max_tex_res)
min_discard = 1.f;
- // dim_max_for_image_i is the per-texture cap. TextureMaxDiscardOverride
- // raises it (debug). Codec_max applies only to fetches, not here.
- static LLCachedControl<S32> max_discard_override(gSavedSettings, "TextureMaxDiscardOverride", 0);
- S32 effective_cap = (max_discard_override > 0) ? (S32)max_discard_override : dim_max_for_image_i;
- discard_level = llclamp(discard_level, min_discard, (F32)effective_cap);
-
- mDesiredDiscardLevel = llmin(effective_cap, (S32)discard_level);
-
- // Apply the setMinDiscardLevel cap, relaxed under VRAM pressure
- // (cap_relax = 1 - 1/mult: 0 at mult=1, ~0.5 at mult=2, ~0.9 at
- // mult=10). Caps of 0 (thumbnails) and avatar bakes are preserved.
- S32 effective_min_cap = mMinDesiredDiscardLevel;
- if (sMemoryPressureMultiplier > 1.f &&
- mMinDesiredDiscardLevel > 0 && mMinDesiredDiscardLevel < S8_MAX &&
- !isAgentAvatarBoost(mBoostLevel))
- {
- F32 cap_relax = 1.f - 1.f / sMemoryPressureMultiplier;
- F32 room = (F32)dim_max_for_image_i - (F32)mMinDesiredDiscardLevel;
- effective_min_cap += (S32)(cap_relax * room);
- effective_min_cap = llmin(effective_min_cap, dim_max_for_image_i);
- }
- mDesiredDiscardLevel = llmin((S8)effective_min_cap, mDesiredDiscardLevel);
-
- // Halve the floor for bubble-resident textures (mMinDistanceFactor == 0
- // = at least one face inside the bubble) so the close-vs-far gradient
- // is preserved at every pressure level.
- if (!isAgentAvatarBoost(mBoostLevel))
- {
- S32 forced = (S32)floorf(sLastDitchMinDiscard);
- if (mMinDistanceFactor <= 0.f) forced /= 2;
- forced = llclamp(forced, 0, dim_max_for_image_i);
- if (forced > mDesiredDiscardLevel)
- {
- mDesiredDiscardLevel = (S8)forced;
- }
- }
+ discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
+ // Can't go higher than the max discard level
+ mDesiredDiscardLevel = llmin(getMaxDiscardLevel() + 1, (S32)discard_level);
+ // Clamp to min desired discard
+ mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel);
//
// At this point we've calculated the quality level that we want,
@@ -3451,9 +3120,7 @@ void LLViewerLODTexture::processTextureStats()
//
S32 current_discard = getDiscardLevel();
- // Avatar bakes exempt: shrinking mid-bake can leave the avatar
- // stuck as a cloud until the next bake completes.
- if (!isAgentAvatarBoost(mBoostLevel))
+ if (mBoostLevel < LLGLTexture::BOOST_AVATAR_BAKED)
{
if (current_discard < mDesiredDiscardLevel && !mForceToSaveRawImage)
{ // should scale down
@@ -3461,6 +3128,13 @@ void LLViewerLODTexture::processTextureStats()
}
}
+ if (isUpdateFrozen() // we are out of memory and nearing max allowed bias
+ && mBoostLevel < LLGLTexture::BOOST_SCULPTED
+ && mDesiredDiscardLevel < current_discard)
+ {
+ // stop requesting more
+ mDesiredDiscardLevel = current_discard;
+ }
mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S32)mLoadedCallbackDesiredDiscardLevel);
}
@@ -3486,22 +3160,6 @@ bool LLViewerLODTexture::scaleDown()
return false;
}
- // Hard structural blocks only. Per-texture policy (icons pinned to full
- // res, etc.) lives in processTextureStats; if that policy is later
- // relaxed (e.g. honor mKnownDrawWidth for icons rendered at 8x8 in a
- // friend list) the scaleDown path stays open.
- // BOOST_HIGH is the emergency-out for GLTF's "force full res" hack;
- // the other two flags are structural.
- if (!mUseMipMaps || mDontDiscard || mBoostLevel >= LLGLTexture::BOOST_HIGH)
- {
- return false;
- }
- // Avatar bakes are exempt from mid-bake eviction (cloud avatar risk).
- if (isAgentAvatarBoost(mBoostLevel))
- {
- return false;
- }
-
if (!mDownScalePending)
{
mDownScalePending = true;
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 8c5c48bafd..2937651995 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -116,8 +116,6 @@ public:
static void updateClass();
static bool isSystemMemoryLow();
static bool isSystemMemoryCritical();
-
- // Ranges from 1 (no RAM deficit) to 2 (RAM deficit)
static F32 getSystemMemoryBudgetFactor();
LLViewerTexture(bool usemipmaps = true);
@@ -205,25 +203,6 @@ protected:
mutable S32 mMaxVirtualSizeResetInterval;
LLFrameTimer mLastReferencedTimer;
- // 0=Normal, 1=BaseColor, 2=Specular, 3=Emissive. -1 -> base color.
- S8 mPriorityChannel = -1;
-
- // Bind-staleness floor, 0..1. Per-interval increment is 1/max_discard
- // so any texture saturates after interval x max_discard seconds idle.
- F32 mStalenessFactor = 0.f;
-
- // Closest face's face_distance / draw_distance, clamped 0..1.
- // Defaults to 1 so never-measured textures resolve to deepest discard.
- F32 mMinDistanceFactor = 1.f;
-
- // Largest per-face screen-space coverage in pixels. Raw - no bias or
- // channel-priority contamination.
- F32 mMaxOnScreenSize = 0.f;
-
- // Any face on the agent's avatar (rigged / animated). Drives the
- // own-avatar quality boost in processTextureStats.
- bool mOnAgentAvatar = false;
-
ll_face_list_t mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
U32 mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
LLFrameTimer mLastFaceListUpdateTimer ;
@@ -245,36 +224,16 @@ public:
static S32 sAuxCount;
static LLFrameTimer sEvaluationTimer;
static F32 sDesiredDiscardBias;
- // Backgrounded-window discard floor, 0..1. Ramps while backgrounded,
- // snaps to 0 in foreground. Avatar bakes exempt.
- static F32 sBackgroundFactor;
-
- // VRAM-pressure distance multiplier, >= 1. Compresses the distance
- // signal: dist_factor = clamp(mMinDistanceFactor * mult, 0, 1).
- // Grows geometrically while over budget; decays back to 1 when fitting.
- static F32 sMemoryPressureMultiplier;
- // Last-ditch global discard floor. Mirrors sDesiredDiscardBias once the
- // multiplier is exhausted.
- static F32 sLastDitchMinDiscard;
-
- // 0..1 progress of the pressure multiplier from baseline (1) to its
- // configured cap (TextureMemoryPressureMaxMultiplier). Used to gate
- // bubble shrink and last-ditch engagement.
- static F32 getMemoryPressureProgress();
static U32 sBiasTexturesUpdated;
static S32 sMaxSculptRez ;
static U32 sMinLargeImageSize ;
static U32 sMaxSmallImageSize ;
+ static bool sFreezeImageUpdates;
static F32 sCurrentTime ;
// estimated free memory for textures, by bias calculation
static F32 sFreeVRAMMegabytes;
- static F32 sSysMemoryFactor;
- // Viewport pixel area, refreshed once per frame. Hoisted to keep the
- // per-texture hot path out of gViewerWindow.
- static F32 sWindowPixelArea;
-
enum EDebugTexels
{
DEBUG_TEXELS_OFF,
@@ -320,16 +279,6 @@ public:
LLViewerFetchedTexture(const LLImageRaw* raw, FTType f_type, bool usemipmaps);
LLViewerFetchedTexture(const std::string& url, FTType f_type, const LLUUID& id, bool usemipmaps = true);
- // Avatar bake/skin textures - exempt from non-visibility-driven discard
- // (staleness, background, pressure) to avoid the universal-cloud bug.
- static bool isAgentAvatarBoost(S32 boost_level)
- {
- return boost_level == BOOST_AVATAR
- || boost_level == BOOST_AVATAR_BAKED
- || boost_level == BOOST_AVATAR_SELF
- || boost_level == BOOST_AVATAR_BAKED_SELF;
- }
-
public:
struct Compare
@@ -390,7 +339,7 @@ public:
void updateVirtualSize() ;
- S32 getDesiredDiscardLevel() const { return mDesiredDiscardLevel; }
+ S32 getDesiredDiscardLevel() { return mDesiredDiscardLevel; }
void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); }
void setBoostLevel(S32 level) override;
@@ -512,12 +461,6 @@ protected:
S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space
S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have
- // Fetch-side discard cap from the J2C codestream's DWT level count
- // (populated by the fetcher). Distinct from LLImageGL::mMaxDiscardLevel -
- // scaleDown can still trim the GL pyramid past this.
- static constexpr S8 sFallbackCodecMaxDiscardLevel = 5; // MIN_DECOMPOSITION_LEVELS
- S8 mCodecMaxDiscardLevel = sFallbackCodecMaxDiscardLevel;
-
bool mNeedsAux; // We need to decode the auxiliary channels
bool mHasAux; // We have aux channels
bool mDecodingAux; // Are we decoding high components
@@ -597,6 +540,7 @@ public:
S8 getType() const override;
// Process image stats to determine priority/quality requirements.
void processTextureStats() override;
+ bool isUpdateFrozen() ;
bool scaleDown() override;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 4d09eff74e..7dd32074cf 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -47,7 +47,6 @@
#include "message.h"
#include "lldrawpoolbump.h" // to init bumpmap images
-#include "llagentcamera.h"
#include "lltexturecache.h"
#include "lltexturefetch.h"
#include "llviewercontrol.h"
@@ -62,8 +61,6 @@
#include "lltracerecording.h"
#include "llviewerdisplay.h"
#include "llviewerwindow.h"
-#include "llsurface.h"
-#include "llvoavatarself.h"
#include "llprogressview.h"
////////////////////////////////////////////////////////////////////////////
@@ -71,7 +68,6 @@
void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
S32 LLViewerTextureList::sNumImages = 0;
-F32 LLViewerTextureList::sCurrentBubbleMeters = 0.f;
LLViewerTextureList gTextureList;
@@ -97,20 +93,6 @@ LLTextureKey::LLTextureKey(LLUUID id, ETexListType tex_type)
///////////////////////////////////////////////////////////////////////////////
-// eTexIndex -> TextureChannel* index (0=Normal, 1=BaseColor, 2=Specular,
-// 3=Emissive). Single source of truth - route all channel-priority lookups
-// through this table.
-const S32 LLViewerTextureList::sChannelToPriority[LLRender::NUM_TEXTURE_CHANNELS] =
-{
- 1, // DIFFUSE_MAP (0) -> Y (diffuse)
- 0, // NORMAL_MAP / ALT_DIFFUSE (1) -> X (normals)
- 2, // SPECULAR_MAP (2) -> Z (specular/metallic)
- 1, // BASECOLOR_MAP (3) -> Y (diffuse)
- 2, // METALLIC_ROUGHNESS_MAP (4) -> Z (specular/metallic)
- 0, // GLTF_NORMAL_MAP (5) -> X (normals)
- 3, // EMISSIVE_MAP (6) -> W (emissive)
-};
-
LLViewerTextureList::LLViewerTextureList()
: mForceResetTextureStats(false),
mInitialized(false)
@@ -917,7 +899,8 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
{
llassert(!gCubeSnapshot);
- constexpr F32 BIAS_TRS_ON_SCREEN = 1.f; // perf gate for face-loop early exit
+ constexpr F32 BIAS_TRS_OUT_OF_SCREEN = 1.5f;
+ constexpr F32 BIAS_TRS_ON_SCREEN = 1.f;
if (imagep->getBoostLevel() < LLViewerFetchedTexture::BOOST_HIGH) // don't bother checking face list for boosted textures
{
@@ -927,67 +910,9 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
F32 max_vsize = 0.f;
bool on_screen = false;
- // Accumulators for the per-texture signals published below.
- // Defaults map to "deepest discard wanted" until evidence updates them.
- F32 min_distance_factor = 1.f;
- F32 max_on_screen_size = 0.f;
- bool on_agent_avatar = false;
- F32 draw_distance = llmax(gAgentCamera.mDrawDistance, 0.001f);
-
- // Close-camera bubble: faces inside `bubble` meters resolve to
- // dist_factor = 0, so the distance ramp spans (bubble, draw_distance].
- static LLCachedControl<F32> close_bubble(gSavedSettings, "TextureCloseBubbleMeters", 5.f);
- static LLCachedControl<F32> close_bubble_min(gSavedSettings, "TextureCloseBubbleMinMeters", 0.1f);
- static LLCachedControl<F32> bubble_shrink_threshold(gSavedSettings, "TextureCloseBubbleShrinkThreshold", 0.8f);
- static LLCachedControl<F32> bubble_track_rate(gSavedSettings, "TextureCloseBubbleTrackRate", 0.5f);
- F32 bubble_full = llmax((F32)close_bubble, 0.f);
- F32 bubble_min = llclamp((F32)close_bubble_min, 0.f, bubble_full);
- // Advance the slow-track once per frame, not per texture: this
- // function runs once per texture so a naive per-call lerp converges
- // in a single frame.
- static F32 s_tracked_bubble = -1.f;
- static U32 s_tracked_bubble_frame = 0;
- if (s_tracked_bubble < 0.f) s_tracked_bubble = bubble_full;
- if (s_tracked_bubble_frame != LLFrameTimer::getFrameCount())
- {
- s_tracked_bubble_frame = LLFrameTimer::getFrameCount();
- F32 progress = LLViewerTexture::getMemoryPressureProgress();
- F32 shrink_thresh = llclampf((F32)bubble_shrink_threshold);
- F32 shrink_frac = (progress > shrink_thresh)
- ? (progress - shrink_thresh) / llmax(1.f - shrink_thresh, 0.0001f)
- : 0.f;
- F32 target_bubble = bubble_full - (bubble_full - bubble_min) * shrink_frac;
- F32 dt = (F32)gFrameIntervalSeconds;
- F32 alpha = 1.f - expf(-llmax(dt, 0.f) * llmax((F32)bubble_track_rate, 0.f));
- s_tracked_bubble += (target_bubble - s_tracked_bubble) * alpha;
- s_tracked_bubble = llclamp(s_tracked_bubble, bubble_min, bubble_full);
- sCurrentBubbleMeters = s_tracked_bubble;
- }
- F32 bubble = llclamp(s_tracked_bubble, 0.f, draw_distance - 0.001f);
- F32 ramp_range = llmax(draw_distance - bubble, 0.001f);
-
U32 face_count = 0;
U32 max_faces_to_check = 1024;
- // Pick the least-aggressive channel across all uses, so a texture
- // used as both diffuse and normal isn't penalized by its harshest
- // role. -1 sentinel keeps emissive-only textures (W=3) from being
- // clobbered by a smaller init value.
- S32 priority_channel = -1;
- for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
- {
- if (imagep->getNumFaces(i) > 0)
- {
- S32 mapped = sChannelToPriority[i];
- priority_channel = (priority_channel < 0) ? mapped : llmin(priority_channel, mapped);
- }
- }
- if (priority_channel < 0)
- {
- priority_channel = 1; // no faces - default to diffuse
- }
- imagep->mPriorityChannel = (S8)priority_channel;
-
// get adjusted bias based on image resolution
LLImageGL* img = imagep->getGLTexture();
F32 max_discard = F32(img ? img->getMaxDiscardLevel() : MAX_DISCARD_LEVEL);
@@ -1023,15 +948,6 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
on_screen |= face->mInFrustum;
- F32 dist_above_bubble = llmax(face->mDistanceToCamera - bubble, 0.f);
- F32 dist_factor = llclampf(dist_above_bubble / ramp_range);
- min_distance_factor = llmin(min_distance_factor, dist_factor);
-
- if (face->mAvatar && face->mAvatar == gAgentAvatarp)
- {
- on_agent_avatar = true;
- }
-
// Scale desired texture resolution higher or lower depending on texture scale
//
// Minimum usage examples: a 1024x1024 texture with aplhabet (texture atlas),
@@ -1047,10 +963,6 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
min_scale = llclamp(min_scale * min_scale, texture_scale_min(), texture_scale_max());
vsize /= min_scale;
- // Raw screen-space coverage - taken before the bias /
- // camera-boost mutations below so the size signal is clean.
- max_on_screen_size = llmax(max_on_screen_size, vsize);
-
// apply bias to offscreen faces all the time, but only to onscreen faces when bias is large
// use mImportanceToCamera to make bias switch a bit more gradual
if (!face->mInFrustum || LLViewerTexture::sDesiredDiscardBias > 1.9f + face->mImportanceToCamera / 2.f)
@@ -1058,6 +970,13 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
vsize /= bias;
}
+ // boost resolution of textures that are important to the camera
+ if (face->mInFrustum)
+ {
+ static LLCachedControl<F32> texture_camera_boost(gSavedSettings, "TextureCameraBoost", 8.f);
+ vsize *= llmax(face->mImportanceToCamera*texture_camera_boost, 1.f);
+ }
+
max_vsize = llmax(max_vsize, vsize);
// addTextureStats limits size to sMaxVirtualSize
@@ -1076,95 +995,57 @@ void LLViewerTextureList::updateImageDecodePriority(LLViewerFetchedTexture* imag
}
}
- bool used_face_fast_path = (face_count > max_faces_to_check);
- if (used_face_fast_path)
+ if (face_count > max_faces_to_check)
{ // this texture is used in so many places we should just boost it and not bother checking its vsize
// this is especially important because the above is not time sliced and can hit multiple ms for a single texture
max_vsize = MAX_IMAGE_AREA;
}
- imagep->addTextureStats(max_vsize);
+ if (imagep->getType() == LLViewerTexture::LOD_TEXTURE && imagep->getBoostLevel() == LLViewerTexture::BOOST_NONE)
+ { // conditionally reset max virtual size for unboosted LOD_TEXTURES
+ // this is an alternative to decaying mMaxVirtualSize over time
+ // that keeps textures from continously downrezzing and uprezzing in the background
- // Publish per-texture signals for processTextureStats. Closest face
- // wins for distance (min); biggest face wins for size (max). Default
- // distance=1, size=0 maps to "deepest discard wanted" - never-
- // measured textures stay coarse until distance/size evidence arrives.
- if (used_face_fast_path)
- {
- // Fast path saw only a prefix of faces - force best-quality
- // sentinels to match the MAX_IMAGE_AREA vsize boost above.
- imagep->mMinDistanceFactor = 0.f;
- imagep->mMaxOnScreenSize = (F32)MAX_IMAGE_AREA;
- }
- else if (face_count == 0 && imagep->getBoostLevel() == LLGLTexture::BOOST_TERRAIN)
- {
- // Terrain detail textures don't register faces with the texture
- // (LLVOSurfacePatch addFace(NULL)). Drive distance from the LOD
- // system; floor at a small nonzero value so pressure has
- // something to bite into (pow(0, p) = 0).
- static LLCachedControl<F32> terrain_distance_floor(gSavedSettings, "TextureTerrainDistanceFloor", 0.01f);
- static LLCachedControl<F32> terrain_coverage(gSavedSettings, "TextureTerrainCoverageFraction", 0.99f);
- F32 nearest = LLSurface::sNearestVisiblePatchDistance;
- F32 nearest_above_bubble = (nearest < FLT_MAX) ? llmax(nearest - bubble, 0.f) : ramp_range;
- F32 dist = llclampf(nearest_above_bubble / ramp_range);
- imagep->mMinDistanceFactor = llmax(dist, llclampf((F32)terrain_distance_floor));
- imagep->mMaxOnScreenSize = LLViewerTexture::sWindowPixelArea * llclampf((F32)terrain_coverage);
- }
- else
- {
- imagep->mMinDistanceFactor = min_distance_factor;
- imagep->mMaxOnScreenSize = max_on_screen_size;
+ if (LLViewerTexture::sDesiredDiscardBias > BIAS_TRS_OUT_OF_SCREEN ||
+ (!on_screen && LLViewerTexture::sDesiredDiscardBias > BIAS_TRS_ON_SCREEN))
+ {
+ imagep->mMaxVirtualSize = 0.f;
+ }
}
- imagep->mOnAgentAvatar = on_agent_avatar;
- // Bind-staleness. Avatar bakes exempt (cloud-bug protection).
- // Per-interval increment is 1/max_discard so saturation time is
- // interval * max_discard seconds regardless of texture size.
- // Never-bound textures defer to distance/size or initial fetch
- // could never start.
- if (LLViewerFetchedTexture::isAgentAvatarBoost(imagep->getBoostLevel()))
- {
- imagep->mStalenessFactor = 0.f;
- }
- else if (LLImageGL* gli = imagep->getGLTexture())
- {
- static LLCachedControl<F32> bind_decay_seconds(gSavedSettings, "TextureBindDecaySeconds", 5.f);
- static LLCachedControl<F32> staleness_interval(gSavedSettings, "TextureStalenessIntervalSeconds", 5.f);
- F32 grace = llmax((F32)bind_decay_seconds, 0.f);
- F32 interval = llmax((F32)staleness_interval, 0.0001f);
+ imagep->addTextureStats(max_vsize);
- // Clock starts at whichever is later: the last real bind or
- // the GL-create time. The latter is the fallback for textures
- // decoded into GL but never actually rendered - without it,
- // mLastBindTime stays 0 forever and staleness can't evict.
- F32 clock_time = llmax(gli->mLastBindTime, gli->mGLCreateTime);
- bool has_clock = (clock_time > 0.f);
- F32 time_since = has_clock ? (LLImageGL::sLastFrameTime - clock_time) : 0.f;
+ // Derive stream priority channel from face lists.
+ // Map render texture channels to priority channels:
+ // 0 = normal, 1 = diffuse, 2 = specular, 3 = emissive
+ {
+ static const S32 render_to_priority[] = {
+ 1, // DIFFUSE_MAP (0)
+ 0, // NORMAL_MAP / ALTERNATE_DIFFUSE_MAP (1)
+ 2, // SPECULAR_MAP (2)
+ 1, // BASECOLOR_MAP (3)
+ 2, // METALLIC_ROUGHNESS_MAP (4)
+ 0, // GLTF_NORMAL_MAP (5)
+ 3, // EMISSIVE_MAP (6)
+ };
- if (!has_clock || time_since <= grace)
- {
- imagep->mStalenessFactor = 0.f;
- }
- else
+ S32 priority_channel = 1; // default to diffuse
+ for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
{
- S32 full_w = imagep->getFullWidth();
- S32 full_h = imagep->getFullHeight();
- S32 max_discard = (full_w > 0 && full_h > 0)
- ? LLImageGL::dimDerivedMaxDiscard(full_w, full_h)
- : (S32)gli->getMaxDiscardLevel();
- if (max_discard > 0)
+ if (imagep->getNumFaces(i) > 0)
{
- F32 steps = (time_since - grace) / interval;
- F32 step_size = 1.f / (F32)max_discard;
- imagep->mStalenessFactor = llclampf(steps * step_size);
- }
- else
- {
- imagep->mStalenessFactor = 0.f;
+ priority_channel = llmin(priority_channel, render_to_priority[i]);
}
}
- }
+ static LLCachedControl<LLVector4> channel_priority(gSavedSettings, "TextureChannelPriority",
+ LLVector4(10.0f, 20.0f, 40.0f, 20.0f));
+ F32 factor = llmax(channel_priority().mV[priority_channel], 0.1f);
+ if (factor != 1.0f)
+ {
+ imagep->mMaxVirtualSize /= factor;
+ }
+ }
}
#if 0
@@ -1273,7 +1154,8 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
imagep->postCreateTexture();
imagep->mCreatePending = false;
- if (imagep->hasGLTexture() && imagep->getDiscardLevel() < imagep->getDesiredDiscardLevel())
+ if (imagep->hasGLTexture() && imagep->getDiscardLevel() < imagep->getDesiredDiscardLevel() &&
+ (imagep->getDesiredDiscardLevel() <= MAX_DISCARD_LEVEL))
{
// NOTE: this may happen if the desired discard reduces while a decode is in progress and does not
// necessarily indicate a problem, but if log occurrences excede that of dsiplay_stats: FPS,
@@ -1298,16 +1180,13 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time)
gCopyProgram.bind();
gPipeline.mScreenTriangleVB->setBuffer();
- // give time to downscaling first - if mDownScaleQueue is not empty, we're running out of memory and need
+ // give time to downscaling first -- if mDownScaleQueue is not empty, we're running out of memory and need
// to free up memory by discarding off screen textures quickly
- // Drain rate scales with both pending creates and the downscale
- // queue itself. Without the queue term, a backlog of evictions
- // could only drain 5/frame regardless of size, and the system
- // can't actually free VRAM fast enough under pressure.
- S32 min_count = (S32)mCreateTextureList.size() / 20
- + (S32)mDownScaleQueue.size() / 5
- + 5;
+ // do at least 5 and make sure we don't get too far behind even if it violates
+ // the time limit. If we don't downscale quickly the viewer will hit swap and may
+ // freeze.
+ S32 min_count = (S32)mCreateTextureList.size() / 20 + 5;
create_timer.reset();
while (!mDownScaleQueue.empty())
@@ -1409,15 +1288,12 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
//update MIN_UPDATE_COUNT or 5% of other textures, whichever is greater
update_count = llmax((U32) MIN_UPDATE_COUNT, (U32) mUUIDMap.size()/20);
- // Scale up the per-frame update window under VRAM pressure so eviction
- // candidates get re-evaluated quickly. Both the legacy bias and the
- // new pressure multiplier widen the window.
- F32 pressure_scale = llmax(LLViewerTexture::sDesiredDiscardBias,
- LLViewerTexture::sMemoryPressureMultiplier);
- if (pressure_scale > 1.f
+ if (LLViewerTexture::sDesiredDiscardBias > 1.f
&& LLViewerTexture::sBiasTexturesUpdated < (U32)mUUIDMap.size())
{
- update_count = (S32)(update_count * pressure_scale);
+ // We are over memory target. Bias affects discard rates, so update
+ // existing textures agresively to free memory faster.
+ update_count = (S32)(update_count * LLViewerTexture::sDesiredDiscardBias);
// This isn't particularly precise and can overshoot, but it doesn't need
// to be, just making sure it did a full circle and doesn't get stuck updating
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index dbed8b5c2f..7c7112f4cf 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -30,7 +30,6 @@
#include "lluuid.h"
//#include "message.h"
#include "llgl.h"
-#include "llrender.h"
#include "llviewertexture.h"
#include "llui.h"
#include <list>
@@ -93,10 +92,6 @@ class LLViewerTextureList
friend class LLLocalBitmap;
public:
- // eTexIndex -> TextureChannel* index (0=Normal, 1=BaseColor,
- // 2=Specular, 3=Emissive). Single source of truth.
- static const S32 sChannelToPriority[LLRender::NUM_TEXTURE_CHANNELS];
-
static bool createUploadFile(LLPointer<LLImageRaw> raw_image,
const std::string& out_filename,
const S32 max_image_dimentions = LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT,
@@ -244,10 +239,6 @@ private:
bool mInitialized ;
LLFrameTimer mForceDecodeTimer;
-public:
- // Current close-camera bubble in meters (frame-coherent, slow-tracked).
- static F32 sCurrentBubbleMeters;
-
private:
static S32 sNumImages;
static void (*sUUIDCallback)(void**, const LLUUID &);
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index eb0261b5e5..3441e25c6a 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -173,10 +173,7 @@ LLPointer<LLViewerFetchedTexture> fetch_terrain_texture(const LLUUID& id)
return nullptr;
}
- // LOD_TEXTURE so streaming math runs (the base-class processTextureStats
- // pins mDesiredDiscardLevel at 0).
- LLPointer<LLViewerFetchedTexture> tex = LLViewerTextureManager::getFetchedTexture(
- id, FTT_DEFAULT, true, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+ LLPointer<LLViewerFetchedTexture> tex = LLViewerTextureManager::getFetchedTexture(id);
return tex;
}
@@ -346,9 +343,18 @@ bool LLTerrainMaterials::makeTextureReady(LLPointer<LLViewerFetchedTexture>& tex
{
if (boost)
{
- // Quality is driven by the streaming math via synthetic signals
- // for BOOST_TERRAIN textures in updateImageDecodePriority.
boost_minimap_texture(tex, BASE_SIZE*BASE_SIZE);
+
+ S32 width = tex->getFullWidth();
+ S32 height = tex->getFullHeight();
+ S32 min_dim = llmin(width, height);
+ S32 ddiscard = 0;
+ while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
+ {
+ ddiscard++;
+ min_dim /= 2;
+ }
+ tex->setMinDiscardLevel(ddiscard);
}
return false;
}
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index 3043b17589..99dca7b395 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -127,35 +127,31 @@
top_delta="16"
left="30"
width="160"
- name="TextureQualityLabel"
+ name="MaxTextureResolutionLabel"
text_readonly_color="LabelDisabledColor">
- Texture quality:
+ Maximum LOD resolution:
</text>
<combo_box
- control_name="RenderTextureQuality"
+ control_name="RenderMaxTextureResolution"
height="19"
layout="topleft"
left_pad="10"
top_delta="0"
- name="TextureQuality"
- tool_tip="Controls maximum texture resolution and how aggressively textures stream by channel. Higher quality keeps more detail in memory."
+ name="MaxTextureResolution"
+ tool_tip="Maximum resolution for 'level of detail' textures"
width="90">
<combo_box.item
- label="Low"
- name="Low"
- value="0"/>
- <combo_box.item
- label="Medium"
- name="Medium"
- value="1"/>
+ label="512"
+ name="512"
+ value="512"/>
<combo_box.item
- label="High"
- name="High"
- value="2"/>
+ label="1024"
+ name="1024"
+ value="1024"/>
<combo_box.item
- label="Ultra"
- name="Ultra"
- value="3"/>
+ label="2048"
+ name="2048"
+ value="2048"/>
</combo_box>
<check_box