From 8b80fa2779cc067e9a6b4f3ea6a04a69d1233d3d Mon Sep 17 00:00:00 2001 From: Beq Date: Mon, 6 Sep 2021 17:28:30 +0100 Subject: [PATCH] Initial intergation of ART with LL Perf floater --- indra/llcommon/fstelemetry.cpp | 7 + indra/llcommon/fstelemetry.h | 171 ++++++++++++++++++++++++- indra/newview/llappviewer.cpp | 8 ++ indra/newview/lldrawpoolavatar.cpp | 3 + indra/newview/llfloaterperformance.cpp | 6 +- indra/newview/llviewerdisplay.cpp | 3 + indra/newview/pipeline.cpp | 2 + indra/newview/pipeline.h | 2 + 8 files changed, 199 insertions(+), 3 deletions(-) diff --git a/indra/llcommon/fstelemetry.cpp b/indra/llcommon/fstelemetry.cpp index c2bc80b66a..12c31d521d 100644 --- a/indra/llcommon/fstelemetry.cpp +++ b/indra/llcommon/fstelemetry.cpp @@ -28,4 +28,11 @@ namespace FSTelemetry { bool active{false}; + + int RecordSceneTime::writeBuffer{0}; + + bool RecordSceneTime::collectionEnabled{true}; + + std::array< typename RecordSceneTime::StatsArray, 2 > RecordSceneTime::stats{ {} }; + } \ No newline at end of file diff --git a/indra/llcommon/fstelemetry.h b/indra/llcommon/fstelemetry.h index 9a0cdd5e18..c3f6a28bf1 100644 --- a/indra/llcommon/fstelemetry.h +++ b/indra/llcommon/fstelemetry.h @@ -63,9 +63,178 @@ #define FSTelemetryIsConnected #endif // TRACY_ENABLE +#include +#include +#include + namespace FSTelemetry { extern bool active; -} + + enum class ObjStatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_COMBINED, + STATS_COUNT + }; + enum class SceneStatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + RENDER_FPSLIMIT, + RENDER_FPS, + STATS_COUNT + }; + + using ObjStatType = ObjStatType_t; + using SceneStatType = SceneStatType_t; + + class RecordSceneTime + { + using StatsEnum = SceneStatType; + using StatsArray = std::array(StatsEnum::STATS_COUNT)>; + // using StatsBlock = std::unordered_map; + + static int writeBuffer; + static std::array stats; + static bool collectionEnabled; + + RecordSceneTime(const RecordSceneTime&) = delete; + RecordSceneTime() = delete; + + const StatsEnum type; + std::chrono::steady_clock::time_point start; + public: + + static inline void enable(){collectionEnabled=true;}; + static inline void disable(){collectionEnabled=false;}; + static inline bool enabled(){return(collectionEnabled);}; + + RecordSceneTime(SceneStatType type):start{std::chrono::steady_clock::now()}, type{type} {} + + ~RecordSceneTime() + { + auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); + stats[writeBuffer][static_cast(type)] += val; + }; + + static inline void toggleBuffer() + { + if(enabled()) + { + // stats[writeBuffer][static_cast(SceneStatType::RENDER_FPS)] = LLTrace::get_frame_recording().getPeriodMeanPerSec(LLStatViewer::FPS,3); // last 3 Frames + writeBuffer = (writeBuffer+1)%2; + }; // not we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + auto& statsArray = stats[writeBuffer]; + std::fill_n(statsArray.begin() ,static_cast(SceneStatType::STATS_COUNT),0); + } + static inline int getReadBufferIndex(){return (writeBuffer+1)%2;}; + static inline StatsArray getCurrentStatsBuffer(){ return stats[getReadBufferIndex()];} + static inline uint64_t get(StatsEnum type){return stats[getReadBufferIndex()][static_cast(type)];} + }; + + template + class RecordObjectTime + { + using StatsEnum = ObjStatType; + using StatsArray = std::array(StatsEnum::STATS_COUNT)>; + using StatsBlock = std::unordered_map; + + static int writeBuffer; + static std::array stats; + + static std::array max; + static std::array sum; + static bool collectionEnabled; + + RecordObjectTime(const RecordObjectTime&) = delete; + RecordObjectTime() = delete; + const T key; + const StatsEnum type; + std::chrono::steady_clock::time_point start; + + public: + static inline void enable(){collectionEnabled=true;}; + static inline void disable(){collectionEnabled=false;}; + static inline bool enabled(){return(collectionEnabled);}; + + RecordObjectTime(T key, ObjStatType type):start{std::chrono::steady_clock::now()}, key{key}, type{type} {} + + ~RecordObjectTime() + { + using ST = StatsEnum; + // Note: nullptr is used as the key for global stats + auto val = std::chrono::duration(std::chrono::steady_clock::now() - start).count(); + if(key) + { + stats[writeBuffer][key][static_cast(type)] += val; + stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)] += val; + if(max[writeBuffer][static_cast(type)] < stats[writeBuffer][key][static_cast(type)]) + { + max[writeBuffer][static_cast(type)] = stats[writeBuffer][key][static_cast(type)]; + } + if(max[writeBuffer][static_cast(ST::RENDER_COMBINED)] < stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast(ST::RENDER_COMBINED)] = stats[writeBuffer][key][static_cast(ST::RENDER_COMBINED)]; + } + sum[writeBuffer][static_cast(type)] += val; + sum[writeBuffer][static_cast(ST::RENDER_COMBINED)] += val; + } + }; + static inline void toggleBuffer() + { + using ST = StatsEnum; + if(enabled()) + { + writeBuffer = (writeBuffer+1)%2; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + auto& statsMap = stats[writeBuffer]; + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast(ST::STATS_COUNT),0); + } + statsMap.clear(); + std::fill_n(max[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + std::fill_n(sum[writeBuffer].begin(),static_cast(ST::STATS_COUNT),0); + } + static inline int getReadbufferIndex(){return (writeBuffer+1)%2;}; + static inline StatsBlock& getCurrentStatsBuffer(){ return stats[(writeBuffer+1)%2]; } + static inline uint64_t getMax(StatsEnum type){return max[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getSum(StatsEnum type){return sum[(writeBuffer+1)%2][static_cast(type)];} + static inline uint64_t getNum(){return stats[(writeBuffer+1)%2].size();} + static inline uint64_t get(T key, StatsEnum type){return stats[(writeBuffer+1)%2][key][static_cast(type)];} + }; + + static inline void toggleBuffer() + { + // RecordObjectTime::toggleBuffer(); + RecordSceneTime::toggleBuffer(); + } + + template< typename T > + int RecordObjectTime::writeBuffer{0}; + + template< typename T > + bool RecordObjectTime::collectionEnabled{true}; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::max; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsArray, 2 > RecordObjectTime::sum; + + template< typename T > + std::array< typename RecordObjectTime< T >::StatsBlock, 2 > RecordObjectTime< T >::stats{ {{}} }; + +}// namespace FSTelemetry #endif \ No newline at end of file diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 5ed386fc5d..05ce83c6e9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1631,6 +1631,9 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { + { + FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_FRAME); + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; // telemetry enabling. @@ -1828,6 +1831,7 @@ bool LLAppViewer::doFrame() static LLCachedControl yield_time(gSavedSettings, "YieldTime", -1); if(yield_time >= 0) { + FSTelemetry::RecordSceneTime T ( FSTelemetry::SceneStatType::RENDER_SLEEP ); LL_RECORD_BLOCK_TIME(FTM_YIELD); ms_sleep(yield_time); } @@ -1922,6 +1926,7 @@ bool LLAppViewer::doFrame() if (fsLimitFramerate && LLStartUp::getStartupState() == STATE_STARTED && !gTeleportDisplay && !logoutRequestSent() && max_fps > F_APPROXIMATELY_ZERO) { // Sleep a while to limit frame rate. + FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_FPSLIMIT); F32 min_frame_time = 1.f / (F32)max_fps; S32 milliseconds_to_sleep = llclamp((S32)((min_frame_time - frameTimer.getElapsedTimeF64()) * 1000.f), 0, 1000); if (milliseconds_to_sleep > 0) @@ -1961,6 +1966,9 @@ bool LLAppViewer::doFrame() } FSFrameMark; // Tracy support delineate Frame LLPROFILE_UPDATE(); + } + FSTelemetry::RecordSceneTime::toggleBuffer(); + FSTelemetry::RecordObjectTime::toggleBuffer(); return ! LLApp::isRunning(); } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 64fae234b8..124e613b54 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -579,6 +579,8 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } + FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_SHADOWS); + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); if (oa == LLVOAvatar::AOA_INVISIBLE || @@ -1494,6 +1496,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { return; } + FSTelemetry::RecordObjectTime T(avatarp, FSTelemetry::ObjStatType::RENDER_GEOMETRY); // Add avatar hitbox debug static LLCachedControl render_hitbox(gSavedSettings, "DebugRenderHitboxes", false); diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp index ad5cea14ae..4fea996128 100644 --- a/indra/newview/llfloaterperformance.cpp +++ b/indra/newview/llfloaterperformance.cpp @@ -334,19 +334,21 @@ void LLFloaterPerformance::populateNearbyList() getNearbyAvatars(valid_nearby_avs); std::vector::iterator char_iter = valid_nearby_avs.begin(); + auto render_max = FSTelemetry::RecordObjectTime::getMax(FSTelemetry::ObjStatType::RENDER_COMBINED); 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);; + S32 complexity_short = llmax((S32)avatar->getVisualComplexity() / 1000, 1); + auto render_av = FSTelemetry::RecordObjectTime::get(avatar,FSTelemetry::ObjStatType::RENDER_COMBINED); 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; + value["ratio"] = (double)render_av / render_max; value["bottom"] = BAR_BOTTOM_PAD; value["left_pad"] = BAR_LEFT_PAD; value["right_pad"] = BAR_RIGHT_PAD; diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index e23d990184..0bb91556e8 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1192,6 +1192,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { + FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_HUDS); gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -1399,6 +1400,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { + FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_UI); LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1484,6 +1486,7 @@ static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); void swap() { + FSTelemetry::RecordSceneTime T (FSTelemetry::SceneStatType::RENDER_SWAP); LL_RECORD_BLOCK_TIME(FTM_SWAP); if (gDisplaySwapBuffers) diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index be66720237..c4439858d3 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -390,6 +390,8 @@ bool LLPipeline::sRenderTextures = true; bool LLPipeline::sUseDepthTexture = false; // [/RLVa:KB] +static U32 sShowTrueARC; // True when we have the TrueArc overlay active. + // EventHost API LLPipeline listener. static LLPipelineListener sPipelineListener; diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index d9c8aaef29..92135d2fae 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -621,6 +621,8 @@ public: static bool sUseDepthTexture; // [/RLVa:KB] + static U32 sShowTrueARC; // True when we have the TrueArc overlay active. + static LLTrace::EventStatHandle sStatBatchSize; //screen texture