From b66f2e7da7d3ec68984d7fcb5e5996e1451c0baf Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Wed, 21 Sep 2022 21:19:17 +0300 Subject: [PATCH 01/11] SL-18202 WIP merging autotune contribution and updating UI --- indra/newview/CMakeLists.txt | 3 + indra/newview/app_settings/settings.xml | 132 +++++ indra/newview/app_settings/toolbars.xml | 1 + indra/newview/llappviewer.cpp | 150 +++--- indra/newview/lldrawpool.cpp | 63 ++- indra/newview/lldrawpoolalpha.cpp | 34 +- indra/newview/lldrawpoolavatar.cpp | 9 +- indra/newview/lldrawpoolbump.cpp | 33 +- indra/newview/lldrawpoolmaterials.cpp | 14 +- indra/newview/llfloaterperformance.cpp | 4 + indra/newview/llfloaterperformance.h | 1 + indra/newview/llfloaterpreference.cpp | 18 + indra/newview/llfloaterpreference.h | 2 + indra/newview/llperfstats.cpp | 469 ++++++++++++++++++ indra/newview/llperfstats.h | 454 +++++++++++++++++ indra/newview/llstartup.cpp | 6 + indra/newview/llviewercontrol.cpp | 72 +++ indra/newview/llviewerdisplay.cpp | 13 +- indra/newview/llviewerjointmesh.cpp | 11 + indra/newview/llvoavatar.cpp | 93 ++++ indra/newview/llvoavatar.h | 24 + indra/newview/llvovolume.cpp | 21 +- .../default/xui/en/floater_performance.xml | 54 ++ .../en/panel_performance_autoadjustments.xml | 272 ++++++++++ 24 files changed, 1872 insertions(+), 81 deletions(-) create mode 100644 indra/newview/llperfstats.cpp create mode 100644 indra/newview/llperfstats.h create mode 100644 indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 776797da7c..1a009967f5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1383,6 +1383,9 @@ set(viewer_HEADER_FILES VorbisFramework.h ) + list(APPEND viewer_SOURCE_FILES llperfstats.cpp) + list(APPEND viewer_HEADER_FILES llperfstats.h) + source_group("CMake Rules" FILES ViewerInstall.cmake) #build_data.json creation moved to viewer_manifest.py MAINT-6413 diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1877c30dc4..d92632c0a2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16776,6 +16776,138 @@ Value 50 + TargetFPS + + Comment + Desired minimum FPS + Persist + 1 + Type + U32 + Value + 25 + + AutoTuneFPS + + Comment + Allow the viewer to adjust your settings to achieve target FPS + Persist + 0 + Type + Boolean + Value + 0 + + AutoTuneLock + + Comment + When enabled the viewer will dynamically change settings until auto tune is explicitly turned off. + Persist + 1 + Type + Boolean + Value + 1 + + AllowSelfImpostor + + Comment + Allow own render time to impostor your avatar. + Persist + 1 + Type + Boolean + Value + 0 + + RenderAvatarMaxART + + Comment + Render Time Limit in microseconds (0.0 = no limit) + Persist + 0 + Type + F32 + Value + 4.699 + + AutoTuneRenderFarClipMin + + Comment + The lowest draw distance that auto tune is allowed to use + Persist + 0 + Type + F32 + Value + 32.0 + + AutoTuneRenderFarClipTarget + + Comment + The draw distance that auto tune will try to achieve + Persist + 0 + Type + F32 + Value + 256.0 + + UserTargetReflections + + Comment + Set by auto tune floater on build + Persist + 0 + Type + S32 + Value + 4 + + PerfStatsCaptureEnabled + + Comment + Enable/disable render time data to support autotune. + Persist + 1 + Type + Boolean + Value + 1 + + AutoTuneImpostorByDistEnabled + + Comment + Enable/disable using MaxNonImpostor to limit avatar rendering by distance. + Persist + 1 + Type + Boolean + Value + 0 + + AutoTuneImpostorFarAwayDistance + + Comment + Avatars beyond this range will automatically be optimized + Persist + 0 + Type + F32 + Value + 64.0 + + TuningFPSStrategy + + Comment + Strategy to use when tuning FPS. 0=Tune avatar rendering only, 1=Tune both avatar and global scene settings. + Persist + 1 + Type + U32 + Value + 0 + CameraOpacity Comment diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml index f3a23edc58..a1c9d6d9ee 100644 --- a/indra/newview/app_settings/toolbars.xml +++ b/indra/newview/app_settings/toolbars.xml @@ -22,6 +22,7 @@ + diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index d61a66c696..a04d21c4b0 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -108,6 +108,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" +#include "llperfstats.h" // Linden library includes #include "llavatarnamecache.h" @@ -1377,82 +1378,91 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { - LL_RECORD_BLOCK_TIME(FTM_FRAME); + LL_RECORD_BLOCK_TIME(FTM_FRAME); + { + // and now adjust the visuals from previous frame. + if(LLPerfStats::tunables.userAutoTuneEnabled && LLPerfStats::tunables.tuningFlag != LLPerfStats::Tunables::Nothing) + { + LLPerfStats::tunables.applyUpdates(); + } + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_FRAME); if (!LLWorld::instanceExists()) { LLWorld::createInstance(); } - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - LLSD newFrame; - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); - if (LLFloaterReg::instanceVisible("block_timers")) + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); + LLSD newFrame; + { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); // perf stats { - LLTrace::BlockTimer::processTimes(); + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); + if (LLFloaterReg::instanceVisible("block_timers")) + { + LLTrace::BlockTimer::processTimes(); + } + + LLTrace::get_frame_recording().nextPeriod(); + LLTrace::BlockTimer::logStats(); } - - LLTrace::get_frame_recording().nextPeriod(); - LLTrace::BlockTimer::logStats(); - } - LLTrace::get_thread_recorder()->pullFromChildren(); + LLTrace::get_thread_recorder()->pullFromChildren(); - //clear call stack records - LL_CLEAR_CALLSTACKS(); + //clear call stack records + LL_CLEAR_CALLSTACKS(); + } + { + { + LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_IDLE); // ensure we have the entire top scope of frame covered (input event and coro) + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df processMiscNativeEvents") + pingMainloopTimeout("Main:MiscNativeWindowEvents"); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" ) - pingMainloopTimeout("Main:MiscNativeWindowEvents"); + if (gViewerWindow) + { + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + gViewerWindow->getWindow()->processMiscNativeEvents(); + } - if (gViewerWindow) - { - LL_RECORD_BLOCK_TIME(FTM_MESSAGES); - gViewerWindow->getWindow()->processMiscNativeEvents(); - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df gatherInput") + pingMainloopTimeout("Main:GatherInput"); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" ) - pingMainloopTimeout("Main:GatherInput"); - } + if (gViewerWindow) + { + LL_RECORD_BLOCK_TIME(FTM_MESSAGES); + if (!restoreErrorTrap()) + { + LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; + } - if (gViewerWindow) - { - LL_RECORD_BLOCK_TIME(FTM_MESSAGES); - if (!restoreErrorTrap()) - { - LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; - } + gViewerWindow->getWindow()->gatherInput(); + } - gViewerWindow->getWindow()->gatherInput(); - } + //memory leaking simulation + if (gSimulateMemLeak) + { + LLFloaterMemLeak* mem_leak_instance = + LLFloaterReg::findTypedInstance("mem_leaking"); + if (mem_leak_instance) + { + mem_leak_instance->idle(); + } + } - //memory leaking simulation - if (gSimulateMemLeak) - { - LLFloaterMemLeak* mem_leak_instance = - LLFloaterReg::findTypedInstance("mem_leaking"); - if (mem_leak_instance) - { - mem_leak_instance->idle(); - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df mainloop") + // canonical per-frame event + mainloop.post(newFrame); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" ) - // canonical per-frame event - mainloop.post(newFrame); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" ) - // give listeners a chance to run - llcoro::suspend(); - // if one of our coroutines threw an uncaught exception, rethrow it now - LLCoros::instance().rethrow(); - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df suspend") + // give listeners a chance to run + llcoro::suspend(); + } + } if (!LLApp::isExiting()) { @@ -1470,6 +1480,7 @@ bool LLAppViewer::doFrame() && (gHeadlessClient || !gViewerWindow->getShowProgress()) && !gFocusMgr.focusLocked()) { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); joystick->scanJoystick(); gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); @@ -1483,6 +1494,7 @@ bool LLAppViewer::doFrame() } { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); //LL_RECORD_BLOCK_TIME(FTM_IDLE); idle(); } @@ -1517,13 +1529,14 @@ bool LLAppViewer::doFrame() display(); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" ) - pingMainloopTimeout("Main:Snapshot"); - LLFloaterSnapshot::update(); // take snapshots - LLFloaterOutfitSnapshot::update(); - gGLActive = FALSE; - } + { + LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_IDLE); + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" ) + pingMainloopTimeout("Main:Snapshot"); + LLFloaterSnapshot::update(); // take snapshots + LLFloaterOutfitSnapshot::update(); + gGLActive = FALSE; + } } } @@ -1569,7 +1582,8 @@ bool LLAppViewer::doFrame() // of equal priority on Windows if (milliseconds_to_sleep > 0) { - ms_sleep(milliseconds_to_sleep); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SLEEP ); + ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); LLAppViewer::getImageDecodeThread()->pause(); @@ -1670,7 +1684,7 @@ bool LLAppViewer::doFrame() LL_INFOS() << "Exiting main_loop" << LL_ENDL; } - + }LLPerfStats::StatsRecorder::endFrame(); LL_PROFILER_FRAME_END return ! LLApp::isRunning(); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index a3837fe10c..594cfe513d 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -52,6 +52,7 @@ #include "llglcommonfunc.h" #include "llvoavatar.h" #include "llviewershadermgr.h" +#include "llperfstats.h" S32 LLDrawPool::sNumDrawPools = 0; @@ -391,13 +392,22 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL t { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; - + + std::unique_ptr ratPtr{}; // Perf stats for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; if (pparams) { - pushBatch(*pparams, mask, texture); + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments(vobj, false, &ratPtr); + } + } + pushBatch(*pparams, mask, texture); } } } @@ -410,11 +420,21 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, U64 lastMeshId = 0; mask |= LLVertexBuffer::MAP_WEIGHT4; + std::unique_ptr ratPtr{}; // Perf stats for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo* pparams = *k; if (pparams) { + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, true ,&ratPtr); + } + } + if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash) { uploadMatrixPalette(*pparams); @@ -430,12 +450,21 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { - pushBatch(*pparams, mask, texture, batch_textures); + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, false, &ratPtr); + } + } + pushBatch(*pparams, mask, texture, batch_textures); } } } @@ -446,11 +475,21 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc LLVOAvatar* lastAvatar = nullptr; U64 lastMeshId = 0; mask |= LLVertexBuffer::MAP_WEIGHT4; + std::unique_ptr ratPtr{}; // Perf stats for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + if(pparams->mFace) + { + LLViewerObject* vobj = pparams->mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, true, &ratPtr); + } + } + if (pparams->mAvatar.notNull() && (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)) { uploadMatrixPalette(*pparams); @@ -466,11 +505,20 @@ void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batc void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + if((*pparams).mFace) + { + LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, false, &ratPtr); + } + } LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); pushBatch(*pparams, mask, texture, batch_textures); } @@ -482,11 +530,20 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLVOAvatar* lastAvatar = nullptr; U64 lastMeshId = 0; + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { + if((*pparams).mFace) + { + LLViewerObject* vobj = (*pparams).mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, true, &ratPtr); + } + } if (LLGLSLShader::sCurBoundShaderPtr) { LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index e674707c01..de5b9d5062 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -49,6 +49,7 @@ #include "llspatialpartition.h" #include "llglcommonfunc.h" #include "llvoavatar.h" +#include "llperfstats.h" BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; @@ -327,10 +328,20 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + if(vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + if (params.mParticle) { continue; @@ -500,8 +511,16 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector& mask |= LLVertexBuffer::MAP_WEIGHT4; + std::unique_ptr ratPtr{}; // Render time Stats collection for (LLDrawInfo* draw : emissives) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives"); + auto vobj = draw->mFace?draw->mFace->getViewerObject():nullptr; + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, draw->mFace->isState(LLFace::RIGGED), &ratPtr ); + } + bool tex_setup = TexSetup(draw, false); if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) { @@ -566,7 +585,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + std::unique_ptr ratPtr{}; // Render time Stats collection + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; if ((bool)params.mAvatar != rigged) @@ -585,6 +605,16 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) continue; } + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + if(depth_only) { // when updating depth buffer, discard faces that are more than 90% transparent @@ -769,6 +799,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) } } + ratPtr.reset(); // force the final batch to terminate to avoid double counting on the subsidiary batches for FB and Emmissives + // render emissive faces into alpha channel for bloom effects if (!depth_only) { diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 4a9a3caaec..02dea6b828 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -52,6 +52,7 @@ #include "llviewerpartsim.h" #include "llviewercontrol.h" // for gSavedSettings #include "llviewertexturelist.h" +#include "llperfstats.h" static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK; static U32 sBufferUsage = GL_STREAM_DRAW_ARB; @@ -380,9 +381,12 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } + LLPerfStats::RecordAvatarTime T(avatarp->getID(), LLPerfStats::StatType_t::RENDER_SHADOWS); + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); - BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); - if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) + BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); + // no shadows if the shadows are causing this avatar to breach the limit. + if (avatarp->isTooSlowWithShadows() || impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) { // No shadows for impostored (including jellydolled) or invisible avs. return; @@ -789,6 +793,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } + LLPerfStats::RecordAvatarTime T(avatarp->getID(), LLPerfStats::StatType_t::RENDER_GEOMETRY); if (!single_avatar && !avatarp->isFullyLoaded() ) { diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 8db6a10e26..09b2400aff 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -48,6 +48,7 @@ #include "llspatialpartition.h" #include "llviewershadermgr.h" #include "llmodel.h" +#include "llperfstats.h" //#include "llimagebmp.h" //#include "../tools/imdebug/imdebug.h" @@ -538,10 +539,18 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + std::unique_ptr ratPtr{}; + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + applyModelMatrix(params); if (params.mGroup) @@ -706,10 +715,21 @@ void LLDrawPoolBump::renderDeferred(S32 pass) LLVOAvatar* avatar = nullptr; U64 skin = 0; + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if(vobj && vobj->isAttachment()) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff); LLDrawPoolBump::bindBumpMap(params, bump_channel); @@ -1337,10 +1357,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + std::unique_ptr ratPtr{}; for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } + if (LLDrawPoolBump::bindBumpMap(params)) { if (mRigged) diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 2b05f4c453..f2408a3294 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -32,6 +32,7 @@ #include "pipeline.h" #include "llglcommonfunc.h" #include "llvoavatar.h" +#include "llperfstats.h" S32 diffuse_channel = -1; @@ -164,9 +165,20 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) + std::unique_ptr ratPtr{}; + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { LLDrawInfo& params = **i; + + if(params.mFace) + { + LLViewerObject* vobj = (LLViewerObject *)params.mFace->getViewerObject(); + + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, params.mFace->isState(LLFace::RIGGED), &ratPtr ); + } + } mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]); mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity); diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 0ef9ab3215..257c0b2b37 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -99,16 +99,19 @@ BOOL LLFloaterPerformance::postBuild() mComplexityPanel = getChild("panel_performance_complexity"); mSettingsPanel = getChild("panel_performance_preferences"); mHUDsPanel = getChild("panel_performance_huds"); + mAutoadjustmentsPanel = getChild("panel_performance_autoadjustments"); getChild("nearby_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); getChild("complexity_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mComplexityPanel)); getChild("settings_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); getChild("huds_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); + getChild("autoadjustments_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mAutoadjustmentsPanel)); initBackBtn(mNearbyPanel); initBackBtn(mComplexityPanel); initBackBtn(mSettingsPanel); initBackBtn(mHUDsPanel); + initBackBtn(mAutoadjustmentsPanel); mHUDList = mHUDsPanel->getChild("hud_list"); mHUDList->setNameListType(LLNameListCtrl::SPECIAL); @@ -197,6 +200,7 @@ void LLFloaterPerformance::hidePanels() mComplexityPanel->setVisible(FALSE); mHUDsPanel->setVisible(FALSE); mSettingsPanel->setVisible(FALSE); + mAutoadjustmentsPanel->setVisible(FALSE); } void LLFloaterPerformance::initBackBtn(LLPanel* panel) diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index e40eee162d..01b65365da 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -76,6 +76,7 @@ private: LLPanel* mComplexityPanel; LLPanel* mHUDsPanel; LLPanel* mSettingsPanel; + LLPanel* mAutoadjustmentsPanel; LLNameListCtrl* mHUDList; LLNameListCtrl* mObjectList; LLNameListCtrl* mNearbyList; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index ac1dbe9867..77bf03852f 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -115,6 +115,7 @@ #include "llpresetsmanager.h" #include "llsearchableui.h" +#include "llperfstats.h" const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; char const* const VISIBILITY_DEFAULT = "default"; @@ -1481,6 +1482,23 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool sh } } +void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + setRenderTimeText((F32)(LLPerfStats::renderAvatarMaxART_ns/1000), value_label, short_val); +} + +void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%.0f", value)); + } +} + void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index a089fde9ff..de4e3cd886 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -358,6 +358,8 @@ class LLAvatarComplexityControls public: static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); static void setText(U32 value, LLTextBox* text_box, bool short_val = false); + static void updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false); static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp new file mode 100644 index 0000000000..16d0df0245 --- /dev/null +++ b/indra/newview/llperfstats.cpp @@ -0,0 +1,469 @@ +/** +* @file llperfstats.cpp +* @brief Statistics collection to support autotune and perf flaoter. +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llperfstats.h" +#include "llcontrol.h" +#include "pipeline.h" +#include "llagentcamera.h" +#include "llvoavatar.h" +#include "llworld.h" +#include + +extern LLControlGroup gSavedSettings; + +namespace LLPerfStats +{ + std::atomic tunedAvatars{0}; + std::atomic renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features + bool belowTargetFPS{false}; + U32 lastGlobalPrefChange{0}; + std::mutex bufferToggleLock{}; + + Tunables tunables; + + std::atomic StatsRecorder::writeBuffer{0}; + bool StatsRecorder::collectionEnabled{true}; + LLUUID StatsRecorder::focusAv{LLUUID::null}; + std::array StatsRecorder::statsDoubleBuffer{ {} }; + std::array StatsRecorder::max{ {} }; + std::array StatsRecorder::sum{ {} }; + + void Tunables::applyUpdates() + { + assert_main_thread(); + // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) + if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; + if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); }; + if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); }; + if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipMin", userMinDrawDistance); }; + if( tuningFlag & UserTargetDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipTarget", userTargetDrawDistance); }; + if( tuningFlag & UserImpostorDistance ){ gSavedSettings.setF32("AutoTuneImpostorFarAwayDistance", userImpostorDistance); }; + if( tuningFlag & UserImpostorDistanceTuningEnabled ){ gSavedSettings.setBOOL("AutoTuneImpostorByDistEnabled", userImpostorDistanceTuningEnabled); }; + if( tuningFlag & UserFPSTuningStrategy ){ gSavedSettings.setU32("TuningFPSStrategy", userFPSTuningStrategy); }; + if( tuningFlag & UserAutoTuneEnabled ){ gSavedSettings.setBOOL("AutoTuneFPS", userAutoTuneEnabled); }; + if( tuningFlag & UserAutoTuneLock ){ gSavedSettings.setBOOL("AutoTuneLock", userAutoTuneLock); }; + if( tuningFlag & UserTargetFPS ){ gSavedSettings.setU32("TargetFPS", userTargetFPS); }; + if( tuningFlag & UserTargetReflections ){ gSavedSettings.setS32("UserTargetReflections", userTargetReflections); }; + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + if( tuningFlag & UserARTCutoff ){ gSavedSettings.setF32("RenderAvatarMaxART", userARTCutoffSliderValue); }; + resetChanges(); + } + + void Tunables::updateRenderCostLimitFromSettings() + { + assert_main_thread(); + const auto newval = gSavedSettings.getF32("RenderAvatarMaxART"); + if(newval < log10(LLPerfStats::ART_UNLIMITED_NANOS/1000)) + { + LLPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; + } + else + { + LLPerfStats::renderAvatarMaxART_ns = 0; + }; + } + + // static + void Tunables::updateSettingsFromRenderCostLimit() + { + if( userARTCutoffSliderValue != log10( ( (F32)LLPerfStats::renderAvatarMaxART_ns )/1000 ) ) + { + if( LLPerfStats::renderAvatarMaxART_ns != 0 ) + { + updateUserARTCutoffSlider(log10( ( (F32)LLPerfStats::renderAvatarMaxART_ns )/1000 ) ); + } + else + { + updateUserARTCutoffSlider(log10( (F32)LLPerfStats::ART_UNLIMITED_NANOS/1000 ) ); + } + } + } + + void Tunables::initialiseFromSettings() + { + assert_main_thread(); + // the following variables are two way and have "push" in llviewercontrol + LLPerfStats::tunables.userMinDrawDistance = gSavedSettings.getF32("AutoTuneRenderFarClipMin"); + LLPerfStats::tunables.userTargetDrawDistance = gSavedSettings.getF32("AutoTuneRenderFarClipTarget"); + LLPerfStats::tunables.userImpostorDistance = gSavedSettings.getF32("AutoTuneImpostorFarAwayDistance"); + LLPerfStats::tunables.userImpostorDistanceTuningEnabled = gSavedSettings.getBOOL("AutoTuneImpostorByDistEnabled"); + LLPerfStats::tunables.userFPSTuningStrategy = gSavedSettings.getU32("TuningFPSStrategy"); + LLPerfStats::tunables.userTargetFPS = gSavedSettings.getU32("TargetFPS"); + LLPerfStats::tunables.userTargetReflections = gSavedSettings.getS32("UserTargetReflections"); + LLPerfStats::tunables.userAutoTuneEnabled = gSavedSettings.getBOOL("AutoTuneFPS"); + LLPerfStats::tunables.userAutoTuneLock = gSavedSettings.getBOOL("AutoTuneLock"); + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + updateRenderCostLimitFromSettings(); + resetChanges(); + } + + StatsRecorder::StatsRecorder():q(1024*16),t(&StatsRecorder::run) + { + // create a queue + // create a thread to consume from the queue + tunables.initialiseFromSettings(); + t.detach(); + } + + // static + void StatsRecorder::toggleBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + + bool unreliable{false}; + LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null]; + + static constexpr std::initializer_list sceneStatsToAvg = { + StatType_t::RENDER_FRAME, + StatType_t::RENDER_DISPLAY, + StatType_t::RENDER_HUDS, + StatType_t::RENDER_UI, + StatType_t::RENDER_SWAP, + // RENDER_LFS, + // RENDER_MESHREPO, + StatType_t::RENDER_IDLE }; + + static constexpr std::initializer_list avatarStatsToAvg = { + StatType_t::RENDER_GEOMETRY, + StatType_t::RENDER_SHADOWS, + StatType_t::RENDER_COMBINED, + StatType_t::RENDER_IDLE }; + + + if( /*sceneStats[static_cast(StatType_t::RENDER_FPSLIMIT)] != 0 ||*/ sceneStats[static_cast(StatType_t::RENDER_SLEEP)] != 0 ) + { + unreliable = true; + //lastStats[static_cast(StatType_t::RENDER_FPSLIMIT)] = sceneStats[static_cast(StatType_t::RENDER_FPSLIMIT)]; + lastStats[static_cast(StatType_t::RENDER_SLEEP)] = sceneStats[static_cast(StatType_t::RENDER_SLEEP)]; + lastStats[static_cast(StatType_t::RENDER_FRAME)] = sceneStats[static_cast(StatType_t::RENDER_FRAME)]; // bring over the total frame render time to deal with region crossing overlap issues + } + + if(!unreliable) + { + // only use these stats when things are reliable. + + for(auto & statEntry : sceneStatsToAvg) + { + auto avg = lastStats[static_cast(statEntry)]; + auto val = sceneStats[static_cast(statEntry)]; + sceneStats[static_cast(statEntry)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); + // LL_INFOS("scenestats") << "Scenestat: " << static_cast(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(statEntry)] << LL_ENDL; + } + } +// Allow attachment times etc to update even when FPS limited or sleeping. + auto& statsMap = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_ATTACHMENT)]; + for(auto& stat_entry : statsMap) + { + auto val = stat_entry.second[static_cast(ST::RENDER_COMBINED)]; + if(val > SMOOTHING_PERIODS){ + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_ATTACHMENT)][stat_entry.first][static_cast(ST::RENDER_COMBINED)]; + stat_entry.second[static_cast(ST::RENDER_COMBINED)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); + } + } + + + auto& statsMapAv = statsDoubleBuffer[writeBuffer][static_cast(ObjType_t::OT_AVATAR)]; + for(auto& stat_entry : statsMapAv) + { + for(auto& stat : avatarStatsToAvg) + { + auto val = stat_entry.second[static_cast(stat)]; + if(val > SMOOTHING_PERIODS) + { + auto avg = statsDoubleBuffer[writeBuffer ^ 1][static_cast(ObjType_t::OT_AVATAR)][stat_entry.first][static_cast(stat)]; + stat_entry.second[static_cast(stat)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); + } + } + } + + // swap the buffers + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + // clean the write maps in all cases. + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMapByType : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMapByType) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMapByType.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + + // and now adjust the proxy vars so that the main thread can adjust the visuals. + if(tunables.userAutoTuneEnabled) + { + updateAvatarParams(); + } + } + + // clear buffers when we change region or need a hard reset. + // static + void StatsRecorder::clearStatsBuffers() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + // swap the clean buffers in + if(enabled()) + { + std::lock_guard lock{bufferToggleLock}; + writeBuffer ^= 1; + }; + // repeat before we start processing new stuff + for(auto& statsMap : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + } + + //static + int StatsRecorder::countNearbyAvatars(S32 distance) + { + const auto our_pos = gAgentCamera.getCameraPositionGlobal(); + + std::vector positions; + uuid_vec_t avatar_ids; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, our_pos, distance); + return positions.size(); + } + + // static + void StatsRecorder::updateAvatarParams() + { + + if(tunables.userImpostorDistanceTuningEnabled) + { + // if we have less than the user's "max Non-Impostors" avatars within the desired range then adjust the limit. + // also adjusts back up again for nearby crowds. + auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance)); + if( count != tunables.nonImpostors ) + { + tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); + LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL; + } + } + + auto av_render_max_raw = LLPerfStats::StatsRecorder::getMax(ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED); + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = LLPerfStats::StatsRecorder::getSum(ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); + // similar to sleep time, induced by FPS limit + //auto tot_limit_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FPSLIMIT); + + + // the time spent this frame on the "doFrame" call. Treated as "tot time for frame" + auto tot_frame_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + + if( tot_sleep_time_raw != 0 ) + { + // Note: we do not average sleep + // if at some point we need to, the averaging will need to take this into account or + // we forever think we're in the background due to residuals. + LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL; + return; + } + + // The frametime budget we have based on the target FPS selected + auto target_frame_time_raw = (U64)llround((F64)LLTrace::BlockTimer::countsPerSecond()/(tunables.userTargetFPS==0?1:tunables.userTargetFPS)); + // LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL; + auto inferredFPS{1000/(U32)std::max(raw_to_ms(tot_frame_time_raw),1.0)}; + U32 settingsChangeFrequency{inferredFPS > 25?inferredFPS:25}; + /*if( tot_limit_time_raw != 0) + { + // This could be problematic. + tot_frame_time_raw -= tot_limit_time_raw; + }*/ + // 1) Is the target frame time lower than current? + if( target_frame_time_raw <= tot_frame_time_raw ) + { + if(belowTargetFPS == false) + { + // this is the first frame under. hold fire to add a little hysteresis + belowTargetFPS = true; + LLPerfStats::lastGlobalPrefChange = gFrameCount; + } + // if so we've got work to do + + // how much of the frame was spent on non avatar related work? + U64 non_avatar_time_raw = tot_frame_time_raw - tot_avatar_time_raw; + + // If the target frame time < scene time (estimated as non_avatar time) + U64 target_avatar_time_raw; + if(target_frame_time_raw < non_avatar_time_raw) + { + // we cannnot do this by avatar adjustment alone. + if((gFrameCount - LLPerfStats::lastGlobalPrefChange) > settingsChangeFrequency) // give changes a short time to take effect. + { + if(tunables.userFPSTuningStrategy == TUNE_SCENE_AND_AVATARS) + { + // 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit. + // the other reflection options make comparatively little change and if this overshoots we'll be stepping back up later + if(LLPipeline::RenderReflectionDetail != -2) + { + LLPerfStats::tunables.updateReflectionDetail(-2); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + else // deliberately "else" here so we only do one of these in any given frame + { + // step down the DD by 10m per update + auto new_dd = (LLPipeline::RenderFarClip - DD_STEP > tunables.userMinDrawDistance)?(LLPipeline::RenderFarClip - DD_STEP) : tunables.userMinDrawDistance; + if(new_dd != LLPipeline::RenderFarClip) + { + LLPerfStats::tunables.updateFarClip( new_dd ); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + } + } + // if we reach here, we've no more changes to make to tune scenery so we'll resort to agressive Avatar tuning + // Note: moved from outside "if changefrequency elapsed" to stop fallthrough and allow scenery changes time to take effect. + target_avatar_time_raw = 0; + } + else + { + // we made a settings change recently so let's give it time. + return; + } + } + else + { + // set desired avatar budget. + target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw; + } + + if( target_avatar_time_raw < tot_avatar_time_raw ) + { + // we need to spend less time drawing avatars to meet our budget + auto new_render_limit_ns {LLPerfStats::raw_to_ns(av_render_max_raw)}; + // max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction + if( new_render_limit_ns > renderAvatarMaxART_ns ) + { + new_render_limit_ns = renderAvatarMaxART_ns; + } + new_render_limit_ns -= LLPerfStats::ART_MIN_ADJUST_DOWN_NANOS; + + // bounce at the bottom to prevent "no limit" + new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)LLPerfStats::ART_MINIMUM_NANOS); + + // assign the new value + if(renderAvatarMaxART_ns != new_render_limit_ns) + { + renderAvatarMaxART_ns = new_render_limit_ns; + tunables.updateSettingsFromRenderCostLimit(); + } + // LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL; + } + // LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< LLPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << LLPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL; + } + else if( LLPerfStats::raw_to_ns(target_frame_time_raw) > (LLPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) ) + { + if(belowTargetFPS == true) + { + // we reached target, force a pause + lastGlobalPrefChange = gFrameCount; + belowTargetFPS = false; + } + + // once we're over the FPS target we slow down further + if((gFrameCount - lastGlobalPrefChange) > settingsChangeFrequency*3) + { + if(!tunables.userAutoTuneLock) + { + // we've reached the target and stayed long enough to consider stable. + // turn off if we are not locked. + tunables.updateUserAutoTuneEnabled(false); + } + if( LLPerfStats::tunedAvatars > 0 ) + { + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. + renderAvatarMaxART_ns += LLPerfStats::ART_MIN_ADJUST_UP_NANOS; + tunables.updateSettingsFromRenderCostLimit(); + return; + } + if(tunables.userFPSTuningStrategy == TUNE_SCENE_AND_AVATARS) + { + if( LLPipeline::RenderFarClip < tunables.userTargetDrawDistance ) + { + LLPerfStats::tunables.updateFarClip( std::min(LLPipeline::RenderFarClip + DD_STEP, tunables.userTargetDrawDistance) ); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + if( (tot_frame_time_raw * 1.5) < target_frame_time_raw ) + { + // if everything else is "max" and we have >50% headroom let's knock the water quality up a notch at a time. + LLPerfStats::tunables.updateReflectionDetail( std::min(LLPipeline::RenderReflectionDetail + 1, tunables.userTargetReflections) ); + } + } + } + } + } +} \ No newline at end of file diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h new file mode 100644 index 0000000000..1e867f5ef1 --- /dev/null +++ b/indra/newview/llperfstats.h @@ -0,0 +1,454 @@ +/** +* @file llperfstats.h +* @brief Statistics collection to support autotune and perf flaoter. +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, Linden Research, Inc. +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +* +* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA +* $/LicenseInfo$ +*/ +#pragma once +#ifndef LL_PERFSTATS_H_INCLUDED +#define LL_PERFSTATS_H_INCLUDED + +#include +#include +#include +#include +#include +#include "lluuid.h" +#include "llfasttimer.h" +#include "llapp.h" +#include "llprofiler.h" +#include "pipeline.h" + +extern U32 gFrameCount; +extern LLUUID gAgentID; +namespace LLPerfStats +{ +// Note if changing these, they should correspond with the log range of the correpsonding sliders + static constexpr U64 ART_UNLIMITED_NANOS{50000000}; + static constexpr U64 ART_MINIMUM_NANOS{100000}; + static constexpr U64 ART_MIN_ADJUST_UP_NANOS{10000}; + static constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000}; + + static constexpr F32 PREFERRED_DD{180}; + static constexpr U32 SMOOTHING_PERIODS{50}; + static constexpr U32 DD_STEP{10}; + + static constexpr U32 TUNE_AVATARS_ONLY{0}; + static constexpr U32 TUNE_SCENE_AND_AVATARS{1}; + + extern std::atomic tunedAvatars; + extern std::atomic renderAvatarMaxART_ns; + extern bool belowTargetFPS; + extern U32 lastGlobalPrefChange; + extern std::mutex bufferToggleLock; + + enum class ObjType_t{ + OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery + OT_AVATAR, + OT_ATTACHMENT, + OT_HUD, + OT_COUNT + }; + enum class StatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_DISPLAY, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + //RENDER_FPSLIMIT, + RENDER_FPS, + RENDER_IDLE, + RENDER_DONE, // toggle buffer & clearbuffer (see processUpdate for hackery) + STATS_COUNT + }; + + struct StatsRecord + { + StatType_t statType; + ObjType_t objType; + LLUUID avID; + LLUUID objID; + uint64_t time; + bool isRigged; + bool isHUD; + }; + + struct Tunables + { + static constexpr U32 Nothing{0}; + static constexpr U32 NonImpostors{1}; + static constexpr U32 ReflectionDetail{2}; + static constexpr U32 FarClip{4}; + static constexpr U32 UserMinDrawDistance{8}; + static constexpr U32 UserTargetDrawDistance{16}; + static constexpr U32 UserImpostorDistance{32}; + static constexpr U32 UserImpostorDistanceTuningEnabled{64}; + static constexpr U32 UserFPSTuningStrategy{128}; + static constexpr U32 UserAutoTuneEnabled{256}; + static constexpr U32 UserTargetFPS{512}; + static constexpr U32 UserARTCutoff{1024}; + static constexpr U32 UserTargetReflections{2048}; + static constexpr U32 UserAutoTuneLock{4096}; + + U32 tuningFlag{0}; // bit mask for changed settings + + // proxy variables, used to pas the new value to be set via the mainthread + U32 nonImpostors{0}; + S32 reflectionDetail{0}; + F32 farClip{0.0}; + F32 userMinDrawDistance{0.0}; + F32 userTargetDrawDistance{0.0}; + F32 userImpostorDistance{0.0}; + bool userImpostorDistanceTuningEnabled{false}; + U32 userFPSTuningStrategy{0}; + bool userAutoTuneEnabled{false}; + bool userAutoTuneLock{true}; + U32 userTargetFPS{0}; + F32 userARTCutoffSliderValue{0}; + S32 userTargetReflections{0}; + + void updateNonImposters(U32 nv){nonImpostors=nv; tuningFlag |= NonImpostors;}; + void updateReflectionDetail(S32 nv){reflectionDetail=nv; tuningFlag |= ReflectionDetail;}; + void updateFarClip(F32 nv){farClip=nv; tuningFlag |= FarClip;}; + void updateUserMinDrawDistance(F32 nv){userMinDrawDistance=nv; tuningFlag |= UserMinDrawDistance;}; + void updateUserTargetDrawDistance(F32 nv){userTargetDrawDistance=nv; tuningFlag |= UserTargetDrawDistance;}; + void updateImposterDistance(F32 nv){userImpostorDistance=nv; tuningFlag |= UserImpostorDistance;}; + void updateImposterDistanceTuningEnabled(bool nv){userImpostorDistanceTuningEnabled=nv; tuningFlag |= UserImpostorDistanceTuningEnabled;}; + void updateUserFPSTuningStrategy(U32 nv){userFPSTuningStrategy=nv; tuningFlag |= UserFPSTuningStrategy;}; + void updateTargetFps(U32 nv){userTargetFPS=nv; tuningFlag |= UserTargetFPS;}; + void updateUserARTCutoffSlider(F32 nv){userARTCutoffSliderValue=nv; tuningFlag |= UserARTCutoff;}; + void updateUserAutoTuneEnabled(bool nv){userAutoTuneEnabled=nv; tuningFlag |= UserAutoTuneEnabled;}; + void updateUserAutoTuneLock(bool nv){userAutoTuneLock=nv; tuningFlag |= UserAutoTuneLock;}; + void updateUserTargetReflections(S32 nv){userTargetReflections=nv; tuningFlag |= UserTargetReflections;}; + + void resetChanges(){tuningFlag=Nothing;}; + void initialiseFromSettings(); + void updateRenderCostLimitFromSettings(); + void updateSettingsFromRenderCostLimit(); + void applyUpdates(); + }; + + extern Tunables tunables; + + class StatsRecorder{ + using Queue = LLThreadSafeQueue; + public: + + static inline StatsRecorder& getInstance() + { + static StatsRecorder instance; + return instance; + } + static inline void setFocusAv(const LLUUID& avID){focusAv = avID;}; + static inline const LLUUID& getFocusAv(){return focusAv;}; + static inline void send(StatsRecord && upd){StatsRecorder::getInstance().q.pushFront(std::move(upd));}; + static void endFrame(){StatsRecorder::getInstance().q.pushFront(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 0});}; + static void clearStats(){StatsRecorder::getInstance().q.pushFront(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 1});}; + + static inline void setEnabled(bool on_or_off){collectionEnabled=on_or_off;}; + static inline void enable() { collectionEnabled=true; }; + static inline void disable() { collectionEnabled=false; }; + static inline bool enabled() { return collectionEnabled; }; + + static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; + // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} + static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(otype)][id][static_cast(type)]; + } + static inline uint64_t getSceneStat(StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast(type)]; + } + + static inline uint64_t getSum(ObjType_t otype, StatType_t type) + { + return sum[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static inline uint64_t getMax(ObjType_t otype, StatType_t type) + { + return max[getReadBufferIndex()][static_cast(otype)][static_cast(type)]; + } + static void updateAvatarParams(); + private: + StatsRecorder(); + + static int countNearbyAvatars(S32 distance); +// StatsArray is a uint64_t for each possible statistic type. + using StatsArray = std::array(LLPerfStats::StatType_t::STATS_COUNT)>; + using StatsMap = std::unordered_map>; + using StatsTypeMatrix = std::array(LLPerfStats::ObjType_t::OT_COUNT)>; + using StatsSummaryArray = std::array(LLPerfStats::ObjType_t::OT_COUNT)>; + + static std::atomic writeBuffer; + static LLUUID focusAv; + static std::array statsDoubleBuffer; + static std::array max; + static std::array sum; + static bool collectionEnabled; + + + void processUpdate(const StatsRecord& upd) const + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // LL_INFOS("perfstats") << "processing update:" << LL_ENDL; + // Note: nullptr is used as the key for global stats + #ifdef TRACY_ENABLE + static char avstr[36]; + static char obstr[36]; + #endif + + if (upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 0) + { + // LL_INFOS("perfstats") << "End of Frame Toggle Buffer:" << gFrameCount << LL_ENDL; + toggleBuffer(); + return; + } + if (upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 1) + { + // LL_INFOS("perfstats") << "New region - clear buffers:" << gFrameCount << LL_ENDL; + clearStatsBuffers(); + return; + } + + auto ot{upd.objType}; + auto& key{upd.objID}; + auto& avKey{upd.avID}; + auto type {upd.statType}; + auto val {upd.time}; + + if (ot == ObjType_t::OT_GENERAL) + { + // LL_INFOS("perfstats") << "General update:" << LL_ENDL; + doUpd(key, ot, type,val); + return; + } + + if (ot == ObjType_t::OT_AVATAR) + { + // LL_INFOS("perfstats") << "Avatar update:" << LL_ENDL; + doUpd(avKey, ot, type, val); + return; + } + + if (ot == ObjType_t::OT_ATTACHMENT) + { + if( !upd.isHUD ) // don't include HUD cost in self. + { + LL_PROFILE_ZONE_NAMED("Att as Av") + // For all attachments that are not rigged we add them to the avatar (for all avatars) cost. + doUpd(avKey, ObjType_t::OT_AVATAR, type, val); + } + if( avKey == focusAv ) + { + LL_PROFILE_ZONE_NAMED("Att as Att") + // For attachments that are for the focusAv (self for now) we record them for the attachment/complexity view + if(upd.isHUD) + { + ot = ObjType_t::OT_HUD; + } + // LL_INFOS("perfstats") << "frame: " << gFrameCount << " Attachment update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << LL_ENDL; + doUpd(key, ot, type, val); + } + // else + // { + // // LL_INFOS("perfstats") << "frame: " << gFrameCount << " non-self Att update("<< (type==StatType_t::RENDER_GEOMETRY?"GEOMETRY":"SHADOW") << ": " << key.asString() << " = " << val << " for av " << avKey.asString() << LL_ENDL; + // } + } + } + + static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast(ot)]}; + auto& thisAsset = stm[key]; + + thisAsset[static_cast(type)] += val; + thisAsset[static_cast(ST::RENDER_COMBINED)] += val; + + sum[writeBuffer][static_cast(ot)][static_cast(type)] += val; + sum[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] += val; + + if(max[writeBuffer][static_cast(ot)][static_cast(type)] < thisAsset[static_cast(type)]) + { + max[writeBuffer][static_cast(ot)][static_cast(type)] = thisAsset[static_cast(type)]; + } + if(max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] < thisAsset[static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ot)][static_cast(ST::RENDER_COMBINED)] = thisAsset[static_cast(ST::RENDER_COMBINED)]; + } + } + + static void toggleBuffer(); + static void clearStatsBuffers(); + + // thread entry + static void run() + { + StatsRecord upd[10]; + auto & instance {StatsRecorder::getInstance()}; + LL_PROFILER_SET_THREAD_NAME("PerfStats"); + + while( enabled() && !LLApp::isExiting() ) + { + auto count = 0; + while (count < 10) + { + if (instance.q.tryPopFor(std::chrono::milliseconds(10), upd[count])) + { + count++; + } + else + { + break; + } + } + //LL_PROFILER_THREAD_BEGIN("PerfStats"); + if(count) + { + // LL_INFOS("perfstats") << "processing " << count << " updates." << LL_ENDL; + for(auto i =0; i < count; i++) + { + instance.processUpdate(upd[i]); + } + } + //LL_PROFILER_THREAD_END("PerfStats"); + } + } + + Queue q; + std::thread t; + + ~StatsRecorder() = default; + StatsRecorder(const StatsRecorder&) = delete; + StatsRecorder& operator=(const StatsRecorder&) = delete; + + }; + + template + class RecordTime + { + + private: + RecordTime(const RecordTime&) = delete; + RecordTime() = delete; + U64 start; + public: + StatsRecord stat; + + RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false, bool isHUDAtt=false): + start{LLTrace::BlockTimer::getCPUClockCount64()}, + stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt, isHUDAtt} + { + //LL_PROFILE_ZONE_COLOR(tracy::Color::Orange); + }; + + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t * = nullptr> + explicit RecordTime( StatType_t type ):RecordTime(LLUUID::null, LLUUID::null, type ) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + }; + + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t * = nullptr> + RecordTime( const LLUUID & av, StatType_t type ):RecordTime(std::move(av), LLUUID::null, type) + { + //LL_PROFILE_ZONE_COLOR(tracy::Color::Purple); + }; + + ~RecordTime() + { + if(!LLPerfStats::StatsRecorder::enabled()) + { + return; + } + + //LL_PROFILE_ZONE_COLOR(tracy::Color::Red); + + stat.time = LLTrace::BlockTimer::getCPUClockCount64() - start; + StatsRecorder::send(std::move(stat)); + }; + }; + + + inline double raw_to_ns(U64 raw) { return (static_cast(raw) * 1000000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + inline double raw_to_us(U64 raw) { return (static_cast(raw) * 1000000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + inline double raw_to_ms(U64 raw) { return (static_cast(raw) * 1000.0) / (F64)LLTrace::BlockTimer::countsPerSecond(); }; + + using RecordSceneTime = RecordTime; + using RecordAvatarTime = RecordTime; + using RecordAttachmentTime = RecordTime; + using RecordHudAttachmentTime = RecordTime; + +};// namespace LLPerfStats + +// helper functions +using RATptr = std::unique_ptr; +using RSTptr = std::unique_ptr; + +template +static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPtrp) +{ + if( !vobj ){ ratPtrp->reset(); return;}; + + const T* rootAtt{vobj}; + if (rootAtt->isAttachment()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + + while( !rootAtt->isRootEdit() ) + { + rootAtt = (T*)(rootAtt->getParent()); + } + + auto avPtr = (T*)(rootAtt->getParent()); + if(!avPtr){ratPtrp->reset(); return;} + + auto& av = avPtr->getID(); + auto& obj = rootAtt->getAttachmentItemID(); + if (!*ratPtrp || (*ratPtrp)->stat.objID != obj || (*ratPtrp)->stat.avID != av) + { + if (*ratPtrp) + { + // deliberately reset to ensure destruction before construction of replacement. + ratPtrp->reset(); + }; + *ratPtrp = std::make_unique( + av, + obj, + ( LLPipeline::sShadowRender?LLPerfStats::StatType_t::RENDER_SHADOWS : LLPerfStats::StatType_t::RENDER_GEOMETRY ), + isRigged, + rootAtt->isHUDAttachment()); + } + } + return; +}; + +#endif \ No newline at end of file diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index dc48eaa823..9cbd56ee7f 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -207,6 +207,7 @@ #include "llstacktrace.h" #include "threadpool.h" +#include "llperfstats.h" #if LL_WINDOWS @@ -1492,6 +1493,8 @@ bool idle_startup() LLViewerParcelAskPlay::getInstance()->loadSettings(); } + gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); + // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized @@ -3405,6 +3408,9 @@ bool process_login_success_response() if(!text.empty()) gAgentID.set(text); gDebugInfo["AgentID"] = text; + LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); + LLPerfStats::StatsRecorder::setFocusAv(gAgentID); + // Agent id needed for parcel info request in LLUrlEntryParcel // to resolve parcel name. LLUrlEntryParcel::setAgentID(gAgentID); diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index fd07fc32bc..e5723ebfe5 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -75,6 +75,7 @@ #include "llspellcheck.h" #include "llslurl.h" #include "llstartup.h" +#include "llperfstats.h" // Third party library includes #include @@ -643,6 +644,66 @@ bool toggle_show_object_render_cost(const LLSD& newvalue) } void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value); + +void handleTargetFPSChanged(const LLSD& newValue) +{ + const auto targetFPS = gSavedSettings.getU32("TargetFPS"); + LLPerfStats::tunables.userTargetFPS = targetFPS; +} + +void handleAutoTuneLockChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneLock"); + LLPerfStats::tunables.userAutoTuneLock = newval; +} + +void handleAutoTuneFPSChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneFPS"); + LLPerfStats::tunables.userAutoTuneEnabled = newval; + if(newval && LLPerfStats::renderAvatarMaxART_ns == 0) // If we've enabled autotune we override "unlimited" to max + { + gSavedSettings.setF32("RenderAvatarMaxART",log10(LLPerfStats::ART_UNLIMITED_NANOS-1000));//triggers callback to update static var + } +} + +void handleRenderAvatarMaxARTChanged(const LLSD& newValue) +{ + LLPerfStats::tunables.updateRenderCostLimitFromSettings(); +} + +void handleUserTargetDrawDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("AutoTuneRenderFarClipTarget"); + LLPerfStats::tunables.userTargetDrawDistance = newval; +} + +void handleUserTargetReflectionsChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getS32("UserTargetReflections"); + LLPerfStats::tunables.userTargetReflections = newval; +} + +void handlePerformanceStatsEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("PerfStatsCaptureEnabled"); + LLPerfStats::StatsRecorder::setEnabled(newval); +} +void handleUserImpostorByDistEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneImpostorByDistEnabled"); + LLPerfStats::tunables.userImpostorDistanceTuningEnabled = newval; +} +void handleUserImpostorDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("AutoTuneImpostorFarAwayDistance"); + LLPerfStats::tunables.userImpostorDistance = newval; +} +void handleFPSTuningStrategyChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("TuningFPSStrategy"); + LLPerfStats::tunables.userFPSTuningStrategy = newval; +} //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() @@ -796,6 +857,17 @@ void settings_setup_listeners() gSavedSettings.getControl("DebugAvatarJoints")->getCommitSignal()->connect(boost::bind(&handleDebugAvatarJointsChanged, _2)); gSavedSettings.getControl("RenderAutoMuteByteLimit")->getSignal()->connect(boost::bind(&handleRenderAutoMuteByteLimitChanged, _2)); gSavedPerAccountSettings.getControl("AvatarHoverOffsetZ")->getCommitSignal()->connect(boost::bind(&handleAvatarHoverOffsetChanged, _2)); + + gSavedSettings.getControl("TargetFPS")->getSignal()->connect(boost::bind(&handleTargetFPSChanged, _2)); + gSavedSettings.getControl("AutoTuneFPS")->getSignal()->connect(boost::bind(&handleAutoTuneFPSChanged, _2)); + gSavedSettings.getControl("AutoTuneLock")->getSignal()->connect(boost::bind(&handleAutoTuneLockChanged, _2)); + gSavedSettings.getControl("RenderAvatarMaxART")->getSignal()->connect(boost::bind(&handleRenderAvatarMaxARTChanged, _2)); + gSavedSettings.getControl("PerfStatsCaptureEnabled")->getSignal()->connect(boost::bind(&handlePerformanceStatsEnabledChanged, _2)); + gSavedSettings.getControl("UserTargetReflections")->getSignal()->connect(boost::bind(&handleUserTargetReflectionsChanged, _2)); + gSavedSettings.getControl("AutoTuneRenderFarClipTarget")->getSignal()->connect(boost::bind(&handleUserTargetDrawDistanceChanged, _2)); + gSavedSettings.getControl("AutoTuneImpostorFarAwayDistance")->getSignal()->connect(boost::bind(&handleUserImpostorDistanceChanged, _2)); + gSavedSettings.getControl("AutoTuneImpostorByDistEnabled")->getSignal()->connect(boost::bind(&handleUserImpostorByDistEnabledChanged, _2)); + gSavedSettings.getControl("TuningFPSStrategy")->getSignal()->connect(boost::bind(&handleFPSTuningStrategyChanged, _2)); } #if TEST_CACHED_CONTROL diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index be54cb2f96..fa026c2888 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -78,6 +78,7 @@ #include "llscenemonitor.h" #include "llenvironment.h" +#include "llperfstats.h" extern LLPointer gStartTexture; extern bool gShiftFrame; @@ -256,7 +257,8 @@ static LLTrace::BlockTimerStatHandle FTM_EEP_UPDATE("Env Update"); // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { - LL_RECORD_BLOCK_TIME(FTM_RENDER); + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering. + LL_RECORD_BLOCK_TIME(FTM_RENDER); if (gWindowResized) { //skip render on frames where window has been resized @@ -1051,7 +1053,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { - gGL.matrixMode(LLRender::MM_PROJECTION); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_HUDS); // render time capture - Primary contributor to HUDs (though these end up in render batches) + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); @@ -1242,7 +1245,8 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_UI ); // render time capture - Primary UI stat can have HUD time overlap (TODO) + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1325,7 +1329,8 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { - LL_RECORD_BLOCK_TIME(FTM_SWAP); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU + LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) { diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index f3b0e82b3a..489f90aabb 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -55,6 +55,7 @@ #include "m3math.h" #include "m4math.h" #include "llmatrix4a.h" +#include "llperfstats.h" #if !LL_DARWIN && !LL_LINUX extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; @@ -230,6 +231,16 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) return 0; } + // render time capture + // This path does not appear to have attachments. Prove this then remove. + std::unique_ptr ratPtr{}; + auto vobj = mFace->getViewerObject(); + if( vobj && vobj->isAttachment() ) + { + trackAttachments( vobj, mFace->isState(LLFace::RIGGED), &ratPtr ); + LL_WARNS("trackAttachments") << "Attachment render time is captuted." << LL_ENDL; + } + U32 triangle_count = 0; S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index b66a6958fe..1a71780a88 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -113,6 +113,8 @@ #include "llrendersphere.h" #include "llskinningutil.h" +#include "llperfstats.h" + #include extern F32 SPEED_ADJUST_MAX; @@ -2544,6 +2546,9 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) LL_INFOS() << "Warning! Idle on dead avatar" << LL_ENDL; return; } + // record time and refresh "tooSlow" status + LLPerfStats::RecordAvatarTime T(getID(), LLPerfStats::StatType_t::RENDER_IDLE); // per avatar "idle" time. + updateTooSlow(); static LLCachedControl disable_all_render_types(gSavedSettings, "DisableAllRenderTypes"); if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)) @@ -8268,6 +8273,94 @@ bool LLVOAvatar::isTooComplex() const return too_complex; } +// use Avatar Render Time as complexity metric +// markARTStale - Mark stale and set the frameupdate to now so that we can wait at least one frame to get a revised number. +void LLVOAvatar::markARTStale() +{ + mARTStale=true; + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); +} + +// Udpate Avatar state based on render time +void LLVOAvatar::updateTooSlow() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + static LLCachedControl alwaysRenderFriends(gSavedSettings, "AlwaysRenderFriends"); + static LLCachedControl allowSelfImpostor(gSavedSettings, "AllowSelfImpostor"); + const auto id = getID(); + + // mTooSlow - Is the avatar flagged as being slow (includes shadow time) + // mTooSlowWithoutShadows - Is the avatar flagged as being slow even with shadows removed. + // mARTStale - the rendertime we have is stale because of an update. We need to force a re-render to re-assess slowness + + if( mARTStale ) + { + if ( LLFrameTimer::getFrameCount() - mLastARTUpdateFrame < 5 ) + { + // LL_INFOS() << this->getFullname() << " marked stale " << LL_ENDL; + // we've not had a chance to update yet (allow a few to be certain a full frame has passed) + return; + } + + mARTStale = false; + mTooSlow = false; + mTooSlowWithoutShadows = false; + // LL_INFOS() << this->getFullname() << " refreshed ART combined = " << mRenderTime << " @ " << mLastARTUpdateFrame << LL_ENDL; + } + + // Either we're not stale or we've updated. + + U64 render_time_raw; + U64 render_geom_time_raw; + + if( !mTooSlow ) + { + // we are fully rendered, so we use the live values + std::lock_guard lock{LLPerfStats::bufferToggleLock}; + render_time_raw = LLPerfStats::StatsRecorder::get(LLPerfStats::ObjType_t::OT_AVATAR, id, LLPerfStats::StatType_t::RENDER_COMBINED); + render_geom_time_raw = LLPerfStats::StatsRecorder::get(LLPerfStats::ObjType_t::OT_AVATAR, id, LLPerfStats::StatType_t::RENDER_GEOMETRY); + } + else + { + // use the cached values. + render_time_raw = mRenderTime; + render_geom_time_raw = mGeomTime; + } + if( (LLPerfStats::renderAvatarMaxART_ns > 0) && + (LLPerfStats::raw_to_ns(render_time_raw) >= LLPerfStats::renderAvatarMaxART_ns) ) + { + if( !mTooSlow ) // if we were previously not slow (with or without shadows.) + { + // if we weren't capped, we are now + mLastARTUpdateFrame = LLFrameTimer::getFrameCount(); + mRenderTime = render_time_raw; + mGeomTime = render_geom_time_raw; + mARTStale = false; + mTooSlow = true; + } + if(!mTooSlowWithoutShadows) // if we were not previously above the full impostor cap + { + bool render_friend_or_exception = ( alwaysRenderFriends && LLAvatarTracker::instance().isBuddy( id ) ) || + ( getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER ); + if( (!isSelf() || allowSelfImpostor) && !render_friend_or_exception ) + { + // Note: slow rendering Friends still get their shadows zapped. + mTooSlowWithoutShadows = (LLPerfStats::raw_to_ns(render_geom_time_raw) >= LLPerfStats::renderAvatarMaxART_ns); + } + } + } + else + { + // LL_INFOS() << this->getFullname() << " ("<< (combined?"combined":"geometry") << ") good render time = " << LLPerfStats::raw_to_ns(render_time_raw) << " vs ("<< LLVOAvatar::sRenderTimeCap_ns << " set @ " << mLastARTUpdateFrame << LL_ENDL; + mTooSlow = false; + mTooSlowWithoutShadows = false; + } + if(mTooSlow) + { + LLPerfStats::tunedAvatars++; // increment the number of avatars that have been tweaked. + } +} + //----------------------------------------------------------------------------- // findMotion() //----------------------------------------------------------------------------- diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index e9c3d48a78..a27327d8a3 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -350,6 +350,18 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; + + // check and return current state relative to limits + // default will test only the geometry (combined=false). + // this allows us to disable shadows separately on complex avatars. + inline bool isTooSlowWithShadows() const {return mTooSlow;}; + inline bool isTooSlowWithoutShadows() const {return mTooSlowWithoutShadows;}; + inline bool isTooSlow(bool combined = false) const + { + return(combined?mTooSlow:mTooSlowWithoutShadows); + } + void updateTooSlow(); + bool isTooComplex() const; bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -369,6 +381,7 @@ public: void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed); void calcMutedAVColor(); + void markARTStale(); protected: LLViewerStats::PhaseMap& getPhases() { return mPhases; } @@ -390,6 +403,15 @@ private: LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; + U32 mLastARTUpdateFrame{0}; + U64 mRenderTime{0}; + U64 mGeomTime{0}; + bool mARTStale{true}; + bool mARTCapped{false}; + // variables to hold "slowness" status + bool mTooSlow{false}; + bool mTooSlowWithoutShadows{false}; + private: LLViewerStats::PhaseMap mPhases; @@ -1145,6 +1167,8 @@ public: // COF version of last appearance message received for this av. S32 mLastUpdateReceivedCOFVersion; + U64 getLastART() const { return mRenderTime; } + /** Diagnostics ** ** *******************************************************************************/ diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f4a938e57d..77d1511dcd 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -88,6 +88,7 @@ #include "llcallstack.h" #include "llsculptidsize.h" #include "llavatarappearancedefines.h" +#include "llperfstats.h" const F32 FORCE_SIMPLE_RENDER_AREA = 512.f; const F32 FORCE_CULL_AREA = 8.f; @@ -5589,6 +5590,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) LL_PROFILE_ZONE_NAMED("rebuildGeom - face list"); //get all the faces into a list + std::unique_ptr ratPtr{}; for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { @@ -5620,6 +5622,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } + if(vobj->isAttachment()) + { + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED),&ratPtr); + } + LLVolume* volume = vobj->getVolume(); if (volume) { @@ -6010,6 +6017,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) U32 buffer_count = 0; + std::unique_ptr ratPtr{}; for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); @@ -6019,6 +6027,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); if (!vobj) continue; + + if (vobj->isAttachment()) + { + trackAttachments( vobj, drawablep->isState(LLDrawable::RIGGED), &ratPtr ); + } if (debugLoggingEnabled("AnimatedObjectsLinkset")) { @@ -6458,10 +6471,16 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 indices_index = 0; U16 index_offset = 0; - while (face_iter < i) + std::unique_ptr ratPtr; + while (face_iter < i) { //update face indices for new buffer facep = *face_iter; + LLViewerObject* vobj = facep->getViewerObject(); + if(vobj && vobj->isAttachment()) + { + trackAttachments(vobj, LLPipeline::sShadowRender, &ratPtr); + } if (buffer.isNull()) { // Bulk allocation failed diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml index bf2623f356..ee88701037 100644 --- a/indra/newview/skins/default/xui/en/floater_performance.xml +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -277,6 +277,52 @@ top="19" right="-20"/> + + + Preferred frame rate + + + Allow automatic adjustments to reach your preferred frame rate (advanced). + + + + diff --git a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml new file mode 100644 index 0000000000..10ac4b98b7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml @@ -0,0 +1,272 @@ + + + + + Back + + + Preferred frame rate + + + + Desired frame rate + + + + + + + Settings affect + + + + + + + + Reducing detail shown on avatars that are far away will improve graphics speed. + + + + + + meters + + + + Choose the distance range that automatic settings will affect. + + + Minimum distance + + + + + Maximum distance + + + + From 81c287f877a48381bfa212ad00fe23aef260ef5f Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 22 Sep 2022 20:34:29 +0300 Subject: [PATCH 02/11] SL-18202 WIP merging autotune contribution and updating UI #2 --- indra/newview/app_settings/settings.xml | 11 ++ indra/newview/llfloaterperformance.cpp | 150 ++++++++++-------- indra/newview/llfloaterperformance.h | 5 +- indra/newview/llperfstats.cpp | 20 +-- indra/newview/llperfstats.h | 2 +- indra/newview/pipeline.cpp | 10 +- .../xui/en/panel_performance_nearby.xml | 24 +-- 7 files changed, 127 insertions(+), 95 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d92632c0a2..b1b971da14 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16820,6 +16820,17 @@ Value 0 + ShowTunedART + + Comment + Show the current render time not the pre-tuning render time in the avatar display. + Persist + 1 + Type + Boolean + Value + 1 + RenderAvatarMaxART Comment diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index 257c0b2b37..afa46db1e3 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -38,6 +38,7 @@ #include "llfloaterreg.h" #include "llnamelistctrl.h" #include "llnotificationsutil.h" +#include "llperfstats.h" #include "llradiogroup.h" #include "llsliderctrl.h" #include "lltextbox.h" @@ -54,6 +55,11 @@ const S32 BAR_LEFT_PAD = 2; const S32 BAR_RIGHT_PAD = 5; const S32 BAR_BOTTOM_PAD = 9; +constexpr auto AvType {LLPerfStats::ObjType_t::OT_AVATAR}; +constexpr auto AttType {LLPerfStats::ObjType_t::OT_ATTACHMENT}; +constexpr auto HudType {LLPerfStats::ObjType_t::OT_HUD}; +constexpr auto SceneType {LLPerfStats::ObjType_t::OT_GENERAL}; + class LLExceptionsContextMenu : public LLListContextMenu { public: @@ -87,7 +93,7 @@ LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) LLFloaterPerformance::~LLFloaterPerformance() { - mComplexityChangedSignal.disconnect(); + mMaxARTChangedSignal.disconnect(); delete mContextMenu; delete mUpdateTimer; } @@ -135,11 +141,15 @@ BOOL LLFloaterPerformance::postBuild() mNearbyList = mNearbyPanel->getChild("nearby_list"); mNearbyList->setRightMouseDownCallback(boost::bind(&LLFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); - updateComplexityText(); - mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateComplexityText, this)); - mNearbyPanel->getChild("IndirectMaxComplexity")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxComplexity, this)); + mMaxARTChangedSignal = gSavedSettings.getControl("RenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + mNearbyPanel->getChild("RenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); - LLAvatarComplexityControls::setIndirectMaxArc(); + // store the current setting as the users desired reflection detail and DD + gSavedSettings.setS32("UserTargetReflections", LLPipeline::RenderReflectionDetail); + if(!LLPerfStats::tunables.userAutoTuneEnabled) + { + gSavedSettings.setF32("AutoTuneRenderFarClipTarget", LLPipeline::RenderFarClip); + } return TRUE; } @@ -224,16 +234,13 @@ void LLFloaterPerformance::populateHUDList() hud_complexity_list_t::iterator iter = complexity_list.begin(); hud_complexity_list_t::iterator end = complexity_list.end(); - U32 max_complexity = 0; - for (; iter != end; ++iter) - { - max_complexity = llmax(max_complexity, (*iter).objectsCost); - } - + auto huds_max_render_time_raw = LLPerfStats::StatsRecorder::getMax(HudType, LLPerfStats::StatType_t::RENDER_GEOMETRY); for (iter = complexity_list.begin(); iter != end; ++iter) { - LLHUDComplexity hud_object_complexity = *iter; - S32 obj_cost_short = llmax((S32)hud_object_complexity.objectsCost / 1000, 1); + LLHUDComplexity hud_object_complexity = *iter; + + auto hud_render_time_raw = LLPerfStats::StatsRecorder::get(HudType, hud_object_complexity.objectId, LLPerfStats::StatType_t::RENDER_GEOMETRY); + LLSD item; item["special_id"] = hud_object_complexity.objectId; item["target"] = LLNameListCtrl::SPECIAL; @@ -241,14 +248,14 @@ void LLFloaterPerformance::populateHUDList() row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; + value["ratio"] = (F32)hud_render_time_raw / huds_max_render_time_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = std::to_string(obj_cost_short); + row[1]["value"] = llformat( "%.f",LLPerfStats::raw_to_us(hud_render_time_raw) ); row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -283,45 +290,46 @@ void LLFloaterPerformance::populateObjectList() object_complexity_list_t::iterator iter = complexity_list.begin(); object_complexity_list_t::iterator end = complexity_list.end(); - U32 max_complexity = 0; - for (; iter != end; ++iter) + // for consistency we lock the buffer while we build the list. In theory this is uncontended as the buffer should only toggle on end of frame { - max_complexity = llmax(max_complexity, (*iter).objectCost); - } + std::lock_guard guard{ LLPerfStats::bufferToggleLock }; + auto att_max_render_time_raw = LLPerfStats::StatsRecorder::getMax(AttType, LLPerfStats::StatType_t::RENDER_COMBINED); - for (iter = complexity_list.begin(); iter != end; ++iter) - { - LLObjectComplexity object_complexity = *iter; - S32 obj_cost_short = llmax((S32)object_complexity.objectCost / 1000, 1); - LLSD item; - item["special_id"] = object_complexity.objectId; - item["target"] = LLNameListCtrl::SPECIAL; - LLSD& row = item["columns"]; - row[0]["column"] = "complex_visual"; - row[0]["type"] = "bar"; - LLSD& value = row[0]["value"]; - value["ratio"] = (F32)obj_cost_short / max_complexity * 1000; - value["bottom"] = BAR_BOTTOM_PAD; - value["left_pad"] = BAR_LEFT_PAD; - value["right_pad"] = BAR_RIGHT_PAD; - - row[1]["column"] = "complex_value"; - row[1]["type"] = "text"; - row[1]["value"] = std::to_string(obj_cost_short); - row[1]["font"]["name"] = "SANSSERIF"; - - row[2]["column"] = "name"; - row[2]["type"] = "text"; - row[2]["value"] = object_complexity.objectName; - row[2]["font"]["name"] = "SANSSERIF"; - - LLScrollListItem* obj = mObjectList->addElement(item); - if (obj) + for (iter = complexity_list.begin(); iter != end; ++iter) { - LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); - if (value_text) + LLObjectComplexity object_complexity = *iter; + + auto attach_render_time_raw = LLPerfStats::StatsRecorder::get(AttType, object_complexity.objectId, LLPerfStats::StatType_t::RENDER_COMBINED); + LLSD item; + item["special_id"] = object_complexity.objectId; + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "complex_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = ((F32)attach_render_time_raw) / att_max_render_time_raw; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "complex_value"; + row[1]["type"] = "text"; + row[1]["value"] = llformat("%.f", LLPerfStats::raw_to_us(attach_render_time_raw)); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "name"; + row[2]["type"] = "text"; + row[2]["value"] = object_complexity.objectName; + row[2]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mObjectList->addElement(item); + if (obj) { - value_text->setAlignment(LLFontGL::HCENTER); + LLScrollListText* value_text = dynamic_cast(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } } } } @@ -332,6 +340,7 @@ void LLFloaterPerformance::populateObjectList() void LLFloaterPerformance::populateNearbyList() { + static LLCachedControl showTunedART(gSavedSettings, "ShowTunedART"); S32 prev_pos = mNearbyList->getScrollPos(); LLUUID prev_selected_id = mNearbyList->getStringUUIDSelectedItem(); mNearbyList->clearRows(); @@ -342,26 +351,44 @@ void LLFloaterPerformance::populateNearbyList() mNearbyMaxComplexity = LLWorld::getInstance()->getNearbyAvatarsAndCompl(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); + + LLPerfStats::bufferToggleLock.lock(); + auto av_render_max_raw = LLPerfStats::StatsRecorder::getMax(AvType, LLPerfStats::StatType_t::RENDER_COMBINED); + LLPerfStats::bufferToggleLock.unlock(); + while (char_iter != valid_nearby_avs.end()) { LLVOAvatar* avatar = dynamic_cast(*char_iter); if (avatar && (LLVOAvatar::AOA_INVISIBLE != avatar->getOverallAppearance())) { - S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1);; + LLPerfStats::bufferToggleLock.lock(); + auto render_av_raw = LLPerfStats::StatsRecorder::get(AvType, avatar->getID(),LLPerfStats::StatType_t::RENDER_COMBINED); + LLPerfStats::bufferToggleLock.unlock(); + + auto is_slow = avatar->isTooSlowWithShadows(); LLSD item; item["id"] = avatar->getID(); LLSD& row = item["columns"]; row[0]["column"] = "complex_visual"; row[0]["type"] = "bar"; LLSD& value = row[0]["value"]; - value["ratio"] = (F32)complexity_short / mNearbyMaxComplexity * 1000; + // The ratio used in the bar is the current cost, as soon as we take action this changes so we keep the + // pre-tune value for the numerical column and sorting. + value["ratio"] = (double)render_av_raw / av_render_max_raw; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; row[1]["column"] = "complex_value"; row[1]["type"] = "text"; - row[1]["value"] = std::to_string(complexity_short); + if (is_slow && !showTunedART) + { + row[1]["value"] = llformat( "%.f", LLPerfStats::raw_to_us( avatar->getLastART() ) ); + } + else + { + row[1]["value"] = llformat( "%.f", LLPerfStats::raw_to_us( render_av_raw ) ); + } row[1]["font"]["name"] = "SANSSERIF"; row[2]["column"] = "name"; @@ -387,7 +414,7 @@ void LLFloaterPerformance::populateNearbyList() else { std::string color = "white"; - if (LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) + if (is_slow || LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) { color = "LabelDisabledColor"; LLScrollListBar* bar = dynamic_cast(av_item->getColumn(0)); @@ -462,18 +489,11 @@ void LLFloaterPerformance::onClickExceptions() LLFloaterReg::showInstance("avatar_render_settings"); } -void LLFloaterPerformance::updateMaxComplexity() +void LLFloaterPerformance::updateMaxRenderTime() { - LLAvatarComplexityControls::updateMax( - mNearbyPanel->getChild("IndirectMaxComplexity"), - mNearbyPanel->getChild("IndirectMaxComplexityText"), - true); -} - -void LLFloaterPerformance::updateComplexityText() -{ - LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), - mNearbyPanel->getChild("IndirectMaxComplexityText", true), + LLAvatarComplexityControls::updateMaxRenderTime( + mNearbyPanel->getChild("RenderAvatarMaxART"), + mNearbyPanel->getChild("RenderAvatarMaxARTText"), true); } diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index 01b65365da..a79da7460b 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -66,8 +66,7 @@ private: void onClickShadows(); void onClickAdvancedLighting(); - void updateMaxComplexity(); - void updateComplexityText(); + void updateMaxRenderTime(); static void changeQualityLevel(const std::string& notif); @@ -87,7 +86,7 @@ private: S32 mNearbyMaxComplexity; - boost::signals2::connection mComplexityChangedSignal; + boost::signals2::connection mMaxARTChangedSignal; }; #endif // LL_LLFLOATERPERFORMANCE_H diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp index 16d0df0245..1a0e5842e2 100644 --- a/indra/newview/llperfstats.cpp +++ b/indra/newview/llperfstats.cpp @@ -76,15 +76,15 @@ namespace LLPerfStats void Tunables::updateRenderCostLimitFromSettings() { assert_main_thread(); - const auto newval = gSavedSettings.getF32("RenderAvatarMaxART"); - if(newval < log10(LLPerfStats::ART_UNLIMITED_NANOS/1000)) - { - LLPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; - } - else - { - LLPerfStats::renderAvatarMaxART_ns = 0; - }; + const auto newval = gSavedSettings.getF32("RenderAvatarMaxART"); + if(newval < log10(LLPerfStats::ART_UNLIMITED_NANOS/1000)) + { + LLPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; + } + else + { + LLPerfStats::renderAvatarMaxART_ns = 0; + } } // static @@ -466,4 +466,4 @@ namespace LLPerfStats } } } -} \ No newline at end of file +} diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h index 1e867f5ef1..961594f18c 100644 --- a/indra/newview/llperfstats.h +++ b/indra/newview/llperfstats.h @@ -451,4 +451,4 @@ static inline void trackAttachments(const T * vobj, bool isRigged, RATptr* ratPt return; }; -#endif \ No newline at end of file +#endif diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 7044d27430..2a059e5db4 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -10853,10 +10853,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; - pushRenderTypeMask(); - - if (visually_muted || too_complex) - { + bool too_slow = avatar->isTooSlowWithoutShadows(); // only if we really have to do we imposter. + + pushRenderTypeMask(); + + if ( !too_slow && ( visually_muted || too_complex ) ) + { // only show jelly doll geometry andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml index e1aef13717..e80bf592e4 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -57,22 +57,22 @@ Hide the most complex avatars to boost speed. + width="490"> - 0 + no limit Date: Fri, 23 Sep 2022 16:49:47 +0300 Subject: [PATCH 03/11] SL-18202 remove old autofps --- indra/newview/app_settings/settings.xml | 57 ------- indra/newview/llagent.cpp | 2 - indra/newview/llfloaterperformance.cpp | 16 +- indra/newview/llfloaterpreference.cpp | 18 --- indra/newview/llfloaterpreference.h | 2 - .../llfloaterpreferencesgraphicsadvanced.cpp | 5 - indra/newview/llstartup.cpp | 4 - indra/newview/llviewerdisplay.cpp | 2 - indra/newview/pipeline.cpp | 143 +----------------- indra/newview/pipeline.h | 7 - .../floater_preferences_graphics_advanced.xml | 4 - .../xui/en/panel_performance_preferences.xml | 37 +---- .../xui/en/panel_preferences_graphics1.xml | 34 +---- 13 files changed, 10 insertions(+), 321 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b1b971da14..bf72492a28 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16719,63 +16719,6 @@ Value 0 - AutoFPS - - Comment - - Allow dynamic adjustment of graphics preferences - - Persist - 1 - Type - Boolean - Value - 0 - - AutoAdjustmentTimeout - - Comment - Time before next iteration of automatic adjustments - Persist - 1 - Type - F32 - Value - 5 - - InitialAdjustmentTimeout - - Comment - Time before first iteration of automatic adjustments after login to the world, teleporting, maximizing Viewer etc. - Persist - 1 - Type - F32 - Value - 10 - - AutoFPSLowerBoundary - - Comment - FPS lower boundary when automatic adjustments are occured to reduce graphics quality to increase FPS - Persist - 1 - Type - S32 - Value - 30 - - AutoFPSUpperBoundary - - Comment - FPS upper boundary when automatic adjustments are occured to increase graphics quality - Persist - 1 - Type - S32 - Value - 50 - TargetFPS Comment diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 78c726043e..8a6186123e 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -4097,7 +4097,6 @@ void LLAgent::handleTeleportFinished() } } - gPipeline.setAdjustmentTimerExpiry(gSavedSettings.getF32("InitialAdjustmentTimeout")); } void LLAgent::handleTeleportFailed() @@ -4130,7 +4129,6 @@ void LLAgent::handleTeleportFailed() mTPNeedsNeabyChatSeparator = false; - gPipeline.setAdjustmentTimerExpiry(gSavedSettings.getF32("InitialAdjustmentTimeout")); } /*static*/ diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index afa46db1e3..da1670c15e 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -58,7 +58,6 @@ const S32 BAR_BOTTOM_PAD = 9; constexpr auto AvType {LLPerfStats::ObjType_t::OT_AVATAR}; constexpr auto AttType {LLPerfStats::ObjType_t::OT_ATTACHMENT}; constexpr auto HudType {LLPerfStats::ObjType_t::OT_HUD}; -constexpr auto SceneType {LLPerfStats::ObjType_t::OT_GENERAL}; class LLExceptionsContextMenu : public LLListContextMenu { @@ -87,8 +86,6 @@ LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) mNearbyMaxComplexity(0) { mContextMenu = new LLExceptionsContextMenu(this); - - mCommitCallbackRegistrar.add("Pref.AutoAdjustWarning", boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); } LLFloaterPerformance::~LLFloaterPerformance() @@ -133,7 +130,6 @@ BOOL LLFloaterPerformance::postBuild() mSettingsPanel->getChild("graphics_quality")->setCommitCallback(boost::bind(&LLFloaterPerformance::onChangeQuality, this, _2)); mSettingsPanel->getChild("advanced_lighting_model")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::onClickAdvancedLighting, this)); mSettingsPanel->getChild("ShadowDetail")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::onClickShadows, this)); - mSettingsPanel->getChild("Reflections")->setMouseDownCallback(boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); mNearbyPanel->getChild("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); mNearbyPanel->getChild("hide_avatars")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickHideAvatars, this)); @@ -623,16 +619,10 @@ void LLFloaterPerformance::onClickAdvancedLighting() void LLFloaterPerformance::onClickShadows() { - if (gSavedSettings.getBOOL("AutoFPS")) + if (!is_ALM_available() || !gSavedSettings.getBOOL("RenderDeferred")) { - LLFloaterPreference::showAutoAdjustWarning(); - } - else - { - if (!is_ALM_available() || !gSavedSettings.getBOOL("RenderDeferred")) - { - changeQualityLevel("ShadowsConfirm"); - } + changeQualityLevel("ShadowsConfirm"); } + } // EOF diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 77bf03852f..e9d5a8e02c 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -305,7 +305,6 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); - mCommitCallbackRegistrar.add("Pref.AutoAdjustWarning", boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); sSkin = gSavedSettings.getString("SkinCurrent"); @@ -1800,23 +1799,6 @@ void LLFloaterPreference::updateSearchableItems() mSearchDataDirty = true; } -void LLFloaterPreference::showAutoAdjustWarning() -{ - static LLCachedControl use_auto_adjust(gSavedSettings,"AutoFPS"); - if (use_auto_adjust) - { - LLNotificationsUtil::add("AutoFPSConfirmDisable", LLSD(), LLSD(), - [](const LLSD¬if, const LLSD&resp) - { - S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); - if (opt == 0) - { - gSavedSettings.setBOOL("AutoFPS", FALSE); - } - }); - } -} - void LLFloaterPreference::applyUIColor(LLUICtrl* ctrl, const LLSD& param) { LLUIColorTable::instance().setColor(param.asString(), LLColor4(ctrl->getValue())); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index de4e3cd886..94aac56506 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -109,8 +109,6 @@ public: void updateClickActionViews(); void updateSearchableItems(); - static void showAutoAdjustWarning(); - void onBtnOK(const LLSD& userdata); void onBtnCancel(const LLSD& userdata); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index ba2fd6eef2..4cfc91f88e 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -49,8 +49,6 @@ LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const L mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); - mCommitCallbackRegistrar.add("Pref.AutoAdjustWarning", boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); - mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2)); mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); @@ -81,9 +79,6 @@ BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateComplexityText, this)); - getChild("ShadowDetail")->setMouseDownCallback(boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); - getChild("Reflections")->setMouseDownCallback(boost::bind(&LLFloaterPreference::showAutoAdjustWarning)); - return TRUE; } diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9cbd56ee7f..00c2fca7df 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2254,10 +2254,6 @@ bool idle_startup() if (STATE_CLEANUP == LLStartUp::getStartupState()) { - if (gAgent.isFirstLogin()) - { - gSavedSettings.setBOOL("AutoFPS", TRUE); - } set_startup_status(1.0, "", ""); display_startup(); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index fa026c2888..a1773ae8d5 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1024,8 +1024,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gPipeline.clearReferences(); gPipeline.rebuildGroups(); - - gPipeline.autoAdjustSettings(); } LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 2a059e5db4..3110a1cbe5 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -409,8 +409,7 @@ LLPipeline::LLPipeline() : mLightMovingMask(0), mLightingDetail(0), mScreenWidth(0), - mScreenHeight(0), - mUpdateTimer(new LLTimer()) + mScreenHeight(0) { mNoiseMap = 0; mTrueNoiseMap = 0; @@ -615,12 +614,10 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("CameraDoFResScale"); connectRefreshCachedSettingsSafe("RenderAutoHideSurfaceAreaLimit"); gSavedSettings.getControl("RenderAutoHideSurfaceAreaLimit")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); - gSavedSettings.getControl("AutoFPS")->getCommitSignal()->connect(boost::bind(&LLPipeline::onToggleAutoFPS)); } LLPipeline::~LLPipeline() { - delete mUpdateTimer; } void LLPipeline::cleanup() @@ -11522,141 +11519,3 @@ void LLPipeline::handleShadowDetailChanged() } } -const F32 MIN_DRAW_DISTANCE = 64; -const F32 MAX_DRAW_DISTANCE = 256; - -void update_far_clip(F32 fps_dif) -{ - F32 DIST_PER_FRAME_DIF = 16; - - F32 new_far_clip = llclamp(LLPipeline::RenderFarClip - llmin(fps_dif * DIST_PER_FRAME_DIF, (F32)128), MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); - gSavedSettings.setF32("RenderFarClip", new_far_clip); -} - -void update_max_non_impostors(F32 fps_dif, S32 max_avatars) -{ - const F32 IMPOSTORS_PER_FRAME_DIF = 0.5; - - U32 new_non_imp = (U32)llclamp((S32)(LLVOAvatar::sMaxNonImpostors - llmin((S32)(fps_dif / IMPOSTORS_PER_FRAME_DIF), 10)), 1, max_avatars); - gSavedSettings.setU32("RenderAvatarMaxNonImpostors", new_non_imp); -} - -void LLPipeline::autoAdjustSettings() -{ - static LLCachedControl use_auto_adjustment(gSavedSettings,"AutoFPS"); - if (!use_auto_adjustment) - { - return; - } - - if (LLStartUp::getStartupState() < STATE_STARTED || LLApp::isExiting()) - { - return; - } - - static LLCachedControl adjustment_timeout(gSavedSettings, "AutoAdjustmentTimeout"); - static LLCachedControl initial_adjustment_timeout(gSavedSettings, "InitialAdjustmentTimeout"); - - static LLCachedControl fps_lower_boundary(gSavedSettings, "AutoFPSLowerBoundary"); - static LLCachedControl fps_upper_boundary(gSavedSettings, "AutoFPSUpperBoundary"); - - if (gViewerWindow && gViewerWindow->getWindow()->getVisible() - && gFocusMgr.getAppHasFocus() && !gTeleportDisplay) - { - static bool is_init = false; - if (!is_init) - { - //wait for FPS to stabilize after login in-world - mUpdateTimer->setTimerExpirySec((F32)initial_adjustment_timeout); - is_init = true; - } - if (mUpdateTimer->hasExpired()) - { - mUpdateTimer->setTimerExpirySec((F32)adjustment_timeout); - - const S32 FPS_STAT_PERIODS = 50; - S32 fps = (S32)llround(LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, FPS_STAT_PERIODS)); - if (fps < fps_lower_boundary) - { - S32 fps_dif = fps_lower_boundary - fps; - - if (sWaterReflections && RenderReflectionDetail > WATER_REFLECT_NONE_WATER_OPAQUE) - { - S32 reflection_detail = llclamp(RenderReflectionDetail - 1, WATER_REFLECT_NONE_WATER_OPAQUE, WATER_REFLECT_MINIMAL); - gSavedSettings.setS32("RenderReflectionDetail", reflection_detail); - return; - } - - if (LLPipeline::sRenderDeferred && RenderShadowDetail > 0 && RenderShadowSplits > 0) - { - S32 shadow_splits = llclamp(RenderShadowSplits - 1, 0, 3); - gSavedSettings.setS32("RenderShadowSplits", shadow_splits); - return; - } - - if (RenderFarClip > MIN_DRAW_DISTANCE) - { - update_far_clip(fps_dif); - } - - std::vector valid_nearby_avs; - LLWorld::getInstance()->getNearbyAvatarsAndCompl(valid_nearby_avs); - - if (valid_nearby_avs.size() > 1 && LLVOAvatar::sMaxNonImpostors > 1) - { - update_max_non_impostors(fps_dif, valid_nearby_avs.size()); - } - } - else if (fps > fps_upper_boundary) - { - S32 fps_dif = fps_upper_boundary - fps; - - std::vector valid_nearby_avs; - LLWorld::getInstance()->getNearbyAvatarsAndCompl(valid_nearby_avs); - if (valid_nearby_avs.size() > 1 && (LLVOAvatar::sMaxNonImpostors < valid_nearby_avs.size())) - { - update_max_non_impostors(fps_dif, valid_nearby_avs.size()); - return; - } - - if (RenderFarClip < MAX_DRAW_DISTANCE) - { - update_far_clip(fps_dif); - } - - if (LLPipeline::sRenderDeferred && RenderShadowDetail > 0 && RenderShadowSplits < 3) - { - S32 shadow_splits = llclamp(RenderShadowSplits + 1, 0, 3); - gSavedSettings.setS32("RenderShadowSplits", shadow_splits); - return; - } - - if (sWaterReflections && RenderReflectionDetail < WATER_REFLECT_MINIMAL) - { - S32 reflection_detail = llclamp(RenderReflectionDetail + 1, WATER_REFLECT_NONE_WATER_OPAQUE, WATER_REFLECT_MINIMAL); - gSavedSettings.setS32("RenderReflectionDetail", reflection_detail); - } - } - } - } - else - { - //wait for FPS to stabilize if the window was minimized or not focused before - mUpdateTimer->setTimerExpirySec((F32)initial_adjustment_timeout); - } -} - -void LLPipeline::setAdjustmentTimerExpiry(F32 expiration) -{ - mUpdateTimer->setTimerExpirySec(expiration); -} - -void LLPipeline::onToggleAutoFPS() -{ - if (!gSavedSettings.getBOOL("AutoFPS")) - { - //reset the number of shadow map splits rendered, when disabling auto-fps - //probably should be removed, if we'll have actual UI control for this setting - gSavedSettings.setS32("RenderShadowSplits", 3); - } -} diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index bdd498abff..584d32a767 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -418,8 +418,6 @@ public: static void updateRenderDeferred(); static void refreshCachedSettings(); - static void onToggleAutoFPS(); - void addDebugBlip(const LLVector3& position, const LLColor4& color); void hidePermanentObjects( std::vector& restoreList ); @@ -429,9 +427,6 @@ public: void restoreHiddenObject( const LLUUID& id ); void handleShadowDetailChanged(); - void autoAdjustSettings(); - void setAdjustmentTimerExpiry(F32 expiration); - private: void unloadShaders(); void addToQuickLookup( LLDrawPool* new_poolp ); @@ -724,8 +719,6 @@ protected: U64 mOldRenderDebugMask; std::stack mRenderDebugFeatureStack; - LLTimer* mUpdateTimer; - ///////////////////////////////////////////// // // 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 154c8b7909..9da6ec093b 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 @@ -40,8 +40,6 @@ name="DrawDistance" top_delta="16" width="330"> - - - - Automatic settings - - - - - diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 93cb3ea9c8..5aff7a5127 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -30,28 +30,7 @@ width="120"> (None) - - - + Quality & speed: @@ -238,10 +217,7 @@ max_val="512" name="DrawDistance" top_delta="40" - width="330"> - - + width="330" /> - + Date: Tue, 27 Sep 2022 19:35:49 +0300 Subject: [PATCH 04/11] SL-18202 impostor too slow avatars and add autotune settings button to Preference --- indra/newview/llfloaterperformance.cpp | 5 +++++ indra/newview/llfloaterperformance.h | 1 + indra/newview/llfloaterpreference.cpp | 15 ++++++++++++++- indra/newview/llfloaterpreference.h | 1 + indra/newview/llviewerpartsim.cpp | 2 +- indra/newview/llvoavatar.cpp | 8 ++++---- indra/newview/pipeline.cpp | 8 ++++---- .../xui/en/panel_preferences_graphics1.xml | 14 +++++++++++++- 8 files changed, 43 insertions(+), 11 deletions(-) diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index da1670c15e..e79e9d19b1 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -170,6 +170,11 @@ void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) } } +void LLFloaterPerformance::showAutoadjustmentsPanel() +{ + showSelectedPanel(mAutoadjustmentsPanel); +} + void LLFloaterPerformance::draw() { if (mUpdateTimer->hasExpired()) diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h index a79da7460b..09bcd18bb5 100644 --- a/indra/newview/llfloaterperformance.h +++ b/indra/newview/llfloaterperformance.h @@ -44,6 +44,7 @@ public: void showSelectedPanel(LLPanel* selected_panel); void showMainPanel(); void hidePanels(); + void showAutoadjustmentsPanel(); void detachItem(const LLUUID& item_id); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index e9d5a8e02c..179f70a4a7 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -51,6 +51,7 @@ #include "llfloaterabout.h" #include "llfavoritesbar.h" #include "llfloaterpreferencesgraphicsadvanced.h" +#include "llfloaterperformance.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" #include "llkeyboard.h" @@ -287,6 +288,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); + mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); @@ -726,13 +728,15 @@ void LLFloaterPreference::onOpen(const LLSD& key) LLButton* save_btn = findChild("PrefSaveButton"); LLButton* delete_btn = findChild("PrefDeleteButton"); LLButton* exceptions_btn = findChild("RenderExceptionsButton"); + LLButton* auto_adjustments_btn = findChild("AutoAdjustmentsButton"); - if (load_btn && save_btn && delete_btn && exceptions_btn) + if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) { load_btn->setEnabled(started); save_btn->setEnabled(started); delete_btn->setEnabled(started); exceptions_btn->setEnabled(started); + auto_adjustments_btn->setEnabled(started); } collectSearchableItems(); @@ -1655,6 +1659,15 @@ void LLFloaterPreference::onClickRenderExceptions() LLFloaterReg::showInstance("avatar_render_settings"); } +void LLFloaterPreference::onClickAutoAdjustments() +{ + LLFloaterPerformance* performance_floater = LLFloaterReg::showTypedInstance("performance"); + if (performance_floater) + { + performance_floater->showAutoadjustmentsPanel(); + } +} + void LLFloaterPreference::onClickAdvanced() { LLFloaterReg::showInstance("prefs_graphics_advanced"); diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 94aac56506..1079b41000 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -185,6 +185,7 @@ public: void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); + void onClickAutoAdjustments(); void onClickAdvanced(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index e5265f1dcd..a440f3232a 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -716,7 +716,7 @@ void LLViewerPartSim::updateSimulation() if (upd && vobj && (vobj->getPCode() == LL_PCODE_VOLUME)) { - if(vobj->getAvatar() && vobj->getAvatar()->isTooComplex()) + if(vobj->getAvatar() && vobj->getAvatar()->isTooComplex() && vobj->getAvatar()->isTooSlowWithShadows()) { upd = FALSE; } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 1a71780a88..976b69502f 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3136,7 +3136,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() LLPartData::LL_PART_TARGET_POS_MASK ); // do not generate particles for dummy or overly-complex avatars - if (!mIsDummy && !isTooComplex()) + if (!mIsDummy && !isTooComplex() && !isTooSlowWithShadows()) { setParticleSource(particle_parameters, getID()); } @@ -3717,7 +3717,7 @@ bool LLVOAvatar::isVisuallyMuted() } else { - muted = isTooComplex(); + muted = isTooComplex() || isTooSlowWithShadows(); } } @@ -11174,7 +11174,7 @@ LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const { // Always want to see this AV as an impostor result = AOA_JELLYDOLL; } - else if (isTooComplex()) + else if (isTooComplex() || isTooSlowWithShadows()) { result = AOA_JELLYDOLL; } @@ -11201,7 +11201,7 @@ void LLVOAvatar::calcMutedAVColor() new_color = LLColor4::grey4; change_msg = " blocked: color is grey4"; } - else if (!isTooComplex()) + else if (!isTooComplex() && !isTooSlowWithShadows()) { new_color = LLColor4::white; change_msg = " simple imposter "; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 3110a1cbe5..ba5e35fd3e 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -132,7 +132,7 @@ // NOTE: Keep in sync with indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml // NOTE: Unused consts are commented out since some compilers (on macOS) may complain about unused variables. - const S32 WATER_REFLECT_NONE_WATER_OPAQUE = -2; +// const S32 WATER_REFLECT_NONE_WATER_OPAQUE = -2; const S32 WATER_REFLECT_NONE_WATER_TRANSPARENT = -1; const S32 WATER_REFLECT_MINIMAL = 0; // const S32 WATER_REFLECT_TERRAIN = 1; @@ -5993,7 +5993,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) LLDrawable* drawable = light->drawable; const LLViewerObject *vobj = light->drawable->getVObj(); if(vobj && vobj->getAvatar() - && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList()) + && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList() || vobj->getAvatar()->isTooSlowWithShadows()) ) { drawable->clearState(LLDrawable::NEARBY_LIGHT); @@ -6072,7 +6072,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) continue; } LLVOAvatar * av = light->getAvatar(); - if (av && (av->isTooComplex() || av->isInMuteList())) + if (av && (av->isTooComplex() || av->isInMuteList() || av->isTooSlowWithShadows())) { // avatars that are already in the list will be removed by removeMutedAVsLights continue; @@ -10850,7 +10850,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; - bool too_slow = avatar->isTooSlowWithoutShadows(); // only if we really have to do we imposter. + bool too_slow = avatar->isTooSlowWithShadows(); pushRenderTypeMask(); diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 5aff7a5127..ad02df3087 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -258,6 +258,18 @@ + + Date: Wed, 28 Sep 2022 14:16:16 +0300 Subject: [PATCH 05/11] SL-18248 Move frame breakdown stats to 'Scene loading statistics' floater --- doc/contributions.txt | 1 + indra/newview/llviewerstats.cpp | 91 +++++++++++++++++++ .../xui/en/floater_scene_load_stats.xml | 53 +++++++++++ 3 files changed, 145 insertions(+) diff --git a/doc/contributions.txt b/doc/contributions.txt index 2c1e5487ce..e059f3bb38 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -281,6 +281,7 @@ Beq Janus SL-11300 SL-15709 SL-16021 + SL-18202 Beth Walcher Bezilon Kasei Biancaluce Robbiani diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index a420de98f5..0045dcb547 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -58,6 +58,7 @@ #include "llfeaturemanager.h" #include "llviewernetwork.h" #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llperfstats.h" #include "llsdserialize.h" #include "llsdutil.h" #include "llcorehttputil.h" @@ -208,6 +209,13 @@ LLTrace::EventStatHandle AVATAR_EDIT_TIME("avataredittime", "Second LLTrace::EventStatHandle > OBJECT_CACHE_HIT_RATE("object_cache_hits"); LLTrace::EventStatHandle TEXTURE_FETCH_TIME("texture_fetch_time"); + +LLTrace::SampleStatHandle > SCENERY_FRAME_PCT("scenery_frame_pct"); +LLTrace::SampleStatHandle > AVATAR_FRAME_PCT("avatar_frame_pct"); +LLTrace::SampleStatHandle > HUDS_FRAME_PCT("huds_frame_pct"); +LLTrace::SampleStatHandle > UI_FRAME_PCT("ui_frame_pct"); +LLTrace::SampleStatHandle > SWAP_FRAME_PCT("swap_frame_pct"); +LLTrace::SampleStatHandle > IDLE_FRAME_PCT("idle_frame_pct"); } LLViewerStats::LLViewerStats() @@ -414,6 +422,89 @@ void update_statistics() texture_stats_timer.reset(); } } + + if (LLFloaterReg::instanceVisible("scene_load_stats")) + { + static const F32 perf_stats_freq = 1; + static LLFrameTimer perf_stats_timer; + if (perf_stats_timer.getElapsedTimeF32() >= perf_stats_freq) + { + LLStringUtil::format_map_t args; + LLPerfStats::bufferToggleLock.lock(); // prevent toggle for a moment + + auto tot_frame_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = LLPerfStats::StatsRecorder::getSum(LLPerfStats::ObjType_t::OT_AVATAR, LLPerfStats::StatType_t::RENDER_COMBINED); + // cumulative avatar render specific time (a bit arbitrary as the processing is too.) + // auto tot_av_idle_time_raw = LLPerfStats::StatsRecorder::getSum(AvType, LLPerfStats::StatType_t::RENDER_IDLE); + // auto tot_avatar_render_time_raw = tot_avatar_time_raw - tot_av_idle_time_raw; + // the time spent this frame on the "display()" call. Treated as "tot time rendering" + auto tot_render_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_DISPLAY); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); + // time spent on UI + auto tot_ui_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_UI); + // cumulative time spent rendering HUDS + auto tot_huds_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_HUDS); + // "idle" time. This is the time spent in the idle poll section of the main loop + auto tot_idle_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_IDLE); + // similar to sleep time, induced by FPS limit + //auto tot_limit_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FPSLIMIT); + // swap time is time spent in swap buffer + auto tot_swap_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SWAP); + + LLPerfStats::bufferToggleLock.unlock(); + + auto tot_frame_time_ns = LLPerfStats::raw_to_ns(tot_frame_time_raw); + auto tot_avatar_time_ns = LLPerfStats::raw_to_ns(tot_avatar_time_raw); + auto tot_huds_time_ns = LLPerfStats::raw_to_ns(tot_huds_time_raw); + // UI time includes HUD time so dedut that before we calc percentages + auto tot_ui_time_ns = LLPerfStats::raw_to_ns(tot_ui_time_raw - tot_huds_time_raw); + + // auto tot_sleep_time_ns = LLPerfStats::raw_to_ns( tot_sleep_time_raw ); + // auto tot_limit_time_ns = LLPerfStats::raw_to_ns( tot_limit_time_raw ); + + // auto tot_render_time_ns = LLPerfStats::raw_to_ns( tot_render_time_raw ); + auto tot_idle_time_ns = LLPerfStats::raw_to_ns(tot_idle_time_raw); + auto tot_swap_time_ns = LLPerfStats::raw_to_ns(tot_swap_time_raw); + auto tot_scene_time_ns = LLPerfStats::raw_to_ns(tot_render_time_raw - tot_avatar_time_raw - tot_swap_time_raw - tot_ui_time_raw); + // auto tot_overhead_time_ns = LLPerfStats::raw_to_ns( tot_frame_time_raw - tot_render_time_raw - tot_idle_time_raw ); + + // // remove time spent sleeping for fps limit or out of focus. + // tot_frame_time_ns -= tot_limit_time_ns; + // tot_frame_time_ns -= tot_sleep_time_ns; + + if (tot_frame_time_ns != 0) + { + auto pct_avatar_time = (tot_avatar_time_ns * 100) / tot_frame_time_ns; + auto pct_huds_time = (tot_huds_time_ns * 100) / tot_frame_time_ns; + auto pct_ui_time = (tot_ui_time_ns * 100) / tot_frame_time_ns; + auto pct_idle_time = (tot_idle_time_ns * 100) / tot_frame_time_ns; + auto pct_swap_time = (tot_swap_time_ns * 100) / tot_frame_time_ns; + auto pct_scene_render_time = (tot_scene_time_ns * 100) / tot_frame_time_ns; + pct_avatar_time = llclamp(pct_avatar_time, 0., 100.); + pct_huds_time = llclamp(pct_huds_time, 0., 100.); + pct_ui_time = llclamp(pct_ui_time, 0., 100.); + pct_idle_time = llclamp(pct_idle_time, 0., 100.); + pct_swap_time = llclamp(pct_swap_time, 0., 100.); + pct_scene_render_time = llclamp(pct_scene_render_time, 0., 100.); + if (tot_sleep_time_raw == 0) + { + sample(LLStatViewer::SCENERY_FRAME_PCT, (U32)llround(pct_scene_render_time)); + sample(LLStatViewer::AVATAR_FRAME_PCT, (U32)llround(pct_avatar_time)); + sample(LLStatViewer::HUDS_FRAME_PCT, (U32)llround(pct_huds_time)); + sample(LLStatViewer::UI_FRAME_PCT, (U32)llround(pct_ui_time)); + sample(LLStatViewer::SWAP_FRAME_PCT, (U32)llround(pct_swap_time)); + sample(LLStatViewer::IDLE_FRAME_PCT, (U32)llround(pct_idle_time)); + } + } + else + { + LL_WARNS("performance") << "Scene time 0. Skipping til we have data." << LL_ENDL; + } + perf_stats_timer.reset(); + } + } } void update_texture_time() diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml index 2abd8ec5c0..37efbe654e 100644 --- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml @@ -410,6 +410,59 @@ + + + + + + + + From 0bbe44c4b9df591ecfc451652b79cacb9087276d Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Mon, 3 Oct 2022 15:52:50 +0300 Subject: [PATCH 06/11] SL-17541 simple fallback when refresh rate is unknown --- indra/llwindow/llwindowmacosx.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 66f7e60371..74878df781 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -49,6 +49,8 @@ BOOL gHiDPISupport = TRUE; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; +const S32 DEFAULT_REFRESH_RATE = 60; + namespace { NSKeyEventRef mRawKeyEvent = NULL; @@ -661,6 +663,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); + if(mRefreshRate == 0) + { + //consider adding more appropriate fallback later + mRefreshRate = DEFAULT_REFRESH_RATE; + } // Disable vertical sync for swap toggleVSync(enable_vsync); From 0bd3560b3e057f7ca74f4d586a02a29235d46489 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 3 Oct 2022 20:49:08 +0300 Subject: [PATCH 07/11] SL-18273 add VSync checkbox to Preferred frame rate pane --- .../en/panel_performance_autoadjustments.xml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml index 10ac4b98b7..4c2061bc60 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml @@ -149,6 +149,49 @@ name="av_and_scene" value="1" /> + + + Synchronize the refresh rate and frame rate of a monitor, + + + which can result in smoother performance. + + Date: Mon, 3 Oct 2022 20:56:15 +0300 Subject: [PATCH 08/11] SL-18271 update tooltip text for Continuous checkbox --- .../skins/default/xui/en/panel_performance_autoadjustments.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml index 4c2061bc60..5d4ffd232b 100644 --- a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml +++ b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml @@ -115,7 +115,7 @@ left_pad="10" name="AutoTuneContinuous" top_delta="0" - tool_tip="The viewer will continually adapt the settings to meet the target FPS until stopped even with the floater closed. When disabled clicking the Auto Tune button will adjust for the current settings then stop." + tool_tip="The viewer will continually adapt the settings to meet the target FPS until stopped even with the floater closed. When disabled clicking the Start button will adjust for the current settings then stop." width="64"> Date: Tue, 4 Oct 2022 13:17:04 +0300 Subject: [PATCH 09/11] SL-18296 FIXED 'Start' button is till toggled when desired FPS is reached --- indra/newview/llfloaterperformance.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index e79e9d19b1..644e52c022 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -194,6 +194,12 @@ void LLFloaterPerformance::draw() populateObjectList(); } + auto button = getChild("AutoTuneFPS"); + if((bool)button->getToggleState() != LLPerfStats::tunables.userAutoTuneEnabled) + { + button->toggleState(); + } + mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); } LLFloater::draw(); From 386334f32c92be34c1c574c9d30346e559300353 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Fri, 21 Oct 2022 18:31:31 +0300 Subject: [PATCH 10/11] Post-merge fix --- indra/newview/llviewercontrol.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index 161c8ce0da..2140c70a20 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -781,7 +781,7 @@ void settings_setup_listeners() setting_setup_signal_listener(gSavedSettings, "RenderDebugPipeline", handleRenderDebugPipelineChanged); setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged); setting_setup_signal_listener(gSavedSettings, "RenderDeferred", handleRenderDeferredChanged); - setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleShadowDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); setting_setup_signal_listener(gSavedSettings, "TextureMemory", handleVideoMemoryChanged); From f5b447bc4781d518fbe7841eea6cadd909b57a0a Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Mon, 31 Oct 2022 16:46:28 +0200 Subject: [PATCH 11/11] SL-18495 Enable autofps for new users by default --- indra/newview/app_settings/settings.xml | 4 ++-- indra/newview/llstartup.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 657119ae53..292eef64b9 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16742,14 +16742,14 @@ Type U32 Value - 25 + 30 AutoTuneFPS Comment Allow the viewer to adjust your settings to achieve target FPS Persist - 0 + 1 Type Boolean Value diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index e66fefdd1a..87fba5ec1b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2254,6 +2254,10 @@ bool idle_startup() if (STATE_CLEANUP == LLStartUp::getStartupState()) { + if (gAgent.isFirstLogin()) + { + gSavedSettings.setBOOL("AutoTuneFPS", TRUE); + } set_startup_status(1.0, "", ""); display_startup();