diff options
| author | Mnikolenko Productengine <mnikolenko@productengine.com> | 2026-05-26 18:34:37 +0300 |
|---|---|---|
| committer | Mnikolenko Productengine <mnikolenko@productengine.com> | 2026-05-27 14:50:41 +0300 |
| commit | f27285d02b0f9ef4ba18d37b2d1c743bcfe4fdec (patch) | |
| tree | fb43b56095aa756dd29465aac5d01ef4277719ba | |
| parent | 412509181814baad066425bd1bfdfe3d50b62324 (diff) | |
#5368 add Leap API to query statistics
| -rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/newview/llinventorymodel.cpp | 12 | ||||
| -rw-r--r-- | indra/newview/llinventorymodel.h | 4 | ||||
| -rw-r--r-- | indra/newview/llinventorymodelbackgroundfetch.cpp | 26 | ||||
| -rw-r--r-- | indra/newview/llinventorymodelbackgroundfetch.h | 6 | ||||
| -rw-r--r-- | indra/newview/llstatslistener.cpp | 197 | ||||
| -rw-r--r-- | indra/newview/llstatslistener.h | 41 | ||||
| -rw-r--r-- | indra/newview/llviewerstats.h | 37 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.cpp | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.h | 2 |
10 files changed, 317 insertions, 12 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 8e5e146c03..e4db686776 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -739,6 +739,7 @@ set(viewer_SOURCE_FILES llwebprofile.cpp llwind.cpp llwindowlistener.cpp + llstatslistener.cpp llwlhandlers.cpp llworld.cpp llworldmap.cpp @@ -1412,6 +1413,7 @@ set(viewer_HEADER_FILES llwebprofile.h llwind.h llwindowlistener.h + llstatslistener.h llwlhandlers.h llworld.h llworldmap.h diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 8b9aad4641..604a66c241 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -433,6 +433,8 @@ LLInventoryModel::LLInventoryModel() : // These are now ordered, keep them that way. mBacklinkMMap(), mIsAgentInvUsable(false), + mLibrarySkeletonLoadTime(0.f), + mAgentSkeletonLoadTime(0.f), mRootFolderID(), mLibraryRootFolderID(), mLibraryOwnerID(), @@ -3001,6 +3003,16 @@ bool LLInventoryModel::loadSkeleton( << " after " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL; + const F32 elapsed = timer.getElapsedTimeF32(); + if (owner_id == mLibraryOwnerID) + { + mLibrarySkeletonLoadTime = elapsed; + } + else + { + mAgentSkeletonLoadTime = elapsed; + } + return rv; } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 05ada9121a..3aaba69a60 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -158,8 +158,12 @@ protected: public: // The inventory model usage is sensitive to the initial construction of the model bool isInventoryUsable() const; + F32 getLibrarySkeletonLoadTime() const { return mLibrarySkeletonLoadTime; } + F32 getAgentSkeletonLoadTime() const { return mAgentSkeletonLoadTime; } private: bool mIsAgentInvUsable; // used to handle an invalid inventory state + F32 mLibrarySkeletonLoadTime; + F32 mAgentSkeletonLoadTime; // One-time initialization of HTTP system. void initHttpRequest(); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 82eefb50ac..f68eb7f4a5 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -192,6 +192,8 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch(): mFetchCount(0), mLastFetchCount(0), mFetchFolderCount(0), + mInitialFetchDuration(0.f), + mInitialFetchDurationCaptured(false), mAllRecursiveFoldersFetched(false), mRecursiveInventoryFetchStarted(false), mRecursiveLibraryFetchStarted(false), @@ -199,6 +201,14 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch(): mMinTimeBetweenFetches(0.3f) {} +void LLInventoryModelBackgroundFetch::markFetchStarted() +{ + if (!mBackgroundFetchActive) + { + mFetchStartTimer.reset(); + } +} + LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() { gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, nullptr); @@ -289,6 +299,7 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& id, bool recursive) // it's a folder, do a bulk fetch LL_DEBUGS(LOG_INV) << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; + markFetchStarted(); mBackgroundFetchActive = true; mFolderFetchActive = true; EFetchType recursion_type = recursive ? FT_RECURSIVE : FT_DEFAULT; @@ -376,6 +387,7 @@ void LLInventoryModelBackgroundFetch::scheduleFolderFetch(const LLUUID& cat_id, { if (mFetchFolderQueue.empty() || mFetchFolderQueue.front().mUUID != cat_id) { + markFetchStarted(); mBackgroundFetchActive = true; mFolderFetchActive = true; @@ -403,6 +415,7 @@ void LLInventoryModelBackgroundFetch::scheduleItemFetch(const LLUUID& item_id, b { if (mFetchItemQueue.empty() || mFetchItemQueue.front().mUUID != item_id) { + markFetchStarted(); mBackgroundFetchActive = true; if (forced) { @@ -447,6 +460,7 @@ void LLInventoryModelBackgroundFetch::fetchFolderAndLinks(const LLUUID& cat_id, }); // start idle loop to track completion + markFetchStarted(); mBackgroundFetchActive = true; mFolderFetchActive = true; gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, nullptr); @@ -489,6 +503,7 @@ void LLInventoryModelBackgroundFetch::fetchCOF(nullary_func_t callback) }); // start idle loop to track completion + markFetchStarted(); mBackgroundFetchActive = true; mFolderFetchActive = true; gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, nullptr); @@ -496,6 +511,7 @@ void LLInventoryModelBackgroundFetch::fetchCOF(nullary_func_t callback) void LLInventoryModelBackgroundFetch::findLostItems() { + markFetchStarted(); mBackgroundFetchActive = true; mFolderFetchActive = true; mFetchFolderQueue.emplace_back(LLUUID::null, FT_RECURSIVE); @@ -515,6 +531,11 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() mFolderFetchActive = false; if (isBulkFetchProcessingComplete()) { + if (mAllRecursiveFoldersFetched && !mInitialFetchDurationCaptured) + { + mInitialFetchDuration = mFetchStartTimer.getElapsedTimeF32(); + mInitialFetchDurationCaptured = true; + } mBackgroundFetchActive = false; } @@ -843,6 +864,11 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis() if (isBulkFetchProcessingComplete()) { + if (mAllRecursiveFoldersFetched && !mInitialFetchDurationCaptured) + { + mInitialFetchDuration = mFetchStartTimer.getElapsedTimeF32(); + mInitialFetchDurationCaptured = true; + } mBackgroundFetchActive = false; } } diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index ef6fa06e9f..6a5e0f66ff 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -70,6 +70,7 @@ public: bool inventoryFetchStarted() const; bool inventoryFetchCompleted() const; bool inventoryFetchInProgress() const; + F32 getInitialFetchDuration() const { return mInitialFetchDuration; } void findLostItems(); void incrFetchCount(S32 fetching); @@ -120,6 +121,8 @@ protected: bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; private: + void markFetchStarted(); + bool mRecursiveInventoryFetchStarted; bool mRecursiveLibraryFetchStarted; bool mRecursiveMarketplaceFetchStarted; // AIS3 specific @@ -133,6 +136,9 @@ private: S32 mLastFetchCount; // for debug S32 mFetchFolderCount; + LLFrameTimer mFetchStartTimer; + F32 mInitialFetchDuration; + bool mInitialFetchDurationCaptured; LLFrameTimer mFetchTimer; F32 mMinTimeBetweenFetches; fetch_queue_t mFetchFolderQueue; diff --git a/indra/newview/llstatslistener.cpp b/indra/newview/llstatslistener.cpp new file mode 100644 index 0000000000..47b025cd8b --- /dev/null +++ b/indra/newview/llstatslistener.cpp @@ -0,0 +1,197 @@ +/** + * @file llstatslistener.cpp + * @brief EventAPI interface for querying performance statistics + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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 "llstatslistener.h" + +#include "llinventorymodel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llimagegl.h" +#include "llviewerstats.h" + +namespace +{ +template <typename STAT, typename EXTRACTOR> +LLSD collectPeriodArray(LLTrace::PeriodicRecording& recording, + size_t num_periods, + const STAT& stat, + EXTRACTOR extractor) +{ + LLSD values = LLSD::emptyArray(); + for (size_t i = 1; i <= num_periods; ++i) + { + LLTrace::Recording& period = recording.getPrevRecording(i); + if (period.hasValue(stat)) + { + values.append((F64)extractor(period, stat)); + } + } + return values; +} + +template <typename STAT, typename EXTRACTOR> +void setPeriodArray(LLSD& out, + const char* key, + LLTrace::Recording& last, + LLTrace::PeriodicRecording& recording, + size_t num_periods, + const STAT& stat, + EXTRACTOR extractor) +{ + if (last.hasValue(stat)) + { + out[key] = collectPeriodArray(recording, num_periods, stat, extractor); + } +} +} + +LLStatsListener::LLStatsListener() + : LLEventAPI("LLStats", "Query performance statistics") +{ + add("getPerfData", + "Get performance data from the frame recording buffer, plus texture memory\n" + "and inventory loading timing information.\n" + "Reply contains [\"stats\"] with nested group maps.", + &LLStatsListener::getPerfData, + llsd::map("reply", LLSD())); +} + +void LLStatsListener::getPerfData(LLSD const & evt) +{ + LLEventAPI::Response response(LLSD(), evt); + + // get_frame_recording() is a PeriodicRecording with 200 periods + LLTrace::PeriodicRecording& recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last = recording.getLastRecording(); + + size_t num_periods = recording.getNumRecordedPeriods(); + F64 total_duration = recording.getDuration().value(); + + LLSD stats; + stats["total_periods_duration"] = total_duration; + stats["num_periods"] = (LLSD::Integer)num_periods; + + LLSD frametime; + + setPeriodArray(frametime, "fps", last, recording, num_periods, LLStatViewer::FPS, + [](LLTrace::Recording& period, const auto& stat) { return period.getPerSec(stat); }); + + setPeriodArray(frametime, "frame_time_ms", last, recording, num_periods, LLStatViewer::FRAMETIME, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + setPeriodArray(frametime, "frame_time_jitter_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + // Normalized jitter - scalar samples updated per frame + // report the current (last) value since they are session/period rolling stats + if (last.hasValue(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION)) + { + frametime["normalized_jitter_session"] = last.getLastValue(LLStatViewer::NOTRMALIZED_FRAMETIME_JITTER_SESSION); + } + if (last.hasValue(LLStatViewer::NORMALIZED_FRAMTIME_JITTER_PERIOD)) + { + frametime["normalized_jitter_period"] = last.getLastValue(LLStatViewer::NORMALIZED_FRAMTIME_JITTER_PERIOD); + } + if (last.hasValue(LLStatViewer::NFTV)) + { + frametime["normalized_frametime_variation"] = last.getLastValue(LLStatViewer::NFTV); + } + + // Jitter event minute counters: running avg per minute and count in last completed minute + // These are already minute-window aggregates, so sending single value, not arrays + if (last.hasValue(LLStatViewer::FRAMETIME_JITTER_EVENTS_PER_MINUTE)) + { + frametime["frame_time_jitter_events_per_minute"] = (F64)last.getLastValue(LLStatViewer::FRAMETIME_JITTER_EVENTS_PER_MINUTE); + } + if (last.hasValue(LLStatViewer::FRAMETIME_JITTER_EVENTS_LAST_MINUTE)) + { + frametime["frame_time_jitter_events_last_minute"] = (F64)last.getLastValue(LLStatViewer::FRAMETIME_JITTER_EVENTS_LAST_MINUTE); + } + + // Jitter percentiles / cumulative + setPeriodArray(frametime, "jitter_cumulative_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER_CUMULATIVE, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(frametime, "jitter_99th_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER_99TH, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(frametime, "jitter_95th_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER_95TH, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(frametime, "jitter_stddev_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER_STDDEV, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + // Frame time percentiles + setPeriodArray(frametime, "frametime_99th_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_99TH, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(frametime, "frametime_95th_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_95TH, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(frametime, "frametime_stddev_ms", last, recording, num_periods, LLStatViewer::FRAMETIME_STDDEV, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + // Frametime jitter event count + setPeriodArray(frametime, "frametime_jitter_events", last, recording, num_periods, LLStatViewer::FRAMETIME_JITTER_EVENTS, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + stats["frametime"] = frametime; + + LLSD other; + + // Packet loss + setPeriodArray(other, "packet_loss_percent", last, recording, num_periods, LLStatViewer::PACKETS_LOST_PERCENT, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + // Sim ping + setPeriodArray(other, "sim_ping_ms", last, recording, num_periods, LLStatViewer::SIM_PING, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + // Triangle rendering + setPeriodArray(other, "ktris_per_frame", last, recording, num_periods, LLStatViewer::TRIANGLES_DRAWN, + [](LLTrace::Recording& period, const auto& stat) { return period.getSum(stat); }); + setPeriodArray(other, "ktris_per_sec", last, recording, num_periods, LLStatViewer::TRIANGLES_DRAWN, + [](LLTrace::Recording& period, const auto& stat) { return period.getPerSec(stat); }); + + // Object counts + setPeriodArray(other, "num_objects", last, recording, num_periods, LLStatViewer::NUM_OBJECTS, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + setPeriodArray(other, "num_active_objects", last, recording, num_periods, LLStatViewer::NUM_ACTIVE_OBJECTS, + [](LLTrace::Recording& period, const auto& stat) { return period.getMean(stat); }); + + stats["other"] = other; + + // texture memory usage + LLSD memory; + memory["texture_bytes_alloc_mb"] = (F64)LLImageGL::getTextureBytesAllocated() / 1024.0 / 512.0; + stats["memory"] = memory; + + LLSD inventory; + // library skeleton cache load duration + inventory["skeleton_load_time_library_seconds"] = gInventory.getLibrarySkeletonLoadTime(); + // agent skeleton cache load duration + inventory["skeleton_load_time_agent_seconds"] = gInventory.getAgentSkeletonLoadTime(); + // initial recursive inventory/library background fetch duration + inventory["initial_fetch_time_seconds"] = LLInventoryModelBackgroundFetch::instance().getInitialFetchDuration(); + inventory["fetch_completed"] = LLInventoryModelBackgroundFetch::instance().isEverythingFetched(); + stats["inventory"] = inventory; + + response["stats"] = stats; +} diff --git a/indra/newview/llstatslistener.h b/indra/newview/llstatslistener.h new file mode 100644 index 0000000000..77777034c7 --- /dev/null +++ b/indra/newview/llstatslistener.h @@ -0,0 +1,41 @@ +/** + * @file llstatslistener.h + * @brief EventAPI interface for querying performance statistics + * + * $LicenseInfo:firstyear=2026&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2026, 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$ + */ + +#ifndef LL_LLSTATSLISTENER_H +#define LL_LLSTATSLISTENER_H + +#include "lleventapi.h" + +class LLStatsListener : public LLEventAPI +{ +public: + LLStatsListener(); + +private: + void getPerfData(LLSD const & evt); +}; + +#endif // LL_LLSTATSLISTENER_H diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 8ec0dd0024..f670dadc27 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -209,29 +209,42 @@ extern SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM; extern LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER, - SIM_PING; + FRAMETIME, + SIM_PING, + FRAMETIME_JITTER_99TH, + FRAMETIME_JITTER_95TH, + FRAMETIME_99TH, + FRAMETIME_95TH, + FRAMETIME_JITTER_CUMULATIVE, + FRAMETIME_JITTER_STDDEV, + FRAMETIME_STDDEV; + +extern LLTrace::SampleStatHandle<U32> FRAMETIME_JITTER_EVENTS, + FRAMETIME_JITTER_EVENTS_PER_MINUTE, + FRAMETIME_JITTER_EVENTS_LAST_MINUTE; + +extern LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION; +extern LLTrace::SampleStatHandle<F64> NFTV; +extern LLTrace::SampleStatHandle<F64> NORMALIZED_FRAMTIME_JITTER_PERIOD; extern LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP; extern LLTrace::EventStatHandle<> LOADING_WEARABLES_LONG_DELAY; extern LLTrace::EventStatHandle<F64Milliseconds > REGION_CROSSING_TIME, - FRAME_STACKTIME, - UPDATE_STACKTIME, - NETWORK_STACKTIME, - IMAGE_STACKTIME, - REBUILD_STACKTIME, - RENDER_STACKTIME; + FRAME_STACKTIME, + UPDATE_STACKTIME, + NETWORK_STACKTIME, + IMAGE_STACKTIME, + REBUILD_STACKTIME, + RENDER_STACKTIME; extern LLTrace::EventStatHandle<F64Seconds > AVATAR_EDIT_TIME, - TOOLBOX_TIME, - MOUSELOOK_TIME; + TOOLBOX_TIME, + MOUSELOOK_TIME; extern LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > OBJECT_CACHE_HIT_RATE; -extern LLTrace::SampleStatHandle<F64> NOTRMALIZED_FRAMETIME_JITTER_SESSION; -extern LLTrace::SampleStatHandle<F64> NORMALIZED_FRAMTIME_JITTER_PERIOD; - extern LLTrace::SampleStatHandle<U32> WEBRTC_PACKETS_IN_LOST, WEBRTC_PACKETS_IN_RECEIVED, WEBRTC_PACKETS_OUT_SENT, WEBRTC_PACKETS_OUT_LOST; extern LLTrace::SampleStatHandle<F32> WEBRTC_JITTER_OUT, WEBRTC_JITTER_IN, WEBRTC_LATENCY, WEBRTC_UPLOAD_BANDWIDTH, WEBRTC_JITTER_BUFFER; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 0f3f24d1af..dea96e2012 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -203,6 +203,7 @@ #include "llwindowlistener.h" #include "llviewerwindowlistener.h" +#include "llstatslistener.h" #include "llcleanup.h" #if LL_WINDOWS @@ -1886,6 +1887,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) LLWindowListener::KeyboardGetter getter = [](){ return gKeyboard; }; mWindowListener = std::make_unique<LLWindowListener>(this, getter); mViewerWindowListener = std::make_unique<LLViewerWindowListener>(this); + mStatsListener = std::make_unique<LLStatsListener>(); mSystemChannel.reset(new LLNotificationChannel("System", "Visible", LLNotificationFilters::includeEverything)); mCommunicationChannel.reset(new LLCommunicationChannel("Communication", "Visible")); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index ec28a3fc4a..5f1afe2cbe 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -66,6 +66,7 @@ class LLWindow; class LLRootView; class LLWindowListener; class LLViewerWindowListener; +class LLStatsListener; class LLVOPartGroup; class LLPopupView; class LLCubeMap; @@ -563,6 +564,7 @@ private: std::unique_ptr<LLWindowListener> mWindowListener; std::unique_ptr<LLViewerWindowListener> mViewerWindowListener; + std::unique_ptr<LLStatsListener> mStatsListener; // Object temporarily hovered over while dragging LLPointer<LLViewerObject> mDragHoveredObject; |
