From 8a585912adab1948e250c30d8ceb3588b9148600 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 26 Aug 2025 18:18:07 +0300 Subject: [PATCH 1/7] #4598 Crash in LLReflectionMapManager::update Not enough data for a solid conclusion (does something create settings in a thread?), but should be avoidable if we cache settings differently. --- indra/newview/llreflectionmapmanager.cpp | 41 +++++++++++++----------- indra/newview/llreflectionmapmanager.h | 8 +++++ indra/newview/llviewercontrol.cpp | 8 +++++ 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 3391b7adf7..f24bb892dc 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -145,6 +145,7 @@ static void touch_default_probe(LLReflectionMap* probe) LLReflectionMapManager::LLReflectionMapManager() { mDynamicProbeCount = LL_MAX_REFLECTION_PROBE_COUNT; + refreshSettings(); initCubeFree(); } @@ -222,25 +223,21 @@ void LLReflectionMapManager::update() resume(); } - static LLCachedControl sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1); - static LLCachedControl sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3); - static LLCachedControl sReflectionProbeCount(gSavedSettings, "RenderReflectionProbeCount", 256U); - static LLCachedControl sProbeDynamicAllocation(gSavedSettings, "RenderReflectionProbeDynamicAllocation", -1); mResetFade = llmin((F32)(mResetFade + gFrameIntervalSeconds * 2.f), 1.f); { U32 probe_count_temp = mDynamicProbeCount; - if (sProbeDynamicAllocation > -1) + if (mRenderReflectionProbeDynamicAllocation > -1) { - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { mDynamicProbeCount = 1; } - else if (sLevel == 1) + else if (mRenderReflectionProbeLevel == 1) { mDynamicProbeCount = (U32)mProbes.size(); } - else if (sLevel == 2) + else if (mRenderReflectionProbeLevel == 2) { mDynamicProbeCount = llmax((U32)mProbes.size(), 128); } @@ -249,20 +246,20 @@ void LLReflectionMapManager::update() mDynamicProbeCount = 256; } - if (sProbeDynamicAllocation > 1) + if (mRenderReflectionProbeDynamicAllocation > 1) { // Round mDynamicProbeCount to the nearest increment of 16 - mDynamicProbeCount = ((mDynamicProbeCount + sProbeDynamicAllocation / 2) / sProbeDynamicAllocation) * 16; - mDynamicProbeCount = llclamp(mDynamicProbeCount, 1, sReflectionProbeCount); + mDynamicProbeCount = ((mDynamicProbeCount + mRenderReflectionProbeDynamicAllocation / 2) / mRenderReflectionProbeDynamicAllocation) * 16; + mDynamicProbeCount = llclamp(mDynamicProbeCount, 1, mRenderReflectionProbeCount); } else { - mDynamicProbeCount = llclamp(mDynamicProbeCount + sProbeDynamicAllocation, 1, sReflectionProbeCount); + mDynamicProbeCount = llclamp(mDynamicProbeCount + mRenderReflectionProbeDynamicAllocation, 1, mRenderReflectionProbeCount); } } else { - mDynamicProbeCount = sReflectionProbeCount; + mDynamicProbeCount = mRenderReflectionProbeCount; } mDynamicProbeCount = llmin(mDynamicProbeCount, LL_MAX_REFLECTION_PROBE_COUNT); @@ -328,7 +325,7 @@ void LLReflectionMapManager::update() bool did_update = false; - bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; + bool realtime = mRenderReflectionProbeDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME; LLReflectionMap* closestDynamic = nullptr; @@ -457,7 +454,7 @@ void LLReflectionMapManager::update() closestDynamic = probe; } - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { // only update default probe when coverage is set to none llassert(probe == mDefaultProbe); @@ -489,12 +486,12 @@ void LLReflectionMapManager::update() static LLCachedControl sUpdatePeriod(gSavedSettings, "RenderDefaultProbeUpdatePeriod", 2.f); if ((gFrameTimeSeconds - mDefaultProbe->mLastUpdateTime) < sUpdatePeriod) { - if (sLevel == 0) + if (mRenderReflectionProbeLevel == 0) { // when probes are disabled don't update the default probe more often than the prescribed update period oldestProbe = nullptr; } } - else if (sLevel > 0) + else if (mRenderReflectionProbeLevel > 0) { // when probes are enabled don't update the default probe less often than the prescribed update period oldestProbe = mDefaultProbe; } @@ -520,6 +517,14 @@ void LLReflectionMapManager::update() } } +void LLReflectionMapManager::refreshSettings() +{ + mRenderReflectionProbeDetail = gSavedSettings.getS32("RenderReflectionProbeDetail"); + mRenderReflectionProbeLevel = gSavedSettings.getS32("RenderReflectionProbeLevel"); + mRenderReflectionProbeCount = gSavedSettings.getU32("RenderReflectionProbeCount"); + mRenderReflectionProbeDynamicAllocation = gSavedSettings.getS32("RenderReflectionProbeDynamicAllocation"); +} + LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) { if (gGLManager.mGLVersion < 4.05f || !LLPipeline::sReflectionProbesEnabled) @@ -782,7 +787,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face) } else { - llassert(gSavedSettings.getS32("RenderReflectionProbeLevel") > 0); // should never update a probe that's not the default probe if reflection coverage is none + llassert(mRenderReflectionProbeLevel > 0); // should never update a probe that's not the default probe if reflection coverage is none probe->update(mRenderTarget.getWidth(), face); } diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index 0719c28134..5daed7d1cf 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -110,6 +110,8 @@ public: // maintain reflection probes void update(); + void refreshSettings(); + // add a probe for the given spatial group LLReflectionMap* addProbe(LLSpatialGroup* group = nullptr); @@ -248,6 +250,12 @@ private: U32 mDynamicProbeCount; + // cached settings from gSavedSettings + S32 mRenderReflectionProbeDetail = -1; + S32 mRenderReflectionProbeLevel = 3; + U32 mRenderReflectionProbeCount = 256U; + S32 mRenderReflectionProbeDynamicAllocation = -1; + // resolution of reflection probes U32 mProbeResolution = 128; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 598ad89907..d39805f4c7 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -447,6 +447,7 @@ static bool handleRenderDynamicLODChanged(const LLSD& newvalue) static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) { + gPipeline.mReflectionMapManager.refreshSettings(); if (gPipeline.isInit()) { LLPipeline::refreshCachedSettings(); @@ -459,6 +460,12 @@ static bool handleReflectionProbeDetailChanged(const LLSD& newvalue) return true; } +static bool handleReflectionProbeCountChanged(const LLSD& newvalue) +{ + gPipeline.mReflectionMapManager.refreshSettings(); + return true; +} + #if LL_DARWIN static bool handleAppleUseMultGLChanged(const LLSD& newvalue) { @@ -836,6 +843,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeLevel", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); + setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeCount", handleReflectionProbeCountChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionProbeDetailChanged); #if LL_DARWIN setting_setup_signal_listener(gSavedSettings, "RenderAppleUseMultGL", handleAppleUseMultGLChanged); From bbdb46a833c1c3d8c26aa1a9a69bf05f4b065853 Mon Sep 17 00:00:00 2001 From: Dan Linden <119471733+Dan-Linden@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:41:07 -0700 Subject: [PATCH 2/7] Update qatest.yaml Removed dan's z600 windows machine from the matrix. Added dan's mac, caleb's mac and kurt's windows machines. --- .github/workflows/qatest.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml index 457e915726..e19dce2709 100644 --- a/.github/workflows/qatest.yaml +++ b/.github/workflows/qatest.yaml @@ -47,13 +47,21 @@ jobs: artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: windows - runner: qa-windows-z600-dan + runner: qa-windows-asus-kurt artifact: Windows-installer install-path: 'C:\viewer-automation-main' + - os: mac + runner: qa-mac-dan + artifact: macOS-installer + install-path: '$HOME/Documents/viewer-automation' - os: mac runner: qa-mac-atlas artifact: macOS-installer install-path: '$HOME/Documents/viewer-automation' + - os: mac + runner: qa-mac-caleb + artifact: macOS-installer + install-path: '$HOME/Documents/viewer-automation' fail-fast: false runs-on: [self-hosted, "${{ matrix.runner }}"] From e33439e5238e9d2945aa99515c0206d827cc0910 Mon Sep 17 00:00:00 2001 From: Dan Linden <119471733+Dan-Linden@users.noreply.github.com> Date: Tue, 26 Aug 2025 15:18:10 -0700 Subject: [PATCH 3/7] Update qatest.yaml corrected kurt's machine name to qa-windows-kurt --- .github/workflows/qatest.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qatest.yaml b/.github/workflows/qatest.yaml index e19dce2709..b6883d88d4 100644 --- a/.github/workflows/qatest.yaml +++ b/.github/workflows/qatest.yaml @@ -47,7 +47,7 @@ jobs: artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: windows - runner: qa-windows-asus-kurt + runner: qa-windows-kurt artifact: Windows-installer install-path: 'C:\viewer-automation-main' - os: mac From 0fc42e951f99182b080c7187455d6a4da602441b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 27 Aug 2025 01:42:36 +0300 Subject: [PATCH 4/7] #4608 Crash at LLJoint::findJoint 'this' is null inside findJoint according to bugsplat so likely mRoot was not initialized yet. --- indra/newview/llmeshrepository.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9e8ed3bb43..997fc28333 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2460,7 +2460,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat LLPointer info = nullptr; info = new LLMeshSkinInfo(mesh_id, skin); - if (isAgentAvatarValid()) + if (isAgentAvatarValid() && gAgentAvatarp->mInitFlags != 0) { // joint numbers are consistent inside LLVOAvatar and animations, but inconsistent inside meshes, // generate a map of mesh joint numbers to LLVOAvatar joint numbers LLSkinningUtil::initJointNums(info, gAgentAvatarp); From e23aa060494ea1ae8f01033177ec10c333f01b30 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 29 Aug 2025 00:02:04 +0300 Subject: [PATCH 5/7] #4604 Reduce draw distance when low on RAM --- indra/newview/llviewermessage.cpp | 23 ++++++++++---- indra/newview/llviewertexture.cpp | 51 +++++++++++++++++++++++++------ indra/newview/llviewertexture.h | 3 ++ indra/newview/llvocache.cpp | 13 ++++++-- 4 files changed, 72 insertions(+), 18 deletions(-) diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7d39cc6059..d0e6af799c 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3364,6 +3364,17 @@ void send_agent_update(bool force_send, bool send_reliable) msg->addVector3Fast(_PREHASH_CameraUpAxis, LLViewerCamera::getInstance()->getUpAxis()); static F32 last_draw_disatance_step = 1024; + F32 memory_limited_draw_distance = gAgentCamera.mDrawDistance; + + if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + { + // If we are low on memory, reduce requested draw distance + // Discard's bias is clamped to 4 so we need to check 2 to 4 range + // Factor is intended to go from 1.0 to 2.0 + F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; + memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / factor, gAgentCamera.mDrawDistance / 2.f); + } + if (tp_state == LLAgent::TELEPORT_ARRIVING || LLStartUp::getStartupState() < STATE_MISC) { // Inform interest list, prioritize closer area. @@ -3372,25 +3383,25 @@ void send_agent_update(bool force_send, bool send_reliable) // closer ones. // Todo: revise and remove once server gets distance sorting. last_draw_disatance_step = llmax((F32)(gAgentCamera.mDrawDistance / 2.f), 50.f); + last_draw_disatance_step = llmin(last_draw_disatance_step, memory_limited_draw_distance); msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step); } - else if (last_draw_disatance_step < gAgentCamera.mDrawDistance) + else if (last_draw_disatance_step < memory_limited_draw_distance) { static LLFrameTimer last_step_time; if (last_step_time.getElapsedTimeF32() > 1.f) { // gradually increase draw distance - // Idealy this should be not per second, but based on how loaded - // mesh thread is, but hopefully this is temporary. last_step_time.reset(); - F32 step = gAgentCamera.mDrawDistance * 0.1f; - last_draw_disatance_step = llmin(last_draw_disatance_step + step, gAgentCamera.mDrawDistance); + F32 step = memory_limited_draw_distance * 0.1f; + last_draw_disatance_step = llmin(last_draw_disatance_step + step, memory_limited_draw_distance); } msg->addF32Fast(_PREHASH_Far, last_draw_disatance_step); } else { - msg->addF32Fast(_PREHASH_Far, gAgentCamera.mDrawDistance); + last_draw_disatance_step = memory_limited_draw_distance; + msg->addF32Fast(_PREHASH_Far, memory_limited_draw_distance); } msg->addU32Fast(_PREHASH_ControlFlags, control_flags); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 52939dbbae..7a25fb03a5 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -527,8 +527,16 @@ void LLViewerTexture::updateClass() 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 @@ -559,8 +567,13 @@ void LLViewerTexture::updateClass() sEvaluationTimer.reset(); // lower discard bias over time when at least 10% of budget is free - const F32 FREE_PERCENTAGE_TRESHOLD = -0.1f; - if (sDesiredDiscardBias > 1.f && over_pct < FREE_PERCENTAGE_TRESHOLD) + constexpr F32 FREE_PERCENTAGE_TRESHOLD = -0.1f; + constexpr U32 FREE_SYS_MEM_TRESHOLD = 100; + static LLCachedControl 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 high_mem_discard_decrement(gSavedSettings, "RenderHighMemMinDiscardDecrement", .1f); @@ -627,24 +640,42 @@ void LLViewerTexture::updateClass() } //static -bool LLViewerTexture::isSystemMemoryLow() +U32Megabytes LLViewerTexture::getFreeSystemMemory() { static LLFrameTimer timer; static U32Megabytes physical_res = U32Megabytes(U32_MAX); - static LLCachedControl 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; +} + +//static +bool LLViewerTexture::isSystemMemoryLow() +{ + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + return getFreeSystemMemory() < MIN_FREE_MAIN_MEMORY; +} + +F32 LLViewerTexture::getSystemMemoryBudgetFactor() +{ + static LLCachedControl min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512); + const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory); + S32 free_budget = (S32Megabytes)getFreeSystemMemory() - MIN_FREE_MAIN_MEMORY; + if (free_budget < 0) + { + // Result should range from 1 (0 free budget) to 2 (-512 free budget) + return 1.f - free_budget / MIN_FREE_MAIN_MEMORY; + } + return 1.f; } //end of static functions diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index f9311d85cb..d32c302d8e 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -115,6 +115,7 @@ public: static void initClass(); static void updateClass(); static bool isSystemMemoryLow(); + static F32 getSystemMemoryBudgetFactor(); LLViewerTexture(bool usemipmaps = true); LLViewerTexture(const LLUUID& id, bool usemipmaps) ; @@ -189,6 +190,8 @@ private: friend class LLBumpImageList; friend class LLUIImageList; + static U32Megabytes getFreeSystemMemory(); + protected: friend class LLViewerTextureList; LLUUID mID; diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 501828eee8..ac73c2def6 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -486,14 +486,23 @@ void LLVOCacheEntry::updateDebugSettings() //min radius: all objects within this radius remain loaded in memory static LLCachedControl min_radius(gSavedSettings,"SceneLoadMinRadius"); static const F32 MIN_RADIUS = 1.0f; - const F32 draw_radius = gAgentCamera.mDrawDistance; + + F32 draw_radius = gAgentCamera.mDrawDistance; + if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow()) + { + // Discard's bias maximum is 4 so we need to check 2 to 4 range + // Factor is intended to go from 1.0 to 2.0 + F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f; + // For safety cap reduction at 50%, we don't want to go below half of draw distance + draw_radius = llmax(draw_radius / factor, draw_radius / 2.f); + } const F32 clamped_min_radius = llclamp((F32) min_radius, MIN_RADIUS, draw_radius); // [1, mDrawDistance] sNearRadius = MIN_RADIUS + ((clamped_min_radius - MIN_RADIUS) * adjust_factor); // a percentage of draw distance beyond which all objects outside of view frustum will be unloaded, regardless of pixel threshold static LLCachedControl rear_max_radius_frac(gSavedSettings,"SceneLoadRearMaxRadiusFraction"); const F32 min_radius_plus_one = sNearRadius + 1.f; - const F32 max_radius = rear_max_radius_frac * gAgentCamera.mDrawDistance; + const F32 max_radius = rear_max_radius_frac * draw_radius; const F32 clamped_max_radius = llclamp(max_radius, min_radius_plus_one, draw_radius); // [sNearRadius, mDrawDistance] sRearFarRadius = min_radius_plus_one + ((clamped_max_radius - min_radius_plus_one) * adjust_factor); From 479fee984a595cab4fad0aae9157c5e168da692f Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 29 Aug 2025 00:03:07 +0300 Subject: [PATCH 6/7] #4604 Warn user off high settings when on low-RAM hardware --- indra/newview/llfloaterpreference.cpp | 28 +++++++++++++++++++ indra/newview/llfloaterpreference.h | 1 + .../skins/default/xui/en/notifications.xml | 11 ++++++++ 3 files changed, 40 insertions(+) diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index b74736a39d..291f22d78f 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -758,6 +758,7 @@ void LLFloaterPreference::onOpen(const LLSD& key) // Forget previous language changes. mLanguageChanged = false; + mLastQualityLevel = gSavedSettings.getU32("RenderQualityPerformance"); // Display selected maturity icons. onChangeMaturity(); @@ -1327,6 +1328,33 @@ void LLFloaterPreference::onCommitWindowedMode() void LLFloaterPreference::onChangeQuality(const LLSD& data) { U32 level = (U32)(data.asReal()); + constexpr U32 LVL_HIGH = 4; + if (level >= LVL_HIGH && mLastQualityLevel < level) + { + constexpr U32 LOW_MEM_THRESHOLD = 4097; + U32 total_mem = (U32Megabytes)LLMemory::getMaxMemKB(); + if (total_mem < LOW_MEM_THRESHOLD) + { + LLSD args; + args["TOTAL_MEM"] = LLSD::Integer(total_mem); + LLNotificationsUtil::add("PreferenceQualityWithLowMemory", args, LLSD(), [this](const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // If cancel pressed + if (option == 1) + { + constexpr U32 LVL_MED_PLUS = 3; + gSavedSettings.setU32("RenderQualityPerformance", LVL_MED_PLUS); + mLastQualityLevel = LVL_MED_PLUS; + LLFeatureManager::getInstance()->setGraphicsLevel(LVL_MED_PLUS, true); + refreshEnabledGraphics(); + refresh(); + } + } + ); + } + } + mLastQualityLevel = level; LLFeatureManager::getInstance()->setGraphicsLevel(level, true); refreshEnabledGraphics(); refresh(); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index fa9c421a8f..61ac0a4d77 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -218,6 +218,7 @@ private: bool mGotPersonalInfo; bool mLanguageChanged; bool mAvatarDataInitialized; + U32 mLastQualityLevel = 0; std::string mPriorInstantMessageLogPath; bool mOriginalHideOnlineStatus; diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index b182a241d8..7fc96af55d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -12145,6 +12145,17 @@ Cannot create large prims that intersect other residents. Please re-try when ot yestext="OK"/> + +Your system has [TOTAL_MEM]MB of memory, which might not be enough to run viewer at higher settings and might result in issues. + + + Date: Fri, 29 Aug 2025 20:33:32 +0300 Subject: [PATCH 7/7] #4598 Fix variables being inited before settings are ready --- indra/newview/llreflectionmapmanager.cpp | 1 - indra/newview/pipeline.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index f24bb892dc..663d8626b7 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -145,7 +145,6 @@ static void touch_default_probe(LLReflectionMap* probe) LLReflectionMapManager::LLReflectionMapManager() { mDynamicProbeCount = LL_MAX_REFLECTION_PROBE_COUNT; - refreshSettings(); initCubeFree(); } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 493fcd5d45..209b06fd85 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -426,6 +426,8 @@ void LLPipeline::init() sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); + mReflectionMapManager.refreshSettings(); + mInitialized = true; stop_glerror();