summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2026-06-13 17:48:29 +0800
committerErik Kundiman <erik@megapahit.org>2026-06-13 17:48:29 +0800
commitb370bd8fdb441f3eb86c4c103112ed0874e29e99 (patch)
treeab4584ffd980cc49019db02b021a68a9c2a2fd68 /indra/newview
parentc4824e2afbf372b3c6d061db069b109199720a79 (diff)
parent1d456767fe47773d9dadcaa456b0af31dc6060e5 (diff)
Merge remote-tracking branch 'secondlife/release/26.3' into 26.3
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/lldebugview.cpp2
-rw-r--r--indra/newview/lltextureview.cpp2
-rw-r--r--indra/newview/llviewermessage.cpp5
-rw-r--r--indra/newview/llviewertexture.cpp115
-rw-r--r--indra/newview/llviewertexture.h3
-rw-r--r--indra/newview/llvocache.cpp2
6 files changed, 91 insertions, 38 deletions
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index 3941b82e75..246a9d28e4 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -101,7 +101,7 @@ void LLDebugView::init()
addChild(gSceneMonitorView);
gSceneMonitorView->setRect(rect);
- r.set(150, rect.getHeight() - 60, 820, 110);
+ r.set(150, rect.getHeight() - 60, 835, 110);
LLTextureView::Params tvp;
tvp.name("gTextureView");
tvp.rect(r);
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index 4534db958f..470a133fa7 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -250,7 +250,7 @@ void LLTextureBar::draw()
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// Draw the progress bar.
- S32 bar_width = 100;
+ S32 bar_width = 110;
S32 bar_left = 260;
left = bar_left;
right = left + bar_width;
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index cf1ce421b3..d63e0dc836 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3392,9 +3392,10 @@ void send_agent_update(bool force_send, bool send_reliable)
static F32 last_draw_disatance_step = 1024;
F32 memory_limited_draw_distance = gAgentCamera.mDrawDistance;
- if (LLViewerTexture::isSystemMemoryCritical())
+ if (LLViewerTexture::getSystemMemoryBudgetFactor() > 1.f)
{
- // If we are low on memory, reduce requested draw distance
+ // We are critcally low on memory or recovering,
+ // limit requested draw distance
memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / LLViewerTexture::getSystemMemoryBudgetFactor(), gAgentCamera.mDrawDistance / 2.f);
}
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 0dfc40b85f..c351d4da95 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -114,6 +114,7 @@ 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;
@@ -490,6 +491,13 @@ 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()
{
@@ -523,23 +531,24 @@ 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 used = (F32)ll_round(texture_bytes_alloc + vertex_bytes_alloc);
+ F32 vram_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 budget = max_vram_budget == 0 ? llmax(1024, (F32)gGLManager.mVRAM / tex_vram_divisor) : (F32)max_vram_budget;
+ F32 vram_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 target = llmax(llmin(budget - 512.f, budget * 0.8f), MIN_VRAM_BUDGET);
- sFreeVRAMMegabytes = target - used;
+ 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 over_pct = (used - target) / target;
+ 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 +
@@ -550,7 +559,7 @@ void LLViewerTexture::updateClass()
static LLCachedControl<F32> prediction_gain(gSavedSettings, "TextureMemoryPressurePredictionGain", 10.f);
static LLCachedControl<F32> smoothing_rate(gSavedSettings, "TextureMemoryPressureSmoothingRate", 4.f);
- F32 backoff_target = target * llclamp((F32)backoff_start, 0.05f, 1.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;
@@ -560,7 +569,7 @@ void LLViewerTexture::updateClass()
// frame later, from `used` alone.
bool need_predict = sMemoryPressureMultiplier > 1.001f
|| sLastDitchMinDiscard > 0.f
- || used > backoff_target * 0.5f;
+ || vram_used > backoff_target * 0.5f;
S64 pending_bytes_increase = 0;
S64 pending_bytes_decrease = 0;
@@ -597,7 +606,7 @@ void LLViewerTexture::updateClass()
// 1024 * 512 = 524288: matches the unit reduction at line 513.
constexpr F32 BYTES_TO_USED_UNITS = 1.f / 524288.f;
- F32 predicted_used = used
+ 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);
@@ -607,7 +616,7 @@ void LLViewerTexture::updateClass()
// 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 = used >= budget * llclamp((F32)high_water, 0.5f, 1.f);
+ 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)
@@ -649,14 +658,14 @@ void LLViewerTexture::updateClass()
if (s_pressure_log_timer.getElapsedTimeF32() > 1.f)
{
s_pressure_log_timer.reset();
- F32 over = used / llmax(backoff_target, 1.f);
+ F32 over = vram_used / llmax(backoff_target, 1.f);
LL_INFOS("TextureStream") << "pressure"
<< " mult=" << sMemoryPressureMultiplier
<< " target_mult=" << target_mult
<< " progress=" << progress
- << " used=" << used
+ << " used=" << vram_used
<< " predicted=" << predicted_used
- << " target=" << target
+ << " target=" << vram_target
<< " over=" << over
<< " pred_over=" << predicted_over
<< " in+=" << (S32)(pending_bytes_increase / 1024 / 1024)
@@ -669,10 +678,66 @@ void LLViewerTexture::updateClass()
}
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.05;
+ 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.02;
+ 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)
@@ -720,12 +785,11 @@ void LLViewerTexture::updateClass()
// 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_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);
+ 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));
if (sDesiredDiscardBias > 1.f
&& over_pct < FREE_PERCENTAGE_TRESHOLD
- && getFreeSystemMemory() > MIN_FREE_MAIN_MEMORY
+ && free_sys_mem > MIN_FREE_MAIN_MEMORY
&& !eviction_in_flight)
{
static LLCachedControl<F32> high_mem_discard_decrement(gSavedSettings, "RenderHighMemMinDiscardDecrement", .1f);
@@ -835,13 +899,6 @@ 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()
{
@@ -854,18 +911,10 @@ bool LLViewerTexture::isSystemMemoryCritical()
return getFreeSystemMemory() < get_render_free_main_memory_treshold() / 2;
}
+// static
F32 LLViewerTexture::getSystemMemoryBudgetFactor()
{
- 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;
+ return sSysMemoryFactor;
}
//end of static functions
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 991bb638a1..8c5c48bafd 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -116,6 +116,8 @@ 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);
@@ -268,6 +270,7 @@ public:
// 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;
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 5d456b1a19..7618739b3c 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -488,7 +488,7 @@ void LLVOCacheEntry::updateDebugSettings()
static const F32 MIN_RADIUS = 1.0f;
F32 draw_radius = gAgentCamera.mDrawDistance;
- if (LLViewerTexture::isSystemMemoryCritical())
+ if (LLViewerTexture::getSystemMemoryBudgetFactor() > 1.f)
{
// Factor is intended to go from 1.0 to 2.0
// For safety cap reduction at 50%, we don't want to go below half of draw distance