summaryrefslogtreecommitdiff
path: root/indra/newview/llviewertexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewertexture.cpp')
-rw-r--r--indra/newview/llviewertexture.cpp190
1 files changed, 121 insertions, 69 deletions
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 36b6787ace..e40f109e55 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -87,6 +87,7 @@ S32 LLViewerTexture::sRawCount = 0;
S32 LLViewerTexture::sAuxCount = 0;
LLFrameTimer LLViewerTexture::sEvaluationTimer;
F32 LLViewerTexture::sDesiredDiscardBias = 0.f;
+U32 LLViewerTexture::sBiasTexturesUpdated = 0;
S32 LLViewerTexture::sMaxSculptRez = 128; //max sculpt image size
constexpr S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64;
@@ -107,12 +108,6 @@ LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTextur
const F64 log_2 = log(2.0);
-#if ADDRESS_SIZE == 32
-const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT / 2;
-#else
-const U32 DESIRED_NORMAL_TEXTURE_SIZE = (U32)LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT;
-#endif
-
//----------------------------------------------------------------------------------------------
//namespace: LLViewerTextureAccess
//----------------------------------------------------------------------------------------------
@@ -494,7 +489,12 @@ void LLViewerTexture::updateClass()
}
LLViewerMediaTexture::updateClass();
-
+ // This is a divisor used to determine how much VRAM from our overall VRAM budget to use.
+ // This is **cumulative** on whatever the detected or manually set VRAM budget is.
+ // If we detect 2048MB of VRAM, this will, by default, only use 1024.
+ // If you set 1024MB of VRAM, this will, by default, use 512.
+ // -Geenz 2025-03-03
+ static LLCachedControl<U32> tex_vram_divisor(gSavedSettings, "RenderTextureVRAMDivisor", 2);
static LLCachedControl<U32> max_vram_budget(gSavedSettings, "RenderMaxVRAMBudget", 0);
F64 texture_bytes_alloc = LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0;
@@ -504,7 +504,11 @@ void LLViewerTexture::updateClass()
// 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 budget = max_vram_budget == 0 ? (F32)gGLManager.mVRAM : (F32)max_vram_budget;
+ // 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;
// Try to leave at least half a GB for everyone else and for bias,
// but keep at least 768MB for ourselves
@@ -520,12 +524,19 @@ void LLViewerTexture::updateClass()
bool is_low = is_sys_low || over_pct > 0.f;
static bool was_low = false;
- static bool was_sys_low = false;
if (is_low && !was_low)
{
- // slam to 1.5 bias the moment we hit low memory (discards off screen textures immediately)
- sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f);
+ if (is_sys_low)
+ {
+ // Not having system memory is more serious, so discard harder
+ sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f * getSystemMemoryBudgetFactor());
+ }
+ else
+ {
+ // Slam to 1.5 bias the moment we hit low memory (discards off screen textures immediately)
+ sDesiredDiscardBias = llmax(sDesiredDiscardBias, 1.5f);
+ }
if (is_sys_low || over_pct > 2.f)
{ // if we're low on system memory, emergency purge off screen textures to avoid a death spiral
@@ -538,7 +549,6 @@ void LLViewerTexture::updateClass()
}
was_low = is_low;
- was_sys_low = is_sys_low;
if (is_low)
{
@@ -556,18 +566,25 @@ void LLViewerTexture::updateClass()
// don't execute above until the slam to 1.5 has a chance to take effect
sEvaluationTimer.reset();
- // lower discard bias over time when free memory is available
- if (sDesiredDiscardBias > 1.f && over_pct < 0.f)
+ // 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);
+ if (sDesiredDiscardBias > 1.f
+ && over_pct < FREE_PERCENTAGE_TRESHOLD
+ && getFreeSystemMemory() > MIN_FREE_MAIN_MEMORY)
{
static LLCachedControl<F32> high_mem_discard_decrement(gSavedSettings, "RenderHighMemMinDiscardDecrement", .1f);
- F32 decrement = high_mem_discard_decrement - llmin(over_pct, 0.f);
+ F32 decrement = high_mem_discard_decrement - llmin(over_pct - FREE_PERCENTAGE_TRESHOLD, 0.f);
sDesiredDiscardBias -= decrement * gFrameIntervalSeconds;
}
}
// set to max discard bias if the window has been backgrounded for a while
static F32 last_desired_discard_bias = 1.f;
+ static F32 last_texture_update_count_bias = 1.f;
static bool was_backgrounded = false;
static LLFrameTimer backgrounded_timer;
static LLCachedControl<F32> minimized_discard_time(gSavedSettings, "TextureDiscardMinimizedTime", 1.f);
@@ -603,29 +620,74 @@ void LLViewerTexture::updateClass()
}
sDesiredDiscardBias = llclamp(sDesiredDiscardBias, 1.f, 4.f);
+ if (last_texture_update_count_bias < sDesiredDiscardBias)
+ {
+ // bias increased, reset texture update counter to
+ // let updates happen at an increased rate.
+ last_texture_update_count_bias = sDesiredDiscardBias;
+ sBiasTexturesUpdated = 0;
+ }
+ else if (last_texture_update_count_bias > sDesiredDiscardBias + 0.1f)
+ {
+ // bias decreased, 0.1f is there to filter out small fluctuations
+ // and not reset sBiasTexturesUpdated too often.
+ // Bias jumps to 1.5 at low memory, so getting stuck at 1.1 is not
+ // a problem.
+ last_texture_update_count_bias = sDesiredDiscardBias;
+ }
LLViewerTexture::sFreezeImageUpdates = false;
}
//static
-bool LLViewerTexture::isSystemMemoryLow()
+U32Megabytes LLViewerTexture::getFreeSystemMemory()
{
static LLFrameTimer timer;
static U32Megabytes physical_res = U32Megabytes(U32_MAX);
- static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
- const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
-
if (timer.getElapsedTimeF32() < MEMORY_CHECK_WAIT_TIME) //call this once per second.
{
- return physical_res < MIN_FREE_MAIN_MEMORY;
+ return physical_res;
}
timer.reset();
LLMemory::updateMemoryInfo();
physical_res = LLMemory::getAvailableMemKB();
- return physical_res < MIN_FREE_MAIN_MEMORY;
+ 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()
+{
+ return getFreeSystemMemory() < get_render_free_main_memory_treshold();
+}
+
+//static
+bool LLViewerTexture::isSystemMemoryCritical()
+{
+ return getFreeSystemMemory() < get_render_free_main_memory_treshold() / 2;
+}
+
+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;
}
//end of static functions
@@ -1086,6 +1148,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
mOrigHeight = 0;
mHasAux = false;
mNeedsAux = false;
+ mLastWorkerDiscardLevel = -1;
mRequestedDiscardLevel = -1;
mRequestedDownloadPriority = 0.f;
mFullyLoaded = false;
@@ -1238,12 +1301,11 @@ void LLViewerFetchedTexture::loadFromFastCache()
if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
{
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height))
+ if (mRawImage && (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS))
{
- // scale oversized icon, no need to give more work to gl
- mRawImage->scale(expected_width, expected_height);
+ // Scale oversized thumbnail
+ // thumbnails aren't supposed to go over DEFAULT_THUMBNAIL_DIMENSIONS
+ mRawImage->scale(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS);
}
}
@@ -1685,6 +1747,16 @@ void LLViewerFetchedTexture::processTextureStats()
static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
+ U32 max_tex_res = MAX_IMAGE_SIZE_DEFAULT;
+ if (mBoostLevel < LLGLTexture::BOOST_HIGH)
+ {
+ // restrict texture resolution to download based on RenderMaxTextureResolution
+ static LLCachedControl<U32> max_texture_resolution(gSavedSettings, "RenderMaxTextureResolution", 2048);
+ // sanity clamp debug setting to avoid settings hack shenanigans
+ max_tex_res = (U32)llclamp((U32)max_texture_resolution, 512, MAX_IMAGE_SIZE_DEFAULT);
+ mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)(max_tex_res * max_tex_res));
+ }
+
if (textures_fullres)
{
mDesiredDiscardLevel = 0;
@@ -1706,10 +1778,9 @@ void LLViewerFetchedTexture::processTextureStats()
}
else
{
- U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096
if(!mKnownDrawWidth || !mKnownDrawHeight || (S32)mFullWidth <= mKnownDrawWidth || (S32)mFullHeight <= mKnownDrawHeight)
{
- if (mFullWidth > desired_size || mFullHeight > desired_size)
+ if (mFullWidth > max_tex_res || mFullHeight > max_tex_res)
{
mDesiredDiscardLevel = 1;
}
@@ -1927,9 +1998,9 @@ bool LLViewerFetchedTexture::processFetchResults(S32& desired_discard, S32 curre
bool LLViewerFetchedTexture::updateFetch()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false);
+ static LLCachedControl<bool> textures_decode_disabled(gSavedSettings, "TextureDecodeDisabled", false);
- if(textures_decode_disabled) // don't fetch the surface textures in wireframe mode
+ if (textures_decode_disabled) // don't fetch the surface textures in wireframe mode
{
return false;
}
@@ -1964,7 +2035,7 @@ bool LLViewerFetchedTexture::updateFetch()
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - callback pending");
return false; // process any raw image data in callbacks before replacing
}
- if(mInFastCacheList)
+ if (mInFastCacheList)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - in fast cache");
return false;
@@ -1989,7 +2060,7 @@ bool LLViewerFetchedTexture::updateFetch()
if (mAuxRawImage.notNull()) sAuxCount--;
// keep in mind that fetcher still might need raw image, don't modify original
bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mFetchState, mRawImage, mAuxRawImage,
- mLastHttpGetStatus);
+ mLastHttpGetStatus);
if (mRawImage.notNull()) sRawCount++;
if (mAuxRawImage.notNull())
{
@@ -2005,7 +2076,7 @@ bool LLViewerFetchedTexture::updateFetch()
else
{
mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
- mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
+ mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
}
if (!processFetchResults(desired_discard, current_discard, fetch_discard, decode_priority))
@@ -2016,7 +2087,7 @@ bool LLViewerFetchedTexture::updateFetch()
if (mIsFetching)
{
static const F32 MAX_HOLD_TIME = 5.0f; //seconds to wait before canceling fecthing if decode_priority is 0.f.
- if(decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME)
+ if (decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME)
{
mStopFetchingTimer.reset();
LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority);
@@ -2032,7 +2103,7 @@ bool LLViewerFetchedTexture::updateFetch()
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - priority <= 0");
make_request = false;
}
- else if(mDesiredDiscardLevel > getMaxDiscardLevel())
+ else if (mDesiredDiscardLevel > getMaxDiscardLevel())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - desired > max");
make_request = false;
@@ -2073,7 +2144,7 @@ bool LLViewerFetchedTexture::updateFetch()
if (make_request)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - make request");
- S32 w=0, h=0, c=0;
+ S32 w = 0, h = 0, c = 0;
if (getDiscardLevel() >= 0)
{
w = mGLTexturep->getWidth(0);
@@ -2091,18 +2162,19 @@ bool LLViewerFetchedTexture::updateFetch()
S32 fetch_request_response = -1;
S32 worker_discard = -1;
fetch_request_response = LLAppViewer::getTextureFetch()->createRequest(mFTType, mUrl, getID(), getTargetHost(), decode_priority,
- w, h, c, desired_discard, needsAux(), mCanUseHTTP);
+ w, h, c, desired_discard, needsAux(), mCanUseHTTP);
if (fetch_request_response >= 0) // positive values and 0 are discard values
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created");
mHasFetcher = true;
mIsFetching = true;
+ mLastWorkerDiscardLevel = worker_discard;
// in some cases createRequest can modify discard, as an example
// bake textures are always at discard 0
mRequestedDiscardLevel = llmin(desired_discard, fetch_request_response);
mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
- mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
+ mFetchPriority, mFetchDeltaTime, mRequestDeltaTime, mCanUseHTTP);
}
else if (fetch_request_response == LLTextureFetch::CREATE_REQUEST_ERROR_TRANSITION)
{
@@ -2116,7 +2188,7 @@ bool LLViewerFetchedTexture::updateFetch()
S32 decoded_discard;
bool decoded;
S32 fetch_state = LLAppViewer::getTextureFetch()->getLastFetchState(mID, desired_discard, decoded_discard, decoded);
- if (fetch_state > 1 && decoded && decoded_discard >=0 && decoded_discard <= desired_discard)
+ if (fetch_state > 1 && decoded && decoded_discard >= 0 && decoded_discard <= desired_discard)
{
// worker actually has the image
if (mRawImage.notNull()) sRawCount--;
@@ -2740,11 +2812,9 @@ void LLViewerFetchedTexture::saveRawImage()
}
else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL)
{
- S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_THUMBNAIL_DIMENSIONS;
- S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_THUMBNAIL_DIMENSIONS;
- if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)
+ if (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS)
{
- mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents());
+ mSavedRawImage = new LLImageRaw(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS, mRawImage->getComponents());
mSavedRawImage->copyScaled(mRawImage);
}
else
@@ -2913,8 +2983,6 @@ LLViewerLODTexture::LLViewerLODTexture(const std::string& url, FTType f_type, co
void LLViewerLODTexture::init(bool firstinit)
{
mTexelsPerImage = 64*64;
- mDiscardVirtualSize = 0.f;
- mCalculatedDiscardLevel = -1.f;
}
//virtual
@@ -2939,12 +3007,14 @@ void LLViewerLODTexture::processTextureStats()
static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false);
- { // restrict texture resolution to download based on RenderMaxTextureResolution
+ F32 max_tex_res = MAX_IMAGE_SIZE_DEFAULT;
+ if (mBoostLevel < LLGLTexture::BOOST_HIGH)
+ {
+ // restrict texture resolution to download based on RenderMaxTextureResolution
static LLCachedControl<U32> max_texture_resolution(gSavedSettings, "RenderMaxTextureResolution", 2048);
// sanity clamp debug setting to avoid settings hack shenanigans
- F32 tex_res = (F32)llclamp((S32)max_texture_resolution, 512, 2048);
- tex_res *= tex_res;
- mMaxVirtualSize = llmin(mMaxVirtualSize, tex_res);
+ max_tex_res = (F32)llclamp((S32)max_texture_resolution, 128, MAX_IMAGE_SIZE_DEFAULT);
+ mMaxVirtualSize = llmin(mMaxVirtualSize, max_tex_res * max_tex_res);
}
if (textures_fullres)
@@ -2993,19 +3063,12 @@ void LLViewerLODTexture::processTextureStats()
{
// Calculate the required scale factor of the image using pixels per texel
discard_level = (F32)(log(mTexelsPerImage / mMaxVirtualSize) / log_4);
- mDiscardVirtualSize = mMaxVirtualSize;
- mCalculatedDiscardLevel = discard_level;
}
discard_level = floorf(discard_level);
F32 min_discard = 0.f;
- U32 desired_size = MAX_IMAGE_SIZE_DEFAULT; // MAX_IMAGE_SIZE_DEFAULT = 2048 and max size ever is 4096
- if (mBoostLevel <= LLGLTexture::BOOST_SCULPTED)
- {
- desired_size = DESIRED_NORMAL_TEXTURE_SIZE;
- }
- if (mFullWidth > desired_size || mFullHeight > desired_size)
+ if (mFullWidth > max_tex_res || mFullHeight > max_tex_res)
min_discard = 1.f;
discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL);
@@ -3543,18 +3606,7 @@ void LLViewerMediaTexture::setPlaying(bool playing)
for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter)
{
LLFace* facep = *iter;
- const LLTextureEntry* te = facep->getTextureEntry();
- if (te->getGLTFMaterial())
- {
- // PBR material, switch emissive and basecolor
- switchTexture(LLRender::EMISSIVE_MAP, *iter);
- switchTexture(LLRender::BASECOLOR_MAP, *iter);
- }
- else
- {
- // blinn-phong material, switch diffuse map only
- switchTexture(LLRender::DIFFUSE_MAP, *iter);
- }
+ switchTexture(LLRender::DIFFUSE_MAP, facep);
}
}
else //stop playing this media