From 8b32dfa9904d223762f5397be8f81f77db6ebf0b Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 01:34:14 -0400 Subject: [PATCH 1/9] LLSingleton: DLL-safe registry storage + lock-free fast path; restore LLParamSingleton Make LLSingleton safe for a future shared (multi-DLL) llcommon and restore LLParamSingleton so the DLL-unsafe LLSimpleton can be retired, without reintroducing the per-access mutex locking that motivated LLSimpleton. Storage: per-type instance state moves out of the per-T function-local/template static (which duplicates once per module under DLLs) into a single process-wide registry owned by LLSingletonBase::getSlot() in llsingleton.cpp. Every module resolves the same SingletonSlot; LLSingleton keeps only a per-module cache of the slot's stable address. The registry is keyed by the mangled name string (typeid(T).name()), not std::type_index: we build with -fvisibility=hidden, so each module has its own type_info object for T and type_index would compare unequal across modules and duplicate the slot. Performance: getInstance()/instanceExists() take a lock-free fast path in steady state -- an acquire load of an atomic instance pointer published only at INITIALIZED. Dependency tracking is fully preserved: the fast path is gated on a process-wide sInitializingDepth counter, so whenever any singleton is mid-init every caller falls back to the locked, capture_dependency() path. DLL export: mark class LLSingletonBase LL_COMMON_API so its out-of-line methods, getSlot, and sInitializingDepth are reachable across module boundaries. Restore LLParamSingleton and LLLockedSingleton (adapted to the slot internals + fast path) and their unit tests. INTEGRATION_TEST_llsingleton: 15/15 pass, including the dependency-ordered deleteAll() checks. Co-Authored-By: Claude Opus 4.8 --- indra/llcommon/llsingleton.cpp | 38 +++ indra/llcommon/llsingleton.h | 370 +++++++++++++++++++--- indra/llcommon/tests/llsingleton_test.cpp | 117 +++++++ 3 files changed, 482 insertions(+), 43 deletions(-) diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 05dc3cde79d..1e8fb74b0ef 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -33,9 +33,12 @@ #include "llexception.h" #include "llcoros.h" #include +#include #include // std::cerr in dire emergency #include #include +#include +#include // Our master list of all LLSingletons is itself an LLSingleton. We used to // store it in a function-local static, but that could get destroyed before @@ -165,6 +168,35 @@ class LLSingletonBase::MasterList: } }; +// Process-wide count of LLSingletons currently between push_initializing() and +// pop_initializing(). See the declaration in llsingleton.h and getInstance(). +std::atomic LLSingletonBase::sInitializingDepth{0}; + +//static +LLSingletonBase::SingletonSlot& LLSingletonBase::getSlot(const char* type_name) +{ + // The canonical per-type slots live here, in a single translation unit -- + // hence a single module even in a multi-DLL build -- so every module that + // instantiates LLSingleton resolves the SAME slot for a given type. + // + // Keyed by the mangled name STRING (typeid(T).name()), NOT std::type_index. + // We build with -fvisibility=hidden, so each module has its own type_info + // object for T; comparing those by identity (which is what type_index does) + // would treat the same T as a different key in each module and duplicate the + // slot. The mangled name string is identical across modules for one ABI, so + // a value (string) compare collapses them to a single slot. + // + // The registry is heap-allocated and intentionally never freed so it + // outlives every LLSingleton (which are themselves leaked unless + // deleteAll()'d, and whose destructors re-lock their slot). unordered_map + // node addresses are stable across rehash, so the returned reference is + // valid for the life of the process. + static std::mutex* sRegistryMutex = new std::mutex(); + static auto* sRegistry = new std::unordered_map(); + std::lock_guard lk(*sRegistryMutex); + return (*sRegistry)[type_name]; +} + void LLSingletonBase::add_master() { // As each new LLSingleton is constructed, add to the master list. @@ -201,6 +233,10 @@ void LLSingletonBase::push_initializing(const char* name) // log BEFORE pushing so logging singletons don't cry circularity locked_list.log("Pushing", name); locked_list.get().push_back(this); + // A singleton is now mid-initialization: force getInstance() everywhere off + // its lock-free fast path so dependencies are still captured. Balanced by + // pop_initializing() / reset_initializing(). + sInitializingDepth.fetch_add(1, std::memory_order_release); } void LLSingletonBase::pop_initializing() @@ -219,6 +255,7 @@ void LLSingletonBase::pop_initializing() LLSingletonBase* back(list.back()); // and pop it list.pop_back(); + sInitializingDepth.fetch_sub(1, std::memory_order_release); // The viewer launches an open-ended number of coroutines. While we don't // expect most of them to initialize LLSingleton instances, our present @@ -259,6 +296,7 @@ void LLSingletonBase::reset_initializing(list_t::size_type size) while (list.size() > size) { list.pop_back(); + sInitializingDepth.fetch_sub(1, std::memory_order_release); } // as in pop_initializing() diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 2bd39918901..507921a023c 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -25,13 +25,15 @@ #ifndef LLSINGLETON_H #define LLSINGLETON_H +#include #include #include #include #include #include #include -#include "lockstatic.h" +#include "llpreprocessor.h" // LL_COMMON_API +#include "lockstatic.h" // unrelated consumers rely on transitive include #include "llthread.h" // on_main_thread() #include "llmainthreadtask.h" #include "llprofiler.h" @@ -42,7 +44,7 @@ #pragma warning(disable : 4506) // no definition for inline function #endif -class LLSingletonBase +class LL_COMMON_API LLSingletonBase { public: class MasterList; @@ -75,6 +77,48 @@ class LLSingletonBase DELETED // deleteSingleton() or deleteAll() called } EInitState; + // Canonical per-type storage for one LLSingleton specialization. The class + // template LLSingleton deliberately keeps *no* instance storage of its + // own; it routes through getSlot() below. That matters for DLL safety: a + // function-local or template-static would be duplicated once per module in + // a multi-DLL build (each DLL getting its own "singleton"), whereas getSlot + // lives in exactly one translation unit, so every module resolves the same + // slot. See getSlot(). + struct SingletonSlot + { + // recursive so a constructor/initSingleton() may re-enter getInstance() + std::recursive_mutex mMutex; + // Lock-free fast-path handle. Published (release) ONLY once the instance + // is fully INITIALIZED, and cleared (release) on deletion. A non-null + // load therefore always yields a completely constructed instance. + std::atomic mFastInstance{nullptr}; + // Canonical instance pointer and state, both guarded by mMutex. These + // mirror the old per-type SingletonData exactly. + void* mInstance{nullptr}; + EInitState mInitState{UNINITIALIZED}; + }; + + // Return the one canonical slot for the singleton type whose mangled name + // is 'type_name' (pass typeid(T).name()). Defined in llsingleton.cpp, hence + // single-instance per process even across DLL boundaries. + // + // Keyed by the mangled NAME STRING, deliberately NOT by std::type_index: + // we build with -fvisibility=hidden, so each module gets its own type_info + // object for T. type_info identity / std::type_index therefore compare + // UNEQUAL across modules and would yield a separate slot per module -- the + // very duplication we are eliminating. The mangled name string, by + // contrast, is identical across modules for the same type under one ABI. + // The returned reference is stable for the life of the process. + static SingletonSlot& getSlot(const char* type_name); + + // Number of LLSingletons anywhere in the process currently between + // push_initializing() and pop_initializing(). When this is zero, no + // dependency can possibly be captured, so getInstance() may take the + // lock-free fast path and skip capture_dependency() entirely. A single + // shared (exported) counter; a conservative over-approximation across + // threads is fine -- see getInstance(). + static std::atomic sInitializingDepth; + // Define tag to pass to our template constructor. You can't explicitly // invoke a template constructor with ordinary template syntax: // http://stackoverflow.com/a/3960925/5533635 @@ -230,6 +274,10 @@ LLSingletonBase::LLSingletonBase(tag): LLSingleton_manage_master().push_initializing(this); } +// forward declare for friend directive within LLSingleton +template +class LLParamSingleton; + /** * LLSingleton implements the getInstance() method part of the Singleton * pattern. It can't make the derived class constructors protected, though, so @@ -290,40 +338,67 @@ template class LLSingleton : public LLSingletonBase { private: - // LLSingleton must have a distinct instance of - // SingletonData for every distinct DERIVED_TYPE. It's tempting to - // consider hoisting SingletonData up into LLSingletonBase. Don't do it. - struct SingletonData + // LLSingleton keeps NO instance storage of its own. All + // per-type state lives in the one canonical SingletonSlot returned by + // LLSingletonBase::getSlot() (defined in llsingleton.cpp, hence single- + // instance per process even in a multi-DLL build). sSlot below is merely a + // per-module *cache* of that slot's stable address. Caching the same + // pointer independently in each module is harmless -- and that is exactly + // what makes this DLL-safe, where a function-local/template static instance + // would silently give each module its own "singleton". + // + // sSlot must be a constant-initialized inline static (NOT a function-local + // static) so the fast path pays no magic-static guard. relaxed atomic: + // concurrent first-touchers merely race to store the identical value. + static inline std::atomic sSlot{nullptr}; + + static SingletonSlot& slot() { - // Use a recursive_mutex in case of constructor circularity. With a - // non-recursive mutex, that would result in deadlock. - typedef std::recursive_mutex mutex_t; - LL_PROFILE_MUTEX(mutex_t, mMutex); // LockStatic looks for mMutex + SingletonSlot* s = sSlot.load(std::memory_order_relaxed); + if (LL_UNLIKELY(! s)) + { + // first touch in this module: resolve once and cache + s = &getSlot(typeid(DERIVED_TYPE).name()); + sSlot.store(s, std::memory_order_relaxed); + } + return *s; + } - EInitState mInitState{UNINITIALIZED}; - DERIVED_TYPE* mInstance{nullptr}; + // RAII handle that locks our slot's recursive mutex and exposes the slot + // through operator->, so the construction logic below reads just like the + // old LockStatic-based code (lk->mInstance, lk->mInitState, lk.unlock()). + struct SlotLock + { + SingletonSlot& mSlot; + std::unique_lock mLock; + SlotLock(): SlotLock(slot()) {} + explicit SlotLock(SingletonSlot& s): mSlot(s), mLock(s.mMutex) {} + SingletonSlot* operator->() const { return &mSlot; } + SingletonSlot& operator*() const { return mSlot; } + void unlock() { mLock.unlock(); } }; - typedef llthread::LockStatic LockStatic; + + // Allow LLParamSingleton subclass -- but NOT DERIVED_TYPE itself -- to + // access our private members. + friend class LLParamSingleton; // LLSingleton only supports a nullary constructor. However, the specific // purpose for its subclass LLParamSingleton is to support Singletons // requiring constructor arguments. constructSingleton() supports both use // cases. - // Accepting LockStatic& requires that the caller has already locked our - // static data before calling. + // Accepting SlotLock& requires that the caller has already locked our slot + // before calling. template - static void constructSingleton(LockStatic& lk, Args&&... args) + static void constructSingleton(SlotLock& lk, Args&&... args) { auto prev_size = LLSingleton_manage_master().get_initializing_size(); // Any getInstance() calls after this point are from within constructor lk->mInitState = CONSTRUCTING; + DERIVED_TYPE* instance = nullptr; try { -#if defined(LL_PROFILER_CONFIGURATION) && LL_PROFILER_CONFIGURATION >= LL_PROFILER_CONFIG_TRACY - std::string_view typeidname(typeid(DERIVED_TYPE).name()); - LockableName(lk->mMutex, typeidname.data(), typeidname.size()); -#endif - lk->mInstance = new DERIVED_TYPE(std::forward(args)...); + instance = new DERIVED_TYPE(std::forward(args)...); + lk->mInstance = instance; } catch (const std::exception& err) { @@ -349,23 +424,26 @@ class LLSingleton : public LLSingletonBase // initialize singleton after constructing it so that it can // reference other singletons which in turn depend on it, thus // breaking cyclic dependencies - lk->mInstance->initSingleton(); + instance->initSingleton(); lk->mInitState = INITIALIZED; + // Publish to the lock-free fast path ONLY now that the instance is + // fully constructed AND initialized: a non-null mFastInstance must + // always denote a usable instance. + lk->mFastInstance.store(instance, std::memory_order_release); // pop this off stack of initializing singletons - pop_initializing(lk->mInstance); + pop_initializing(instance); } catch (const std::exception& err) { // pop this off stack of initializing singletons here, too -- // BEFORE logging, so log-machinery LLSingletons don't record a // dependency on DERIVED_TYPE! - pop_initializing(lk->mInstance); + pop_initializing(instance); logwarns({"Error in ", classname(), "::initSingleton(): ", err.what()}); - // Get rid of the instance entirely. This call depends on our - // recursive_mutex. We could have a deleteSingleton(LockStatic&) - // overload and pass lk, but we don't strictly need it. + // Get rid of the instance entirely. This call re-enters our slot's + // recursive mutex. deleteSingleton(); // propagate the exception throw; @@ -420,7 +498,9 @@ class LLSingleton : public LLSingletonBase // deleteSingleton() to defend against manual deletion. When we moved // cleanup to deleteSingleton(), we hit crashes due to dangling // pointers in the MasterList. - LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex); + SlotLock lk; + // Stop lock-free readers BEFORE tearing anything down. + lk->mFastInstance.store(nullptr, std::memory_order_release); lk->mInstance = nullptr; lk->mInitState = DELETED; @@ -446,21 +526,36 @@ class LLSingleton : public LLSingletonBase static void deleteSingleton() { // Hold the lock while we call cleanupSingleton() and the destructor. - // Our destructor also instantiates LockStatic, requiring a recursive + // Our destructor also instantiates SlotLock, requiring a recursive // mutex. - LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex); + SlotLock lk; // of course, only cleanup and delete if there's something there if (lk->mInstance) { - lk->mInstance->cleanup_(); - delete lk->mInstance; - // destructor clears mInstance (and mInitState) + DERIVED_TYPE* instance = static_cast(lk->mInstance); + instance->cleanup_(); + delete instance; + // destructor clears mFastInstance, mInstance and mInitState } } static DERIVED_TYPE* getInstance() { //LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; // TODO -- reenable this when we have a fix for using Tracy with coroutines + SingletonSlot& s = slot(); + + // Lock-free fast path. mFastInstance is published (non-null) only when + // the instance is fully INITIALIZED. The sInitializingDepth == 0 guard + // preserves dependency tracking: while ANY singleton is mid-init we + // fall through to the locked path below so capture_dependency() still + // runs. In steady state this is two atomic loads and a predicted + // branch -- no lock taken, no dependency bookkeeping. + if (void* p = s.mFastInstance.load(std::memory_order_acquire)) + { + if (LL_LIKELY(sInitializingDepth.load(std::memory_order_acquire) == 0)) + return static_cast(p); + } + // We know the viewer has LLSingleton dependency circularities. If you // feel strongly motivated to eliminate them, cheers and good luck. // (At that point we could consider a much simpler locking mechanism.) @@ -505,7 +600,7 @@ class LLSingleton : public LLSingletonBase { // nested scope for 'lk' // In case racing threads call getInstance() at the same moment, // serialize the calls. - LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex); + SlotLock lk(s); switch (lk->mInitState) { @@ -521,11 +616,14 @@ class LLSingleton : public LLSingletonBase // here if DERIVED_TYPE::initSingleton() (directly or indirectly) // calls DERIVED_TYPE::getInstance(): go ahead and allow it case INITIALIZED: + { // normal subsequent calls // record the dependency, if any: check if we got here from another // LLSingleton's constructor or initSingleton() method - capture_dependency(lk->mInstance); - return lk->mInstance; + DERIVED_TYPE* instance = static_cast(lk->mInstance); + capture_dependency(instance); + return instance; + } case DELETED: // called after deleteSingleton() @@ -549,8 +647,9 @@ class LLSingleton : public LLSingletonBase // On the main thread, directly construct the instance while // holding the lock. constructSingleton(lk); - capture_dependency(lk->mInstance); - return lk->mInstance; + DERIVED_TYPE* instance = static_cast(lk->mInstance); + capture_dependency(instance); + return instance; } // Here we need to construct a new instance, but we're on a secondary @@ -594,9 +693,9 @@ class LLSingleton : public LLSingletonBase // Use this to avoid accessing singletons before they can safely be constructed. static bool instanceExists() { - // defend any access to sData from racing threads - LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex); - return lk->mInitState == INITIALIZED; + // mFastInstance is published non-null iff INITIALIZED, so this is an + // exact, lock-free equivalent of the old (mInitState == INITIALIZED). + return slot().mFastInstance.load(std::memory_order_acquire) != nullptr; } // Has this singleton been deleted? This can be useful during shutdown @@ -604,12 +703,197 @@ class LLSingleton : public LLSingletonBase // cleaned up. static bool wasDeleted() { - // defend any access to sData from racing threads - LockStatic lk; LL_PROFILE_MUTEX_LOCK(lk->mMutex); + // DELETED is indistinguishable from UNINITIALIZED on the fast path, so + // take the lock for this (cold, shutdown-time) query. + SlotLock lk; return lk->mInitState == DELETED; } }; + +/** + * LLParamSingleton is like LLSingleton, except in the following ways: + * + * * It is NOT instantiated on demand (instance() or getInstance()). You must + * first call initParamSingleton(constructor args...). + * * Before initParamSingleton(), calling instance() or getInstance() dies with + * LL_ERRS. + * * initParamSingleton() may be called only once. A second call dies with + * LL_ERRS. + * * However, distinct initParamSingleton() calls can be used to engage + * different constructors, as long as only one such call is executed at + * runtime. + * * Unlike LLSingleton, an LLParamSingleton cannot be "revived" by an + * instance() or getInstance() call after deleteSingleton(). + * + * Importantly, though, each LLParamSingleton subclass does participate in the + * dependency-ordered LLSingletonBase::deleteAll() processing. + */ +template +class LLParamSingleton : public LLSingleton +{ +private: + typedef LLSingleton super; + // SingletonSlot is protected in LLSingletonBase; SlotLock is private in + // LLSingleton (reachable here via the friend declaration in LLSingleton). + using SingletonSlot = typename LLSingletonBase::SingletonSlot; + using typename super::SlotLock; + + // Passes arguments to DERIVED_TYPE's constructor and sets appropriate + // states, returning a pointer to the new instance. + template + static DERIVED_TYPE* initParamSingleton_(Args&&... args) + { + // In case racing threads both call initParamSingleton() at the same + // time, serialize them. One should initialize; the other should see + // mInitState already set. + SlotLock lk; + // For organizational purposes this function shouldn't be called twice + if (lk->mInitState != super::UNINITIALIZED) + { + super::logerrs({"Tried to initialize singleton ", + super::template classname(), + " twice!"}); + return nullptr; + } + else if (on_main_thread()) + { + // on the main thread, simply construct instance while holding lock + super::logdebugs({super::template classname(), + "::initParamSingleton()"}); + super::constructSingleton(lk, std::forward(args)...); + return static_cast(lk->mInstance); + } + else + { + // on secondary thread, dispatch to main thread -- + // set state so we catch any other calls before the main thread + // picks up the task + lk->mInitState = super::QUEUED; + // very important to unlock here so main thread can actually process + lk.unlock(); + super::loginfos({super::template classname(), + "::initParamSingleton() dispatching to main thread"}); + // Normally it would be the height of folly to reference-bind + // 'args' into a lambda to be executed on some other thread! By + // the time that thread executed the lambda, the references would + // all be dangling, and Bad Things would result. But + // LLMainThreadTask::dispatch() promises to block until the passed + // task has completed. So in this case we know the references will + // remain valid until the lambda has run, so we dare to bind + // references. + auto instance = LLMainThreadTask::dispatch( + [&](){ + super::loginfos({super::template classname(), + "::initParamSingleton() on main thread"}); + return initParamSingleton_(std::forward(args)...); + }); + super::loginfos({super::template classname(), + "::initParamSingleton() returning on requesting thread"}); + return instance; + } + } + +public: + using super::deleteSingleton; + using super::instanceExists; + using super::wasDeleted; + + /// initParamSingleton() constructs the instance, returning a reference. + /// Pass whatever arguments are required to construct DERIVED_TYPE. + template + static DERIVED_TYPE& initParamSingleton(Args&&... args) + { + return *initParamSingleton_(std::forward(args)...); + } + + static DERIVED_TYPE* getInstance() + { + SingletonSlot& s = super::slot(); + // Lock-free fast path, identical in spirit to LLSingleton::getInstance(). + if (void* p = s.mFastInstance.load(std::memory_order_acquire)) + { + if (LL_LIKELY(LLSingletonBase::sInitializingDepth.load(std::memory_order_acquire) == 0)) + return static_cast(p); + } + + // In case racing threads call getInstance() at the same moment as + // initParamSingleton(), serialize the calls. + SlotLock lk(s); + + switch (lk->mInitState) + { + case super::UNINITIALIZED: + case super::QUEUED: + super::logerrs({"Uninitialized param singleton ", + super::template classname()}); + break; + + case super::CONSTRUCTING: + super::logerrs({"Tried to access param singleton ", + super::template classname(), + " from singleton constructor!"}); + break; + + case super::INITIALIZING: + // As with LLSingleton, explicitly permit circular calls from + // within initSingleton() + case super::INITIALIZED: + { + // for any valid call, capture dependencies + DERIVED_TYPE* instance = static_cast(lk->mInstance); + super::capture_dependency(instance); + return instance; + } + + case super::DELETED: + super::logerrs({"Trying to access deleted param singleton ", + super::template classname()}); + break; + } + + // should never actually get here; this is to pacify the compiler, + // which assumes control might return from logerrs() + return nullptr; + } + + // instance() is replicated here so it calls + // LLParamSingleton::getInstance() rather than LLSingleton::getInstance() + // -- avoid making getInstance() virtual + static DERIVED_TYPE& instance() + { + return *getInstance(); + } +}; + +/** + * Initialization locked singleton, only derived class can decide when to initialize. + * Starts locked. + * For cases when singleton has a dependency onto something or. + * + * LLLockedSingleton is like an LLParamSingleton with a nullary constructor. + * It cannot be instantiated on demand (instance() or getInstance() call) -- + * it must be instantiated by calling construct(). However, it does + * participate in dependency-ordered LLSingletonBase::deleteAll() processing. + */ +template +class LLLockedSingleton : public LLParamSingleton
+{ + typedef LLParamSingleton
super; + +public: + using super::deleteSingleton; + using super::getInstance; + using super::instance; + using super::instanceExists; + using super::wasDeleted; + + static DT* construct() + { + return &super::initParamSingleton(); + } +}; + /** * Use LLSINGLETON(Foo); at the start of an LLSingleton subclass body * when you want to declare an out-of-line constructor: diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 9ebc267fbd7..adf58042722 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -204,4 +204,121 @@ namespace tut private: \ LLSD mDesc; \ } + + // Declare two otherwise-identical LLParamSingleton classes so we can + // validly initialize each using two different constructors. If we tried + // to test that with a single LLParamSingleton class within the same test + // program, we'd get 'trying to use deleted LLParamSingleton' errors. + PARAMSINGLETON(PSing1); + PARAMSINGLETON(PSing2); + + template<> template<> + void singleton_object_t::test<12>() + { + set_test_name("LLParamSingleton"); + + WrapLLErrs catcherr; + // query methods + ensure("false positive on instanceExists()", ! PSing1::instanceExists()); + ensure("false positive on wasDeleted()", ! PSing1::wasDeleted()); + // try to reference before initializing + std::string threw = catcherr.catch_llerrs([](){ + (void)PSing1::instance(); + }); + ensure_contains("too-early instance() didn't throw", threw, "Uninitialized"); + // getInstance() behaves the same as instance() + threw = catcherr.catch_llerrs([](){ + (void)PSing1::getInstance(); + }); + ensure_contains("too-early getInstance() didn't throw", threw, "Uninitialized"); + // initialize using LLSD::String constructor + PSing1::initParamSingleton("string"); + ensure_equals(PSing1::instance().desc(), "string"); + ensure("false negative on instanceExists()", PSing1::instanceExists()); + // try to initialize again + threw = catcherr.catch_llerrs([](){ + PSing1::initParamSingleton("again"); + }); + ensure_contains("second ctor(string) didn't throw", threw, "twice"); + // try to initialize using the other constructor -- should be + // well-formed, but illegal at runtime + threw = catcherr.catch_llerrs([](){ + PSing1::initParamSingleton(17); + }); + ensure_contains("other ctor(int) didn't throw", threw, "twice"); + PSing1::deleteSingleton(); + ensure("false negative on wasDeleted()", PSing1::wasDeleted()); + threw = catcherr.catch_llerrs([](){ + (void)PSing1::instance(); + }); + ensure_contains("accessed deleted LLParamSingleton", threw, "deleted"); + } + + template<> template<> + void singleton_object_t::test<13>() + { + set_test_name("LLParamSingleton alternate ctor"); + + WrapLLErrs catcherr; + // We don't have to restate all the tests for PSing1. Only test validly + // using the other constructor. + PSing2::initParamSingleton(17); + ensure_equals(PSing2::instance().desc(), "17"); + // can't do it twice + std::string threw = catcherr.catch_llerrs([](){ + PSing2::initParamSingleton(34); + }); + ensure_contains("second ctor(int) didn't throw", threw, "twice"); + // can't use the other constructor either + threw = catcherr.catch_llerrs([](){ + PSing2::initParamSingleton("string"); + }); + ensure_contains("other ctor(string) didn't throw", threw, "twice"); + } + + class CircularPCtor: public LLParamSingleton + { + LLSINGLETON(CircularPCtor) + { + // never mind indirection, just go straight for the circularity + (void)instance(); + } + }; + + template<> template<> + void singleton_object_t::test<14>() + { + set_test_name("Circular LLParamSingleton constructor"); + WrapLLErrs catcherr; + std::string threw = catcherr.catch_llerrs([](){ + CircularPCtor::initParamSingleton(); + }); + ensure_contains("constructor circularity didn't throw", threw, "constructor"); + } + + class CircularPInit: public LLParamSingleton + { + LLSINGLETON_EMPTY_CTOR(CircularPInit); + public: + virtual void initSingleton() override + { + // never mind indirection, just go straight for the circularity + CircularPInit *pt = getInstance(); + if (!pt) + { + throw; + } + } + }; + + template<> template<> + void singleton_object_t::test<15>() + { + set_test_name("Circular LLParamSingleton initSingleton()"); + WrapLLErrs catcherr; + std::string threw = catcherr.catch_llerrs([](){ + CircularPInit::initParamSingleton(); + }); + ensure("initSingleton() circularity threw", threw.empty()); + } } From 0d54ec83c1e41ae3b10a0c64d07ddb20d938f9f0 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 02:32:30 -0400 Subject: [PATCH 2/9] Restore usage of LLSingleton and LLParamSingleton --- indra/llappearance/llwearabletype.cpp | 4 + indra/llappearance/llwearabletype.h | 8 +- indra/llcommon/llassettype.cpp | 37 +++++ indra/llcommon/llassettype.h | 39 ----- indra/llcommon/llcoros.cpp | 8 +- indra/llcommon/llcoros.h | 7 +- indra/llcommon/llsingleton.h | 2 +- indra/llcommon/tests/llcond_test.cpp | 8 - indra/llcommon/tests/lleventcoro_test.cpp | 9 -- indra/llcommon/tests/workqueue_test.cpp | 8 - indra/llfilesystem/lldiskcache.h | 11 +- indra/llinventory/llfoldertype.cpp | 35 ++++ indra/llinventory/llfoldertype.h | 34 ---- indra/llinventory/llinventorysettings.h | 8 +- indra/llinventory/llinventorytype.cpp | 37 +++++ indra/llinventory/llinventorytype.h | 37 ----- .../llinventory/tests/inventorymisc_test.cpp | 12 -- indra/llmessage/llavatarnamecache.h | 7 +- .../tests/llcoproceduremanager_test.cpp | 2 - indra/llui/llcommandmanager.h | 6 +- indra/llui/llemojidictionary.cpp | 3 +- indra/llui/llemojidictionary.h | 8 +- indra/llui/llui.cpp | 6 +- indra/llui/lluicolortable.h | 5 +- indra/llui/lluictrlfactory.cpp | 2 +- indra/llui/lluictrlfactory.h | 10 +- indra/llui/tests/llemojidictionary_test.cpp | 40 ++--- indra/newview/alstreaminfo.h | 6 +- indra/newview/altoolalign.h | 6 +- indra/newview/llappviewer.cpp | 152 ++---------------- indra/newview/llcontrolavatar.h | 6 +- .../lldonotdisturbnotificationstorage.h | 8 +- indra/newview/llhudmanager.cpp | 7 +- indra/newview/llhudmanager.h | 8 +- indra/newview/llinventoryicon.cpp | 14 ++ indra/newview/llinventoryicon.h | 11 -- indra/newview/llmaterialmgr.h | 6 +- indra/newview/llmutelist.cpp | 10 +- indra/newview/llmutelist.h | 8 +- .../newview/llpersistentnotificationstorage.h | 6 +- indra/newview/llstartup.cpp | 6 +- indra/newview/lltoolcomp.h | 36 ++--- indra/newview/lltooldraganddrop.h | 5 +- indra/newview/lltoolface.h | 6 +- indra/newview/lltoolfocus.h | 6 +- indra/newview/lltoolgrab.h | 5 +- indra/newview/lltoolindividual.h | 6 +- indra/newview/lltoolmgr.h | 6 +- indra/newview/lltoolpie.h | 4 +- indra/newview/lltoolpipette.h | 6 +- indra/newview/lltoolselectland.h | 6 +- indra/newview/llviewerfoldertype.cpp | 74 +++++++++ indra/newview/llviewerfoldertype.h | 75 --------- indra/newview/llviewerjoystick.h | 7 +- indra/newview/llviewermedia.cpp | 29 ++-- indra/newview/llviewermedia.h | 8 +- indra/newview/llviewernetwork.h | 7 +- indra/newview/llviewerparcelmgr.h | 6 +- indra/newview/llviewerpartsim.h | 5 +- indra/newview/llvocache.h | 5 +- indra/newview/llvoiceclient.cpp | 1 - indra/newview/llvoiceclient.h | 6 +- indra/newview/llvoicewebrtc.cpp | 4 + indra/newview/llvoicewebrtc.h | 8 +- indra/newview/llworldmap.h | 6 +- indra/newview/rlvhelper.h | 8 +- indra/newview/tests/llslurl_test.cpp | 2 - indra/newview/tests/llviewernetwork_test.cpp | 4 - indra/newview/tests/llworldmap_test.cpp | 4 +- .../login/tests/lllogin_test.cpp | 5 +- 70 files changed, 421 insertions(+), 576 deletions(-) diff --git a/indra/llappearance/llwearabletype.cpp b/indra/llappearance/llwearabletype.cpp index da886fd4339..1ec8732a2bc 100644 --- a/indra/llappearance/llwearabletype.cpp +++ b/indra/llappearance/llwearabletype.cpp @@ -70,6 +70,10 @@ LLWearableType::~LLWearableType() { } +void LLWearableType::initSingleton() +{ +} + LLWearableType::EType LLWearableType::typeNameToType(const std::string& type_name) { const LLWearableType::EType wearable = mDictionary.lookup(type_name); diff --git a/indra/llappearance/llwearabletype.h b/indra/llappearance/llwearabletype.h index 45cdf3baf9b..19b9f30d45d 100644 --- a/indra/llappearance/llwearabletype.h +++ b/indra/llappearance/llwearabletype.h @@ -33,12 +33,12 @@ #include "llsingleton.h" #include "llinvtranslationbrdg.h" -class LLWearableType : public LLSimpleton +class LLWearableType : public LLParamSingleton { -public: - LLWearableType(LLTranslationBridge::ptr_t &trans); + LLSINGLETON(LLWearableType, LLTranslationBridge::ptr_t &trans); ~LLWearableType(); - + void initSingleton() override; +public: enum EType { WT_SHAPE = 0, diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 04a6dbefbda..9672a3262be 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -27,8 +27,45 @@ #include "linden_common.h" #include "llassettype.h" +#include "lldictionary.h" #include "llmemory.h" #include "llsd.h" +#include "llsingleton.h" + +///---------------------------------------------------------------------------- +/// Class LLAssetType +///---------------------------------------------------------------------------- +struct AssetEntry : public LLDictionaryEntry +{ + AssetEntry(const char *desc_name, + const char *type_name, // 8 character limit! + const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one + bool can_link, // can you create a link to this type? + bool can_fetch, // can you fetch this asset by ID? + bool can_know) // can you see this asset's ID? + : + LLDictionaryEntry(desc_name), + mTypeName(type_name), + mHumanName(human_name), + mCanLink(can_link), + mCanFetch(can_fetch), + mCanKnow(can_know) + { + llassert(strlen(mTypeName) <= 8); + } + + const char *mTypeName; + const char *mHumanName; + bool mCanLink; + bool mCanFetch; + bool mCanKnow; +}; + +class LLAssetDictionary : public LLSingleton, + public LLDictionary +{ + LLSINGLETON(LLAssetDictionary); +}; LLAssetDictionary::LLAssetDictionary() { diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 6b779877bee..17177d81c3c 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -27,9 +27,6 @@ #ifndef LL_LLASSETTYPE_H #define LL_LLASSETTYPE_H -#include "lldictionary.h" -#include "llsingleton.h" - #include class LL_COMMON_API LLAssetType @@ -177,40 +174,4 @@ class LL_COMMON_API LLAssetType ~LLAssetType() {} }; -///---------------------------------------------------------------------------- -/// Class LLAssetType -///---------------------------------------------------------------------------- -struct AssetEntry : public LLDictionaryEntry -{ - AssetEntry(const char *desc_name, - const char *type_name, // 8 character limit! - const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one - bool can_link, // can you create a link to this type? - bool can_fetch, // can you fetch this asset by ID? - bool can_know) // can you see this asset's ID? - : - LLDictionaryEntry(desc_name), - mTypeName(type_name), - mHumanName(human_name), - mCanLink(can_link), - mCanFetch(can_fetch), - mCanKnow(can_know) - { - llassert(strlen(mTypeName) <= 8); - } - - const char *mTypeName; - const char *mHumanName; - bool mCanLink; - bool mCanFetch; - bool mCanKnow; -}; - -class LLAssetDictionary : public LLSimpleton, - public LLDictionary -{ -public: - LLAssetDictionary(); -}; - #endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 8da91d1f0a4..9e95d9c85f1 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -83,7 +83,7 @@ LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) { CoroData* current{ nullptr }; // be careful about attempted accesses in the final throes of app shutdown - if (instanceExists()) + if (! wasDeleted()) { current = instance().mCurrent.get(); } @@ -148,6 +148,10 @@ LLCoros::LLCoros(): } LLCoros::~LLCoros() +{ +} + +void LLCoros::cleanupSingleton() { // Some of the coroutines (like voice) will depend onto // origin singletons, so clean coros before deleting those @@ -413,7 +417,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) //static void LLCoros::checkStop() { - if (!instanceExists()) + if (wasDeleted()) { LLTHROW(Shutdown("LLCoros was deleted")); } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 0c73b4227a8..bb66ae66bab 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -88,12 +88,13 @@ namespace boost { * can provide diagnostic info: we can look up the name of the * currently-running coroutine. */ -class LL_COMMON_API LLCoros: public LLSimpleton +class LL_COMMON_API LLCoros: public LLSingleton { -public: - LLCoros(); + LLSINGLETON(LLCoros); ~LLCoros(); + void cleanupSingleton() override; +public: // For debugging, return true if on the main coroutine for the current thread // Code that should not be executed from a coroutine should be protected by // llassert(LLCoros::on_main_coro()) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 507921a023c..b2b8f9c1aef 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -749,7 +749,7 @@ class LLParamSingleton : public LLSingleton // mInitState already set. SlotLock lk; // For organizational purposes this function shouldn't be called twice - if (lk->mInitState != super::UNINITIALIZED) + if (lk->mInitState != super::UNINITIALIZED && lk->mInitState != super::DELETED) { super::logerrs({"Tried to initialize singleton ", super::template classname(), diff --git a/indra/llcommon/tests/llcond_test.cpp b/indra/llcommon/tests/llcond_test.cpp index de9571c12bc..f2a302ed134 100644 --- a/indra/llcommon/tests/llcond_test.cpp +++ b/indra/llcommon/tests/llcond_test.cpp @@ -27,14 +27,6 @@ namespace tut { struct llcond_data { - llcond_data() - { - LLCoros::createInstance(); - } - ~llcond_data() - { - LLCoros::deleteSingleton(); - } LLScalarCond cond{0}; }; typedef test_group llcond_group; diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 2d2541e2428..05c25e6627a 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -92,15 +92,6 @@ namespace tut { struct test_data { - test_data() - { - LLCoros::createInstance(); - } - ~test_data() - { - LLCoros::deleteSingleton(); - } - Sync mSync; ImmediateAPI immediateAPI{mSync}; std::string replyName, errorName, threw, stringdata; diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp index 7b0683a7478..209b6b868c2 100644 --- a/indra/llcommon/tests/workqueue_test.cpp +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -38,14 +38,6 @@ namespace tut { struct workqueue_data { - workqueue_data() - { - LLCoros::createInstance(); - } - ~workqueue_data() - { - LLCoros::deleteSingleton(); - } WorkSchedule queue{"queue"}; }; typedef test_group workqueue_group; diff --git a/indra/llfilesystem/lldiskcache.h b/indra/llfilesystem/lldiskcache.h index f1dc617051e..48d72fb7c42 100644 --- a/indra/llfilesystem/lldiskcache.h +++ b/indra/llfilesystem/lldiskcache.h @@ -65,10 +65,17 @@ #include "llsingleton.h" class LLDiskCache : - public LLSimpleton + public LLParamSingleton { public: - LLDiskCache( + /** + * Since this is using the LLSingleton pattern but we + * want to allow the constructor to be called first + * with various parameters, we also invoke the + * LLParamSingleton idiom and use it to initialize + * the class via a call in LLAppViewer. + */ + LLSINGLETON(LLDiskCache, /** * The full name of the cache folder - typically a * a child of the main Viewer cache directory. Defined diff --git a/indra/llinventory/llfoldertype.cpp b/indra/llinventory/llfoldertype.cpp index 4ec97f35ada..573d7d4778f 100644 --- a/indra/llinventory/llfoldertype.cpp +++ b/indra/llinventory/llfoldertype.cpp @@ -32,6 +32,41 @@ #include "llsd.h" #include "llsingleton.h" +///---------------------------------------------------------------------------- +/// Class LLFolderType +///---------------------------------------------------------------------------- +struct FolderEntry : public LLDictionaryEntry +{ + FolderEntry(const std::string &type_name, // 8 character limit! + bool is_protected, // can the viewer change categories of this type? + bool is_automatic, // always made before first login? + bool is_singleton // should exist as a unique copy under root + ) + : + LLDictionaryEntry(type_name), + mIsProtected(is_protected), + mIsAutomatic(is_automatic), + mIsSingleton(is_singleton) + { + llassert(type_name.length() <= 8); + } + + const bool mIsProtected; + const bool mIsAutomatic; + const bool mIsSingleton; +}; + +class LLFolderDictionary : public LLSingleton, + public LLDictionary +{ + LLSINGLETON(LLFolderDictionary); +protected: + virtual LLFolderType::EType notFound() const override + { + return LLFolderType::FT_NONE; + } +}; + // Folder types // // PROTECTED means that folders of this type can't be moved, deleted diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index e0719566b60..7d3732fa954 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -29,8 +29,6 @@ #include #include "llassettype.h" -#include "lldictionary.h" -#include "llsingleton.h" // This class handles folder types (similar to assettype, except for folders) // and operations on those. @@ -127,36 +125,4 @@ class LL_COMMON_API LLFolderType ~LLFolderType() {} }; -///---------------------------------------------------------------------------- -/// Class LLFolderType -///---------------------------------------------------------------------------- -struct FolderEntry : public LLDictionaryEntry -{ - FolderEntry(const std::string& type_name, // 8 character limit! - bool is_protected, // can the viewer change categories of this type? - bool is_automatic, // always made before first login? - bool is_singleton // should exist as a unique copy under root - ) : - LLDictionaryEntry(type_name), - mIsProtected(is_protected), - mIsAutomatic(is_automatic), - mIsSingleton(is_singleton) - { - llassert(type_name.length() <= 8); - } - - const bool mIsProtected; - const bool mIsAutomatic; - const bool mIsSingleton; -}; - -class LLFolderDictionary : public LLSimpleton, public LLDictionary -{ -public: - LLFolderDictionary(); - -protected: - virtual LLFolderType::EType notFound() const override { return LLFolderType::FT_NONE; } -}; - #endif // LL_LLFOLDERTYPE_H diff --git a/indra/llinventory/llinventorysettings.h b/indra/llinventory/llinventorysettings.h index 6d6bc836d89..6b6685d088d 100644 --- a/indra/llinventory/llinventorysettings.h +++ b/indra/llinventory/llinventorysettings.h @@ -32,14 +32,14 @@ #include "llinvtranslationbrdg.h" #include "llsingleton.h" -class LLSettingsType : public LLSimpleton +class LLSettingsType : public LLParamSingleton { + LLSINGLETON(LLSettingsType, LLTranslationBridge::ptr_t &trans); + ~LLSettingsType(); + friend struct SettingsEntry; public: - LLSettingsType(LLTranslationBridge::ptr_t& trans); - ~LLSettingsType(); - enum type_e { ST_SKY = 0, diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 2bbdc146789..8fa8983d3c4 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -27,9 +27,46 @@ #include "linden_common.h" #include "llinventorytype.h" +#include "lldictionary.h" +#include "llmemory.h" +#include "llsingleton.h" static const std::string empty_string; +///---------------------------------------------------------------------------- +/// Class LLInventoryType +///---------------------------------------------------------------------------- +struct InventoryEntry : public LLDictionaryEntry +{ + InventoryEntry(const std::string &name, // unlike asset type names, not limited to 8 characters; need not match asset type names + const std::string &human_name, // for decoding to human readable form; put any and as many printable characters you want in each one. + int num_asset_types = 0, ...) + : + LLDictionaryEntry(name), + mHumanName(human_name) + { + va_list argp; + va_start(argp, num_asset_types); + // Read in local textures + for (U8 i=0; i < num_asset_types; i++) + { + LLAssetType::EType t = (LLAssetType::EType)va_arg(argp,int); + mAssetTypes.push_back(t); + } + va_end(argp); + } + + const std::string mHumanName; + typedef std::vector asset_vec_t; + asset_vec_t mAssetTypes; +}; + +class LLInventoryDictionary : public LLSingleton, + public LLDictionary +{ + LLSINGLETON(LLInventoryDictionary); +}; + LLInventoryDictionary::LLInventoryDictionary() { addEntry(LLInventoryType::IT_TEXTURE, new InventoryEntry("texture", "texture", 1, LLAssetType::AT_TEXTURE)); diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 2b621f02c6f..0627b8df3c7 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -28,8 +28,6 @@ #define LLINVENTORYTYPE_H #include "llassettype.h" -#include "lldictionary.h" -#include "llsingleton.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryType @@ -165,39 +163,4 @@ enum ScriptSubtype_t bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type, LLAssetType::EType asset_type); -///---------------------------------------------------------------------------- -/// Class LLInventoryType -///---------------------------------------------------------------------------- -struct InventoryEntry : public LLDictionaryEntry -{ - InventoryEntry(const std::string &name, // unlike asset type names, not limited to 8 characters; need not match asset type names - const std::string &human_name, // for decoding to human readable form; put any and as many printable characters you want in each one. - int num_asset_types = 0, ...) - : - LLDictionaryEntry(name), - mHumanName(human_name) - { - va_list argp; - va_start(argp, num_asset_types); - // Read in local textures - for (U8 i=0; i < num_asset_types; i++) - { - LLAssetType::EType t = (LLAssetType::EType)va_arg(argp,int); - mAssetTypes.push_back(t); - } - va_end(argp); - } - - const std::string mHumanName; - typedef std::vector asset_vec_t; - asset_vec_t mAssetTypes; -}; - -class LLInventoryDictionary : public LLSimpleton, - public LLDictionary -{ -public: - LLInventoryDictionary(); -}; - #endif diff --git a/indra/llinventory/tests/inventorymisc_test.cpp b/indra/llinventory/tests/inventorymisc_test.cpp index 9ca59d2c1df..f11a4c3bf71 100644 --- a/indra/llinventory/tests/inventorymisc_test.cpp +++ b/indra/llinventory/tests/inventorymisc_test.cpp @@ -127,18 +127,6 @@ namespace tut { struct inventory_data { - inventory_data() - { - LLAssetDictionary::createInstance(); - LLFolderDictionary::createInstance(); - LLInventoryDictionary::createInstance(); - } - ~inventory_data() - { - LLInventoryDictionary::deleteSingleton(); - LLFolderDictionary::deleteSingleton(); - LLAssetDictionary::deleteSingleton(); - } }; typedef test_group inventory_test; typedef inventory_test::object inventory_object; diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 7b0e8053a9e..75837466d78 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -38,12 +38,11 @@ class LLSD; class LLUUID; -class LLAvatarNameCache : public LLSimpleton +class LLAvatarNameCache : public LLSingleton { -public: - LLAvatarNameCache(); + LLSINGLETON(LLAvatarNameCache); ~LLAvatarNameCache(); - +public: typedef boost::signals2::signal use_display_name_signal_t; typedef std::function account_name_changed_callback_t; diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp index a6514b79e8d..0a77fd218b0 100644 --- a/indra/llmessage/tests/llcoproceduremanager_test.cpp +++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp @@ -74,13 +74,11 @@ namespace tut { coproceduremanager_test() { - LLCoros::createInstance(); } ~coproceduremanager_test() { LLCoprocedureManager::instance().close(); - LLCoros::deleteSingleton(); } }; typedef test_group coproceduremanager_t; diff --git a/indra/llui/llcommandmanager.h b/indra/llui/llcommandmanager.h index 6e1742ab89c..e6df0d3a4bf 100644 --- a/indra/llui/llcommandmanager.h +++ b/indra/llui/llcommandmanager.h @@ -171,12 +171,12 @@ class LLCommand class LLCommandManager -: public LLSimpleton +: public LLSingleton { -public: - LLCommandManager(); + LLSINGLETON(LLCommandManager); ~LLCommandManager(); +public: struct Params : public LLInitParam::Block { Multiple< LLCommand::Params, AtLeast<1> > commands; diff --git a/indra/llui/llemojidictionary.cpp b/indra/llui/llemojidictionary.cpp index a8403746726..919a9e98f1b 100644 --- a/indra/llui/llemojidictionary.cpp +++ b/indra/llui/llemojidictionary.cpp @@ -144,8 +144,7 @@ LLEmojiDictionary::LLEmojiDictionary() // static void LLEmojiDictionary::initClass() { - LLEmojiDictionary::createInstance(); - LLEmojiDictionary* pThis = LLEmojiDictionary::getInstance(); + LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton(); pThis->loadTranslations(); pThis->loadGroups(); diff --git a/indra/llui/llemojidictionary.h b/indra/llui/llemojidictionary.h index aea5f8cfe21..ade9e5bdd9f 100644 --- a/indra/llui/llemojidictionary.h +++ b/indra/llui/llemojidictionary.h @@ -105,12 +105,12 @@ struct LLEmojiSearchResult // LLEmojiDictionary class // -class LLEmojiDictionary : public LLSimpleton, public LLInitClass +class LLEmojiDictionary : public LLParamSingleton, public LLInitClass { -public: - LLEmojiDictionary(); - ~LLEmojiDictionary() = default; + LLSINGLETON(LLEmojiDictionary); + ~LLEmojiDictionary() override {}; +public: typedef std::map cat2cat_map_t; typedef std::map cat2group_map_t; // Keyed by full emoji sequence (LLWString) so ZWJ families and flag diff --git a/indra/llui/llui.cpp b/indra/llui/llui.cpp index b4cb6084728..6fca1a0cbf3 100644 --- a/indra/llui/llui.cpp +++ b/indra/llui/llui.cpp @@ -157,7 +157,6 @@ mRootView(NULL), mHelpImpl(NULL) { LL_PROFILE_ZONE_SCOPED; - LLUICtrlFactory::createInstance(); LLRender2D::createInstance(image_provider); LLSpellChecker::createInstance(); @@ -198,17 +197,14 @@ mHelpImpl(NULL) LLUICtrl::EnableCallbackRegistry::defaultRegistrar().add("Floater.CanShow", boost::bind(&LLFloaterReg::canShowInstance, _2, LLSD())); // [/RLVa:KB] - // Create the command manager and parse the master list of commands - LLCommandManager::createInstance(); + // Parse the master list of commands LLCommandManager::load(); } LLUI::~LLUI() { - LLCommandManager::deleteSingleton(); LLSpellChecker::deleteSingleton(); LLRender2D::deleteSingleton(); - LLUICtrlFactory::deleteSingleton(); } void LLUI::setPopupFuncs(const add_popup_t& add_popup, const remove_popup_t& remove_popup, const clear_popups_t& clear_popups) diff --git a/indra/llui/lluicolortable.h b/indra/llui/lluicolortable.h index 85a49e9bdaa..6f6f8b834bb 100644 --- a/indra/llui/lluicolortable.h +++ b/indra/llui/lluicolortable.h @@ -36,16 +36,15 @@ class LLUIColor; -class LLUIColorTable : public LLSimpleton +class LLUIColorTable : public LLSingleton { + LLSINGLETON_EMPTY_CTOR(LLUIColorTable); LOG_CLASS(LLUIColorTable); // consider using sorted vector, can be much faster typedef boost::unordered_map> string_color_map_t; public: - LLUIColorTable() = default; - struct ColorParams : LLInitParam::ChoiceBlock { Alternative value; diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index 740f187ed8d..33ffc3dfc63 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -67,7 +67,7 @@ class LLUICtrlLocate : public LLUICtrl static LLDefaultChildRegistry::Register r1("locate"); // Build time optimization, generate this once in .cpp file -template class LLUICtrlFactory* LLSimpleton::getInstance(); +template class LLUICtrlFactory* LLSingleton::getInstance(); //----------------------------------------------------------------------------- // LLUICtrlFactory() diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 1ad27e4c069..f44b4ba4dcf 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -81,16 +81,14 @@ class LLWidgetNameRegistry // Build time optimization, generate this once in .cpp file #ifndef LLUICTRLFACTORY_CPP -extern template class LLUICtrlFactory* LLSimpleton::getInstance(); +extern template class LLUICtrlFactory* LLSingleton::getInstance(); #endif -class LLUICtrlFactory : public LLSimpleton +class LLUICtrlFactory : public LLSingleton { -public: - LLUICtrlFactory(); + LLSINGLETON(LLUICtrlFactory); ~LLUICtrlFactory(); -private: // only partial specialization allowed in inner classes, so use extra dummy parameter template class ParamDefaults @@ -316,7 +314,7 @@ LLChildRegistry::Register::Register(const char* tag, LLWidgetCreator : LLChildRegistry::StaticRegistrar(tag, func == nullptr ? (LLWidgetCreatorFunc)&LLUICtrlFactory::defaultBuilder : func) { // add this widget to various registries - LLUICtrlFactory::registerWidget(typeid(T), typeid(typename T::Params), tag); + LLUICtrlFactory::instance().registerWidget(typeid(T), typeid(typename T::Params), tag); // since registry_t depends on T, do this in line here // TODO: uncomment this for schema generation diff --git a/indra/llui/tests/llemojidictionary_test.cpp b/indra/llui/tests/llemojidictionary_test.cpp index 90afd849100..29acd3e71bf 100644 --- a/indra/llui/tests/llemojidictionary_test.cpp +++ b/indra/llui/tests/llemojidictionary_test.cpp @@ -98,10 +98,14 @@ namespace tut { struct llemojidictionary_data { - // Construct a dictionary directly. Only pure-logic methods are - // exercised, so the singleton's normal initClass() flow (which - // touches gDirUtilp) is intentionally bypassed. - LLEmojiDictionary dict; + llemojidictionary_data() + { + LLEmojiDictionary::initParamSingleton(); + } + ~llemojidictionary_data() + { + LLEmojiDictionary::deleteSingleton(); + } }; typedef test_group factory; typedef factory::object object; @@ -119,7 +123,7 @@ namespace tut void object::test<1>() { LLEmojiDescriptor d = make_thumbs_up_descriptor(); - const LLEmojiVariant* v = dict.findVariant(d, 3, -1); + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(d, 3, -1); ensure("tone-3 variant found", v != nullptr); ensure_equals("tone matches", v->Tone, U8(3)); } @@ -129,7 +133,7 @@ namespace tut void object::test<2>() { LLEmojiDescriptor d = make_thumbs_up_descriptor(); - const LLEmojiVariant* v = dict.findVariant(d, 0, -1); + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(d, 0, -1); ensure("no preference returns nullptr", v == nullptr); } @@ -139,7 +143,7 @@ namespace tut { LLEmojiDescriptor empty; empty.Character = utf8str_to_wstring("\xF0\x9F\x92\xA9"); // 💩 - const LLEmojiVariant* v = dict.findVariant(empty, 3, -1); + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(empty, 3, -1); ensure("no variants returns nullptr", v == nullptr); } @@ -148,7 +152,7 @@ namespace tut void object::test<4>() { LLEmojiDescriptor d = make_astronaut_descriptor(); - const LLEmojiVariant* v = dict.findVariant(d, 3, 0); // tone=3, man + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(d, 3, 0); // tone=3, man ensure("variant found", v != nullptr); ensure_equals("tone matches", v->Tone, U8(3)); ensure_equals("gender matches", v->Gender, S8(0)); @@ -161,7 +165,7 @@ namespace tut void object::test<5>() { LLEmojiDescriptor d = make_astronaut_descriptor(); - const LLEmojiVariant* v = dict.findVariant(d, 3, -1); + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(d, 3, -1); ensure("variant found", v != nullptr); ensure_equals("tone matches", v->Tone, U8(3)); // Gender preference unset — best match should have Gender=2 @@ -181,7 +185,7 @@ namespace tut // Ask tone=3, gender=woman, but the descriptor has only // gender-neutral variants. Should still return the tone-3 // variant (partial match). - const LLEmojiVariant* v = dict.findVariant(d, 3, 1); + const LLEmojiVariant* v = LLEmojiDictionary::instance().findVariant(d, 3, 1); ensure("partial match accepted", v != nullptr); ensure_equals("tone matches", v->Tone, U8(3)); } @@ -289,9 +293,9 @@ namespace tut template<> template<> void object::test<10>() { - dict.loadEmojisFromSD(make_thumbs_up_dictionary_blob()); + LLEmojiDictionary::instance().loadEmojisFromSD(make_thumbs_up_dictionary_blob()); ensure("base char returned", - dict.getEmojiFromShortCode(":thumbs_up:") == utf8str_to_wstring("\xF0\x9F\x91\x8D")); + LLEmojiDictionary::instance().getEmojiFromShortCode(":thumbs_up:") == utf8str_to_wstring("\xF0\x9F\x91\x8D")); } // getEmojiFromShortCode returns the VARIANT character for a variant @@ -299,9 +303,9 @@ namespace tut template<> template<> void object::test<11>() { - dict.loadEmojisFromSD(make_thumbs_up_dictionary_blob()); + LLEmojiDictionary::instance().loadEmojisFromSD(make_thumbs_up_dictionary_blob()); ensure("variant char returned", - dict.getEmojiFromShortCode(":thumbs_up_dark_skin_tone:") + LLEmojiDictionary::instance().getEmojiFromShortCode(":thumbs_up_dark_skin_tone:") == utf8str_to_wstring("\xF0\x9F\x91\x8D\xF0\x9F\x8F\xBF")); } @@ -309,8 +313,8 @@ namespace tut template<> template<> void object::test<12>() { - dict.loadEmojisFromSD(make_thumbs_up_dictionary_blob()); - ensure("empty for unknown", dict.getEmojiFromShortCode(":nonsense:").empty()); + LLEmojiDictionary::instance().loadEmojisFromSD(make_thumbs_up_dictionary_blob()); + ensure("empty for unknown", LLEmojiDictionary::instance().getEmojiFromShortCode(":nonsense:").empty()); } // findByShortCode prefix-matching now surfaces variants — typing @@ -319,10 +323,10 @@ namespace tut template<> template<> void object::test<13>() { - dict.loadEmojisFromSD(make_thumbs_up_dictionary_blob()); + LLEmojiDictionary::instance().loadEmojisFromSD(make_thumbs_up_dictionary_blob()); std::vector results; - dict.findByShortCode(results, ":thumbs_up_d"); + LLEmojiDictionary::instance().findByShortCode(results, ":thumbs_up_d"); ensure("at least one result", !results.empty()); const LLWString expected_dark = utf8str_to_wstring("\xF0\x9F\x91\x8D\xF0\x9F\x8F\xBF"); diff --git a/indra/newview/alstreaminfo.h b/indra/newview/alstreaminfo.h index 85b82cc40cc..a0813f96e99 100644 --- a/indra/newview/alstreaminfo.h +++ b/indra/newview/alstreaminfo.h @@ -33,13 +33,11 @@ #include "llsingleton.h" -class ALStreamInfo : public LLSimpleton +class ALStreamInfo : public LLSingleton { -public: - ALStreamInfo(); + LLSINGLETON(ALStreamInfo); ~ALStreamInfo(); -private: void handleMetadataUpdate(const LLSD& metadata); boost::signals2::connection mMetadataConnection; diff --git a/indra/newview/altoolalign.h b/indra/newview/altoolalign.h index 5bbe44298cc..28857ddf084 100644 --- a/indra/newview/altoolalign.h +++ b/indra/newview/altoolalign.h @@ -33,12 +33,12 @@ class LLPickInfo; class LLToolSelectRect; class ALToolAlign final -: public LLTool, public LLSimpleton +: public LLTool, public LLSingleton { -public: - ALToolAlign(); + LLSINGLETON(ALToolAlign); ~ALToolAlign() = default; +public: void handleSelect() override; void handleDeselect() override; bool handleMouseDown(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fcc2161f1ac..0f320a53f31 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -231,7 +231,6 @@ #include "llfloatersimplesnapshot.h" #include "llfloatersnapshot.h" #include "llsidepanelinventory.h" -#include "llinventorymodelbackgroundfetch.h" // includes for idle() idleShutdown() #include "llviewercontrol.h" @@ -261,26 +260,9 @@ using namespace LL; #include "llmachineid.h" #include "llcleanup.h" -#include "altoolalign.h" #include "llinventoryicon.h" #include "llcoproceduremanager.h" #include "llviewereventrecorder.h" -#include "llcontrolavatar.h" -#include "lldonotdisturbnotificationstorage.h" -#include "llemojidictionary.h" -#include "llfoldertype.h" -#include "llmaterialmgr.h" -#include "llpersistentnotificationstorage.h" -#include "lltoolcomp.h" -#include "lltooldraganddrop.h" -#include "lltoolface.h" -#include "lltoolfocus.h" -#include "lltoolgrab.h" -#include "lltoolindividual.h" -#include "lltoolpie.h" -#include "lltoolpipette.h" -#include "lltoolselectland.h" -#include "llviewerfoldertype.h" #include "alstreaminfo.h" @@ -820,7 +802,7 @@ bool LLAppViewer::init() // initialize the LLSettingsType translation bridge. LLTranslationBridge::ptr_t trans = std::make_shared(); - LLSettingsType::createInstance(trans); + LLSettingsType::initParamSingleton(trans); // initialize SSE options LLVector4a::initClass(); @@ -839,9 +821,6 @@ bool LLAppViewer::init() // init_default_trans_args(); - // Initialize ui color table singleton - LLUIColorTable::createInstance(); - // Initalize libxml2 xmlInitParser(); @@ -855,17 +834,6 @@ bool LLAppViewer::init() LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ; - // Init dictionary simpletons - LLInventoryDictionary::createInstance(); - LLAssetDictionary::createInstance(); - LLFolderDictionary::createInstance(); - LLViewerFolderDictionary::createInstance(); - LLIconDictionary::createInstance(); - RlvBehaviourDictionary::createInstance(); - - // Init coroutine manager - LLCoros::createInstance(); - //set the max heap size. initMaxHeapSize() ; LLCoros::instance().setStackSize(gSavedSettings.getS32("CoroutineStackSize")); @@ -938,7 +906,7 @@ bool LLAppViewer::init() // initialize LLWearableType translation bridge. // Will immediately use LLTranslationBridge to init LLWearableDictionary - LLWearableType::createInstance(trans); + LLWearableType::initParamSingleton(trans); // Setup notifications after LLUI::initClass() has been called. LLNotifications::instance(); @@ -988,6 +956,8 @@ bool LLAppViewer::init() ///////////////////////////////////////////////// + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated + LLViewerFloaterReg::registerFloaters(); ///////////////////////////////////////////////// @@ -1056,16 +1026,6 @@ bool LLAppViewer::init() LLViewerEventRecorder::createInstance(); LLWatchdog::createInstance(); - // Init parcel manager, name cache, and mute list simpletons - LLViewerParcelMgr::createInstance(); - LLAvatarNameCache::createInstance(); - LLMuteList::createInstance(); - - // Init media before initWindow(): main_view.xml constructs LLProgressView, - // whose postBuild() calls LLViewerMedia::getInstance(). - LLViewerMedia::createInstance(); - - // Initialize tool manager if not already instantiated // // Initialize the window // @@ -1220,17 +1180,9 @@ bool LLAppViewer::init() gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; - // Create joystick singleton and init if enabled + if (gSavedSettings.getBOOL("JoystickEnabled")) { - LLViewerJoystick::createInstance(); - - if (gSavedSettings.getBOOL("JoystickEnabled")) - { - LLViewerJoystick::getInstance()->init(false); - } - - joystick = LLViewerJoystick::getInstance(); - joystick->setNeedsReset(true); + LLViewerJoystick::getInstance()->init(false); } try @@ -1328,42 +1280,21 @@ bool LLAppViewer::init() // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated. LLVoiceChannel::initClass(); - LLVoiceClient::createInstance(gServicePump); + LLVoiceClient::initParamSingleton(gServicePump); LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLFloaterIMContainer::onCurrentChannelChanged, _1), true); + joystick = LLViewerJoystick::getInstance(); + joystick->setNeedsReset(true); /*----------------------------------------------------------------------*/ // Load User's bindings loadKeyBindings(); //LLSimpleton creations LLEnvironment::createInstance(); - LLViewerPartSim::createInstance(); LLWorld::createInstance(); LLViewerStatsRecorder::createInstance(); LLSelectMgr::createInstance(); LLViewerCamera::createInstance(); - LLMaterialMgr::createInstance(); - LLHUDManager::createInstance(); - LLWorldMap::createInstance(); - LLObjectSignaledAnimationMap::createInstance(); - - // Initialize tool manager and tools - LLToolSelectLand::createInstance(); - LLToolIndividual::createInstance(); - LLToolCompInspect::createInstance(); - LLToolCompTranslate::createInstance(); - LLToolCompScale::createInstance(); - LLToolCompRotate::createInstance(); - LLToolCompCreate::createInstance(); - ALToolAlign::createInstance(); - LLToolCompGun::createInstance(); - LLToolFace::createInstance(); - LLToolPipette::createInstance(); - LLToolGrab::createInstance(); - LLToolCamera::createInstance(); - LLToolDragAndDrop::createInstance(); - LLToolPie::createInstance(); - LLToolMgr::createInstance(); gSavedSettings.setU32("DebugQualityPerformance", gSavedSettings.getU32("RenderQualityPerformance")); @@ -1918,7 +1849,7 @@ bool LLAppViewer::cleanup() // Note: this is where gHUDManager used to be deleted. if(LLHUDManager::instanceExists()) { - LLHUDManager::deleteSingleton(); + LLHUDManager::getInstance()->shutdownClass(); } delete gAssetStorage; @@ -1990,7 +1921,6 @@ bool LLAppViewer::cleanup() // Cleanup Inventory after the UI since it will delete any remaining observers // (Deleted observers should have already removed themselves) gInventory.cleanupInventory(); - LLInventoryModelBackgroundFetch::deleteSingleton(); LLCoros::getInstance()->printActiveCoroutines(); @@ -2188,9 +2118,6 @@ bool LLAppViewer::cleanup() { // Turn off Space Navigator and similar devices LLViewerJoystick::getInstance()->terminate(); - - // Cleanup joystick singleton - LLViewerJoystick::deleteSingleton(); } LL_INFOS() << "Shutting down message system" << LL_ENDL; @@ -2242,8 +2169,6 @@ bool LLAppViewer::cleanup() //Note: //SUBSYSTEM_CLEANUP(LLViewerMedia) has to be put before gTextureList.shutdown() //because some new image might be generated during cleaning up media. --bao - LLViewerMedia::deleteSingleton(); - gTextureList.shutdown(); // shutdown again in case a callback added something LLUIImageList::getInstance()->cleanUp(); @@ -2283,41 +2208,13 @@ bool LLAppViewer::cleanup() ll_close_fail_log(); LLError::LLCallStacks::cleanup(); - - // Cleanup simpletons - LLPersistentNotificationStorage::deleteSingleton(); - LLDoNotDisturbNotificationStorage::deleteSingleton(); - LLObjectSignaledAnimationMap::deleteSingleton(); - LLWorldMap::deleteSingleton(); - LLAvatarNameCache::deleteSingleton(); - LLMaterialMgr::deleteSingleton(); + LLEnvironment::deleteSingleton(); LLSelectMgr::deleteSingleton(); - LLToolMgr::deleteSingleton(); - LLToolPie::deleteSingleton(); - LLToolDragAndDrop::deleteSingleton(); - LLToolCamera::deleteSingleton(); - LLToolGrab::deleteSingleton(); - LLToolPipette::deleteSingleton(); - LLToolFace::deleteSingleton(); - ALToolAlign::deleteSingleton(); - LLToolCompGun::deleteSingleton(); - LLToolCompCreate::deleteSingleton(); - LLToolCompRotate::deleteSingleton(); - LLToolCompScale::deleteSingleton(); - LLToolCompTranslate::deleteSingleton(); - LLToolCompInspect::deleteSingleton(); - LLToolIndividual::deleteSingleton(); - LLToolSelectLand::deleteSingleton(); LLViewerStatsRecorder::deleteSingleton(); LLViewerEventRecorder::deleteSingleton(); LLWorld::deleteSingleton(); - LLViewerPartSim::deleteSingleton(); - LLEnvironment::deleteSingleton(); LLVoiceClient::deleteSingleton(); LLUI::deleteSingleton(); - LLMuteList::deleteSingleton(); - LLAvatarNameCache::deleteSingleton(); - LLViewerParcelMgr::deleteSingleton(); // It's not at first obvious where, in this long sequence, a generic cleanup // call OUGHT to go. So let's say this: as we migrate cleanup from @@ -2330,26 +2227,6 @@ bool LLAppViewer::cleanup() // deleteSingleton() methods. LLSingletonBase::deleteAll(); - LLDiskCache::deleteSingleton(); - - // Destroy simpletons that singletons depend on - LLGridManager::deleteSingleton(); - LLUIColorTable::deleteSingleton(); - - // Destroy coroutine manager after everything besides dictionaries - LLCoros::deleteSingleton(); - - // Destroy static dictionaries - RlvBehaviourDictionary::deleteSingleton(); - LLSettingsType::deleteSingleton(); - LLWearableType::deleteSingleton(); - LLEmojiDictionary::deleteSingleton(); - LLIconDictionary::deleteSingleton(); - LLViewerFolderDictionary::deleteSingleton(); - LLFolderDictionary::deleteSingleton(); - LLAssetDictionary::deleteSingleton(); - LLInventoryDictionary::deleteSingleton(); - LLSplashScreen::hide(); LL_INFOS() << "Goodbye!" << LL_ENDL; @@ -3060,9 +2937,6 @@ bool LLAppViewer::initConfiguration() llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); } - // Init grid manager - LLGridManager::createInstance(); - // Handle slurl use. NOTE: Don't let SL-55321 reappear. // This initial-SLURL logic, up through the call to // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- @@ -4675,7 +4549,7 @@ bool LLAppViewer::initCache() mPurgeCache = false; bool read_only = mSecondInstance; LLAppViewer::getTextureCache()->setReadOnly(read_only) ; - LLVOCache::createInstance(read_only); + LLVOCache::initParamSingleton(read_only); // initialize the new disk cache using saved settings const std::string cache_dir_name = gSavedSettings.getString("DiskCacheDirName"); @@ -4747,7 +4621,7 @@ bool LLAppViewer::initCache() } const std::string cache_dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, cache_dir_name); - LLDiskCache::createInstance(cache_dir, disk_cache_size, enable_cache_debug_info); + LLDiskCache::initParamSingleton(cache_dir, disk_cache_size, enable_cache_debug_info); if (!read_only) { diff --git a/indra/newview/llcontrolavatar.h b/indra/newview/llcontrolavatar.h index 0fd59d596c8..0d94fe08ee0 100644 --- a/indra/newview/llcontrolavatar.h +++ b/indra/newview/llcontrolavatar.h @@ -111,11 +111,11 @@ typedef std::map signaled_animation_map_t; typedef std::map object_signaled_animation_map_t; // Stores information about previously requested animations, by object id. -class LLObjectSignaledAnimationMap: public LLSimpleton +class LLObjectSignaledAnimationMap: public LLSingleton { -public: - LLObjectSignaledAnimationMap() = default; + LLSINGLETON_EMPTY_CTOR(LLObjectSignaledAnimationMap); +public: object_signaled_animation_map_t mMap; object_signaled_animation_map_t& getMap() { return mMap; } diff --git a/indra/newview/lldonotdisturbnotificationstorage.h b/indra/newview/lldonotdisturbnotificationstorage.h index 87e57633905..6683646a9b7 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.h +++ b/indra/newview/lldonotdisturbnotificationstorage.h @@ -45,13 +45,13 @@ class LLDoNotDisturbNotificationStorageTimer : public LLEventTimer bool tick(); }; -class LLDoNotDisturbNotificationStorage : public LLSimpleton, public LLNotificationStorage +class LLDoNotDisturbNotificationStorage : public LLParamSingleton, public LLNotificationStorage { - LOG_CLASS(LLDoNotDisturbNotificationStorage); -public: - LLDoNotDisturbNotificationStorage(); + LLSINGLETON(LLDoNotDisturbNotificationStorage); ~LLDoNotDisturbNotificationStorage(); + LOG_CLASS(LLDoNotDisturbNotificationStorage); +public: static const char * toastName; static const char * offerName; diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index 0005682f8fd..d2d6ba7ae6b 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -44,7 +44,6 @@ LLHUDManager::LLHUDManager() LLHUDManager::~LLHUDManager() { - mHUDEffects.clear(); } static LLTrace::BlockTimerStatHandle FTM_UPDATE_HUD_EFFECTS("Update Hud Effects"); @@ -95,6 +94,12 @@ void LLHUDManager::sendEffects() } } +//static +void LLHUDManager::shutdownClass() +{ + getInstance()->mHUDEffects.clear(); +} + void LLHUDManager::cleanupEffects() { S32 i = 0; diff --git a/indra/newview/llhudmanager.h b/indra/newview/llhudmanager.h index 5c3852d5d40..efc93b356a0 100644 --- a/indra/newview/llhudmanager.h +++ b/indra/newview/llhudmanager.h @@ -34,18 +34,20 @@ class LLHUDEffect; class LLMessageSystem; -class LLHUDManager : public LLSimpleton +class LLHUDManager : public LLSingleton { -public: - LLHUDManager(); + LLSINGLETON(LLHUDManager); ~LLHUDManager(); +public: LLHUDEffect *createViewerEffect(const U8 type, bool send_to_sim = true, bool originated_here = true); void updateEffects(); void sendEffects(); void cleanupEffects(); + static void shutdownClass(); + static void processViewerEffect(LLMessageSystem *mesgsys, void **user_data); protected: diff --git a/indra/newview/llinventoryicon.cpp b/indra/newview/llinventoryicon.cpp index f36663d5110..94b8c4bebf7 100644 --- a/indra/newview/llinventoryicon.cpp +++ b/indra/newview/llinventoryicon.cpp @@ -36,6 +36,20 @@ #include "llwearabletype.h" #include "llinventorysettings.h" +struct IconEntry : public LLDictionaryEntry +{ + IconEntry(const std::string &item_name) + : + LLDictionaryEntry(item_name) + {} +}; + +class LLIconDictionary : public LLSingleton, + public LLDictionary +{ + LLSINGLETON(LLIconDictionary); +}; + typedef LLPointer LLUIImagePtr; LLIconDictionary::LLIconDictionary() diff --git a/indra/newview/llinventoryicon.h b/indra/newview/llinventoryicon.h index 0d177b59b55..32e2d8b29d1 100644 --- a/indra/newview/llinventoryicon.h +++ b/indra/newview/llinventoryicon.h @@ -31,17 +31,6 @@ #include "llassettype.h" #include "llinventorytype.h" -struct IconEntry : public LLDictionaryEntry -{ - IconEntry(const std::string& item_name) : LLDictionaryEntry(item_name) {} -}; - -class LLIconDictionary : public LLSimpleton, public LLDictionary -{ -public: - LLIconDictionary(); -}; - class LLInventoryIcon { public: diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h index 596e7cdce30..e4f555da748 100644 --- a/indra/newview/llmaterialmgr.h +++ b/indra/newview/llmaterialmgr.h @@ -78,12 +78,12 @@ inline std::size_t hash_value(TEMaterialPair const& id) return seed; } -class LLMaterialMgr : public LLSimpleton +class LLMaterialMgr : public LLSingleton { -public: - LLMaterialMgr(); + LLSINGLETON(LLMaterialMgr); virtual ~LLMaterialMgr(); +public: typedef std::map material_map_t; typedef boost::signals2::signal get_callback_t; diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index 8cc1d0cee07..b7f46a1a573 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -185,10 +185,12 @@ LLMuteList::LLMuteList() : //----------------------------------------------------------------------------- LLMuteList::~LLMuteList() { - if (LLAvatarNameCache::instanceExists()) - { - LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(nullptr); - } + +} + +void LLMuteList::cleanupSingleton() +{ + LLAvatarNameCache::getInstance()->setAccountNameChangedCallback(nullptr); } // static diff --git a/indra/newview/llmutelist.h b/indra/newview/llmutelist.h index f8a763583a3..a373600dee2 100644 --- a/indra/newview/llmutelist.h +++ b/indra/newview/llmutelist.h @@ -74,11 +74,11 @@ class LLMute U32 mFlags; // flags pertaining to this mute entry }; -class LLMuteList : public LLSimpleton +class LLMuteList : public LLSingleton { -public: - LLMuteList(); + LLSINGLETON(LLMuteList); ~LLMuteList(); + /*virtual*/ void cleanupSingleton() override; enum EMuteListState { @@ -87,7 +87,7 @@ class LLMuteList : public LLSimpleton ML_LOADED, ML_FAILED, }; - +public: // reasons for auto-unmuting a resident enum EAutoReason { diff --git a/indra/newview/llpersistentnotificationstorage.h b/indra/newview/llpersistentnotificationstorage.h index ba73f7ff608..72fe2a79751 100644 --- a/indra/newview/llpersistentnotificationstorage.h +++ b/indra/newview/llpersistentnotificationstorage.h @@ -43,12 +43,12 @@ class LLSD; // be a) serializable(implement LLNotificationResponderInterface), // b) registered with LLResponderRegistry (found in llpersistentnotificationstorage.cpp). -class LLPersistentNotificationStorage : public LLSimpleton, public LLNotificationStorage +class LLPersistentNotificationStorage : public LLParamSingleton, public LLNotificationStorage { + LLSINGLETON(LLPersistentNotificationStorage); + ~LLPersistentNotificationStorage(); LOG_CLASS(LLPersistentNotificationStorage); public: - LLPersistentNotificationStorage(); - ~LLPersistentNotificationStorage(); void saveNotifications(); void loadNotifications(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index f0729376ae8..0cac7271ad0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1134,8 +1134,8 @@ bool idle_startup() { // check existance since this part of code can be reached // twice due to login failures - LLPersistentNotificationStorage::createInstance(); - LLDoNotDisturbNotificationStorage::createInstance(); + LLPersistentNotificationStorage::initParamSingleton(); + LLDoNotDisturbNotificationStorage::initParamSingleton(); } else { @@ -3412,7 +3412,7 @@ void LLStartUp::multimediaInit() set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); do_startup_frame(); - ALStreamInfo::createInstance(); + ALStreamInfo::getInstance(); } void LLStartUp::fontInit() diff --git a/indra/newview/lltoolcomp.h b/indra/newview/lltoolcomp.h index 752e75a085e..f94cb3cf844 100644 --- a/indra/newview/lltoolcomp.h +++ b/indra/newview/lltoolcomp.h @@ -102,11 +102,11 @@ class LLToolComposite : public LLTool //----------------------------------------------------------------------- // LLToolCompTranslate -class LLToolCompInspect : public LLToolComposite, public LLSimpleton +class LLToolCompInspect : public LLToolComposite, public LLSingleton { -public: - LLToolCompInspect(); + LLSINGLETON(LLToolCompInspect); virtual ~LLToolCompInspect(); +public: // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -127,11 +127,11 @@ class LLToolCompInspect : public LLToolComposite, public LLSimpleton +class LLToolCompTranslate : public LLToolComposite, public LLSingleton { -public: - LLToolCompTranslate(); + LLSINGLETON(LLToolCompTranslate); virtual ~LLToolCompTranslate(); +public: // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -148,11 +148,11 @@ class LLToolCompTranslate : public LLToolComposite, public LLSimpleton +class LLToolCompScale : public LLToolComposite, public LLSingleton { -public: - LLToolCompScale(); + LLSINGLETON(LLToolCompScale); virtual ~LLToolCompScale(); +public: // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -173,11 +173,11 @@ class LLToolCompScale : public LLToolComposite, public LLSimpleton +class LLToolCompRotate : public LLToolComposite, public LLSingleton { -public: - LLToolCompRotate(); + LLSINGLETON(LLToolCompRotate); virtual ~LLToolCompRotate(); +public: // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -196,11 +196,11 @@ class LLToolCompRotate : public LLToolComposite, public LLSimpleton +class LLToolCompCreate : public LLToolComposite, public LLSingleton { -public: - LLToolCompCreate(); + LLSINGLETON(LLToolCompCreate); virtual ~LLToolCompCreate(); +public: // Overridden from LLToolComposite virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; @@ -221,11 +221,11 @@ class LLToolGun; class LLToolGrabBase; class LLToolSelect; -class LLToolCompGun : public LLToolComposite, public LLSimpleton +class LLToolCompGun : public LLToolComposite, public LLSingleton { -public: - LLToolCompGun(); + LLSINGLETON(LLToolCompGun); virtual ~LLToolCompGun(); +public: void draw() override; diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h index d6ceb01f195..ad6402c4add 100644 --- a/indra/newview/lltooldraganddrop.h +++ b/indra/newview/lltooldraganddrop.h @@ -41,11 +41,10 @@ class LLViewerRegion; class LLVOAvatar; class LLPickInfo; -class LLToolDragAndDrop : public LLTool, public LLSimpleton +class LLToolDragAndDrop : public LLTool, public LLSingleton { + LLSINGLETON(LLToolDragAndDrop); public: - LLToolDragAndDrop(); - typedef boost::signals2::signal enddrag_signal_t; // overridden from LLTool diff --git a/indra/newview/lltoolface.h b/indra/newview/lltoolface.h index 4320b157655..18d42da1e1e 100644 --- a/indra/newview/lltoolface.h +++ b/indra/newview/lltoolface.h @@ -33,11 +33,11 @@ class LLViewerObject; class LLPickInfo; class LLToolFace -: public LLTool, public LLSimpleton +: public LLTool, public LLSingleton { -public: - LLToolFace(); + LLSINGLETON(LLToolFace); virtual ~LLToolFace(); +public: virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolfocus.h b/indra/newview/lltoolfocus.h index 963f7abbcfe..8541fcaa332 100644 --- a/indra/newview/lltoolfocus.h +++ b/indra/newview/lltoolfocus.h @@ -32,11 +32,11 @@ class LLPickInfo; class LLToolCamera -: public LLTool, public LLSimpleton +: public LLTool, public LLSingleton { -public: - LLToolCamera(); + LLSINGLETON(LLToolCamera); virtual ~LLToolCamera(); +public: virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index 43f852b5779..7806cbc24f8 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -147,10 +147,9 @@ class LLToolGrabBase : public LLTool }; /// This is the LLSingleton instance of LLToolGrab. -class LLToolGrab : public LLToolGrabBase, public LLSimpleton +class LLToolGrab : public LLToolGrabBase, public LLSingleton { -public: - LLToolGrab() = default; + LLSINGLETON_EMPTY_CTOR(LLToolGrab); }; extern bool gGrabBtnVertical; diff --git a/indra/newview/lltoolindividual.h b/indra/newview/lltoolindividual.h index 94f2797c24a..baf687d183d 100644 --- a/indra/newview/lltoolindividual.h +++ b/indra/newview/lltoolindividual.h @@ -37,11 +37,11 @@ class LLPickInfo; // A tool to select individual objects rather than linked sets. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLToolIndividual : public LLTool, public LLSimpleton +class LLToolIndividual : public LLTool, public LLSingleton { -public: - LLToolIndividual(); + LLSINGLETON(LLToolIndividual); virtual ~LLToolIndividual(); +public: virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 135255bb25b..2ba4b8c8091 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -40,11 +40,11 @@ const MASK MASK_ORBIT = MASK_CONTROL; const MASK MASK_PAN = MASK_CONTROL | MASK_SHIFT; const MASK MASK_COPY = MASK_SHIFT; -class LLToolMgr : public LLSimpleton +class LLToolMgr : public LLSingleton { -public: - LLToolMgr(); + LLSINGLETON(LLToolMgr); ~LLToolMgr(); +public: // Must be called after gSavedSettings set up. void initTools(); diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index a83fa7cfbd3..a9c09280087 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -35,11 +35,11 @@ class LLViewerObject; class LLObjectSelection; -class LLToolPie : public LLTool, public LLSimpleton +class LLToolPie : public LLTool, public LLSingleton { + LLSINGLETON(LLToolPie); LOG_CLASS(LLToolPie); public: - LLToolPie(); // Virtual functions inherited from LLMouseHandler virtual bool handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down) override; diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h index e30482d64cb..b3e91fd8191 100644 --- a/indra/newview/lltoolpipette.h +++ b/indra/newview/lltoolpipette.h @@ -40,12 +40,12 @@ class LLViewerObject; class LLPickInfo; class LLToolPipette -: public LLTool, public LLSimpleton +: public LLTool, public LLSingleton { -public: - LLToolPipette(); + LLSINGLETON(LLToolPipette); virtual ~LLToolPipette(); +public: virtual bool handleMouseDown(S32 x, S32 y, MASK mask) override; virtual bool handleMouseUp(S32 x, S32 y, MASK mask) override; virtual bool handleHover(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/lltoolselectland.h b/indra/newview/lltoolselectland.h index 10c39ca122d..15672aa7d4e 100644 --- a/indra/newview/lltoolselectland.h +++ b/indra/newview/lltoolselectland.h @@ -33,12 +33,12 @@ class LLParcelSelection; class LLToolSelectLand -: public LLTool, public LLSimpleton +: public LLTool, public LLSingleton { -public: - LLToolSelectLand(); + LLSINGLETON(LLToolSelectLand); virtual ~LLToolSelectLand(); +public: /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) override; /*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask) override; /*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) override; diff --git a/indra/newview/llviewerfoldertype.cpp b/indra/newview/llviewerfoldertype.cpp index 8e9a2dfd2ee..d151f1fb75c 100644 --- a/indra/newview/llviewerfoldertype.cpp +++ b/indra/newview/llviewerfoldertype.cpp @@ -34,6 +34,80 @@ extern LLControlGroup gSavedSettings; +static const std::string empty_string; + +struct ViewerFolderEntry : public LLDictionaryEntry +{ + // Constructor for non-ensembles + ViewerFolderEntry(const std::string &new_category_name, // default name when creating a new category of this type + const std::string &icon_name_open, // name of the folder icon + const std::string &icon_name_closed, + bool is_quiet, // folder doesn't need a UI update when changed + bool hide_if_empty, // folder not shown if empty + const std::string &dictionary_name = empty_string // no reverse lookup needed on non-ensembles, so in most cases just leave this blank + ) + : + LLDictionaryEntry(dictionary_name), + mNewCategoryName(new_category_name), + mIconNameOpen(icon_name_open), + mIconNameClosed(icon_name_closed), + mIsQuiet(is_quiet), + mHideIfEmpty(hide_if_empty) + { + mAllowedNames.clear(); + } + + // Constructor for ensembles + ViewerFolderEntry(const std::string &xui_name, // name of the xui menu item + const std::string &new_category_name, // default name when creating a new category of this type + const std::string &icon_name, // name of the folder icon + const std::string allowed_names // allowed item typenames for this folder type + ) + : + LLDictionaryEntry(xui_name), + /* Just use default icons until we actually support ensembles + mIconNameOpen(icon_name), + mIconNameClosed(icon_name), + */ + mIconNameOpen("Inv_FolderOpen"), mIconNameClosed("Inv_FolderClosed"), + mNewCategoryName(new_category_name), + mIsQuiet(false), + mHideIfEmpty(false) + { + const std::string delims (","); + LLStringUtilBase::getTokens(allowed_names, mAllowedNames, delims); + } + + bool getIsAllowedName(const std::string &name) const + { + if (mAllowedNames.empty()) + return false; + for (name_vec_t::const_iterator iter = mAllowedNames.begin(); + iter != mAllowedNames.end(); + iter++) + { + if (name == (*iter)) + return true; + } + return false; + } + const std::string mIconNameOpen; + const std::string mIconNameClosed; + const std::string mNewCategoryName; + typedef std::vector name_vec_t; + name_vec_t mAllowedNames; + bool mIsQuiet; + bool mHideIfEmpty; +}; + +class LLViewerFolderDictionary : public LLSingleton, + public LLDictionary +{ + LLSINGLETON(LLViewerFolderDictionary); +protected: + bool initEnsemblesFromFile(); // Reads in ensemble information from foldertypes.xml +}; + LLViewerFolderDictionary::LLViewerFolderDictionary() { // NEW CATEGORY NAME FOLDER OPEN FOLDER CLOSED QUIET? HIDE IF EMPTY? diff --git a/indra/newview/llviewerfoldertype.h b/indra/newview/llviewerfoldertype.h index 169574144bf..f25c1113a39 100644 --- a/indra/newview/llviewerfoldertype.h +++ b/indra/newview/llviewerfoldertype.h @@ -29,8 +29,6 @@ #include #include "llfoldertype.h" -#include "lldictionary.h" -#include "llsingleton.h" // This class is similar to llfoldertype, but contains methods // only used by the viewer. This also handles ensembles. @@ -53,77 +51,4 @@ class LLViewerFolderType : public LLFolderType ~LLViewerFolderType() {} }; -struct ViewerFolderEntry : public LLDictionaryEntry -{ - // Constructor for non-ensembles - ViewerFolderEntry(const std::string &new_category_name, // default name when creating a new category of this type - const std::string &icon_name_open, // name of the folder icon - const std::string &icon_name_closed, - bool is_quiet, // folder doesn't need a UI update when changed - bool hide_if_empty, // folder not shown if empty - const std::string &dictionary_name = {} // no reverse lookup needed on non-ensembles, so in most cases just leave this blank - ) - : - LLDictionaryEntry(dictionary_name), - mNewCategoryName(new_category_name), - mIconNameOpen(icon_name_open), - mIconNameClosed(icon_name_closed), - mIsQuiet(is_quiet), - mHideIfEmpty(hide_if_empty) - { - mAllowedNames.clear(); - } - - // Constructor for ensembles - ViewerFolderEntry(const std::string &xui_name, // name of the xui menu item - const std::string &new_category_name, // default name when creating a new category of this type - const std::string &icon_name, // name of the folder icon - const std::string allowed_names // allowed item typenames for this folder type - ) - : - LLDictionaryEntry(xui_name), - /* Just use default icons until we actually support ensembles - mIconNameOpen(icon_name), - mIconNameClosed(icon_name), - */ - mIconNameOpen("Inv_FolderOpen"), mIconNameClosed("Inv_FolderClosed"), - mNewCategoryName(new_category_name), - mIsQuiet(false), - mHideIfEmpty(false) - { - const std::string delims (","); - LLStringUtilBase::getTokens(allowed_names, mAllowedNames, delims); - } - - bool getIsAllowedName(const std::string &name) const - { - if (mAllowedNames.empty()) - return false; - for (name_vec_t::const_iterator iter = mAllowedNames.begin(); - iter != mAllowedNames.end(); - iter++) - { - if (name == (*iter)) - return true; - } - return false; - } - const std::string mIconNameOpen; - const std::string mIconNameClosed; - const std::string mNewCategoryName; - typedef std::vector name_vec_t; - name_vec_t mAllowedNames; - bool mIsQuiet; - bool mHideIfEmpty; -}; - -class LLViewerFolderDictionary : public LLSimpleton, - public LLDictionary -{ -public: - LLViewerFolderDictionary(); -protected: - bool initEnsemblesFromFile(); // Reads in ensemble information from foldertypes.xml -}; - #endif // LL_LLVIEWERFOLDERTYPE_H diff --git a/indra/newview/llviewerjoystick.h b/indra/newview/llviewerjoystick.h index c662b2d4c7c..c989615653c 100644 --- a/indra/newview/llviewerjoystick.h +++ b/indra/newview/llviewerjoystick.h @@ -46,14 +46,13 @@ typedef enum e_joystick_driver_state JDS_INITIALIZING } EJoystickDriverState; -class LLViewerJoystick : public LLSimpleton +class LLViewerJoystick : public LLSingleton { + LLSINGLETON(LLViewerJoystick); + virtual ~LLViewerJoystick(); LOG_CLASS(LLViewerJoystick); public: - LLViewerJoystick(); - ~LLViewerJoystick(); - void init(bool autoenable); void initDevice(LLSD &guid); bool initDevice(void * preffered_device /*LPDIRECTINPUTDEVICE8*/); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index b6c7ea3cb0f..36b3d08ded6 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -218,6 +218,23 @@ mAnyMediaShowing(false), mAnyMediaPlaying(false), mMaxIntances(MAX_MEDIA_INSTANCES_DEFAULT), mSpareBrowserMediaSource(NULL) +{ +} + +LLViewerMedia::~LLViewerMedia() +{ + gIdleCallbacks.deleteFunction(LLViewerMedia::onIdle, NULL); + mTeleportFinishConnection.disconnect(); + mMaxInstancesConnection.disconnect(); + if (mSpareBrowserMediaSource != NULL) + { + delete mSpareBrowserMediaSource; + mSpareBrowserMediaSource = NULL; + } +} + +// static +void LLViewerMedia::initSingleton() { gIdleCallbacks.addFunction(LLViewerMedia::onIdle, NULL); mTeleportFinishConnection = LLViewerParcelMgr::getInstance()-> @@ -238,18 +255,6 @@ mSpareBrowserMediaSource(NULL) } } -LLViewerMedia::~LLViewerMedia() -{ - gIdleCallbacks.deleteFunction(LLViewerMedia::onIdle, NULL); - mTeleportFinishConnection.disconnect(); - mMaxInstancesConnection.disconnect(); - if (mSpareBrowserMediaSource != NULL) - { - delete mSpareBrowserMediaSource; - mSpareBrowserMediaSource = NULL; - } -} - void LLViewerMedia::setMaxInstances(S32 max_instances) { const F32Gigabytes MIN_PHYSICAL_MEMORY(8); diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index f69248fbbbb..a3cb9ec93e7 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -71,14 +71,14 @@ class LLViewerMediaEventEmitter class LLViewerMediaImpl; class LLMediaCtrl; -class LLViewerMedia: public LLSimpleton +class LLViewerMedia: public LLSingleton { + LLSINGLETON(LLViewerMedia); + ~LLViewerMedia(); + void initSingleton() override; LOG_CLASS(LLViewerMedia); public: - LLViewerMedia(); - ~LLViewerMedia(); - // String to get/set media autoplay in gSavedSettings static const char* AUTO_PLAY_MEDIA_SETTING; static const char* SHOW_MEDIA_ON_OTHERS_SETTING; diff --git a/indra/newview/llviewernetwork.h b/indra/newview/llviewernetwork.h index a5398f22fba..0937425a188 100644 --- a/indra/newview/llviewernetwork.h +++ b/indra/newview/llviewernetwork.h @@ -57,14 +57,13 @@ class LLInvalidGridName * This class maintains the currently selected grid, and provides short * form accessors for each of the properties of the selected grid. **/ -class LLGridManager : public LLSimpleton +class LLGridManager : public LLSingleton { -public: - /// Instantiate the grid manager, load default grids, selects the default grid - LLGridManager(); + LLSINGLETON(LLGridManager); ~LLGridManager(); + public: /* ================================================================ * @name Initialization and Configuration * @{ diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 304c84b6287..c48c438ad04 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -74,12 +74,12 @@ class LLParcelObserver virtual void changed() = 0; }; -class LLViewerParcelMgr : public LLSimpleton +class LLViewerParcelMgr : public LLSingleton { -public: - LLViewerParcelMgr(); + LLSINGLETON(LLViewerParcelMgr); ~LLViewerParcelMgr(); +public: typedef std::function teleport_finished_callback_t; typedef boost::signals2::signal teleport_finished_signal_t; typedef std::function teleport_failed_callback_t; diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 506978f56cc..cf3843bd667 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -133,11 +133,10 @@ class LLViewerPartGroup LLViewerRegion *mRegionp; }; -class LLViewerPartSim : public LLSimpleton +class LLViewerPartSim : public LLSingleton { + LLSINGLETON(LLViewerPartSim); public: - LLViewerPartSim(); - void destroyClass(); typedef std::vector group_list_t; diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index f5bd9198d34..c7bd4625f8d 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -247,10 +247,9 @@ class LLVOCachePartition : public LLViewerOctreePartition // //Note: LLVOCache is not thread-safe // -class LLVOCache : public LLSimpleton +class LLVOCache : public LLParamSingleton { -public: - LLVOCache(bool read_only); + LLSINGLETON(LLVOCache, bool read_only); ~LLVOCache() ; private: diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index eb653b323fc..135a7331cb4 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -167,7 +167,6 @@ void LLVoiceClient::init(LLPumpIO *pump) // Initialize all of the voice modules m_servicePump = pump; #ifndef DISABLE_WEBRTC - LLWebRTCVoiceClient::createInstance(); LLWebRTCVoiceClient::getInstance()->init(pump); #endif } diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index b2d997337ab..70bce055f9b 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -342,13 +342,13 @@ class LLVoiceEffectInterface }; -class LLVoiceClient: public LLSimpleton +class LLVoiceClient: public LLParamSingleton { + LLSINGLETON(LLVoiceClient, LLPumpIO *pump); LOG_CLASS(LLVoiceClient); -public: - LLVoiceClient(LLPumpIO* pump); ~LLVoiceClient(); +public: typedef boost::signals2::signal micro_changed_signal_t; micro_changed_signal_t mMicroChangedSignal; diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index db1852cdcd9..7dea89d286f 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -281,6 +281,10 @@ LLWebRTCVoiceClient::LLWebRTCVoiceClient() : //--------------------------------------------------- LLWebRTCVoiceClient::~LLWebRTCVoiceClient() +{ +} + +void LLWebRTCVoiceClient::cleanupSingleton() { if (mAvatarNameCacheConnection.connected()) { diff --git a/indra/newview/llvoicewebrtc.h b/indra/newview/llvoicewebrtc.h index 9e838fc44c4..8a15ba54b42 100644 --- a/indra/newview/llvoicewebrtc.h +++ b/indra/newview/llvoicewebrtc.h @@ -56,18 +56,18 @@ typedef std::shared_ptr connectionPtr_t; extern const std::string WEBRTC_VOICE_SERVER_TYPE; -class LLWebRTCVoiceClient : public LLSimpleton, +class LLWebRTCVoiceClient : public LLSingleton, virtual public LLVoiceModuleInterface, public llwebrtc::LLWebRTCDevicesObserver, public LLMuteListObserver, public llwebrtc::LLWebRTCLogCallback { + LLSINGLETON(LLWebRTCVoiceClient); LOG_CLASS(LLWebRTCVoiceClient); - -public: - LLWebRTCVoiceClient(); virtual ~LLWebRTCVoiceClient(); +public: + void cleanupSingleton() override; /// @name LLVoiceModuleInterface virtual implementations /// @see LLVoiceModuleInterface //@{ diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index e2a415abe71..8378b5e447e 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -182,12 +182,12 @@ const S32 MAP_MAX_SIZE = 2048; const S32 MAP_BLOCK_SIZE = 4; const S32 MAP_BLOCK_RES = (MAP_MAX_SIZE / MAP_BLOCK_SIZE); -class LLWorldMap : public LLSimpleton +class LLWorldMap : public LLSingleton { -public: - LLWorldMap(); + LLSINGLETON(LLWorldMap); ~LLWorldMap(); +public: // Clear all: list of region info, tiles, blocks and items void reset(); diff --git a/indra/newview/rlvhelper.h b/indra/newview/rlvhelper.h index 316f50190fd..920dd50ed91 100644 --- a/indra/newview/rlvhelper.h +++ b/indra/newview/rlvhelper.h @@ -98,14 +98,14 @@ class RlvBehaviourInfo // RlvBehaviourDictionary and related classes // -class RlvBehaviourDictionary : public LLSimpleton +class RlvBehaviourDictionary : public LLSingleton { friend class RlvFloaterBehaviours; -public: - RlvBehaviourDictionary(); + LLSINGLETON(RlvBehaviourDictionary); +protected: ~RlvBehaviourDictionary(); - +public: void addEntry(const RlvBehaviourInfo* pBhvrEntry); void addModifier(ERlvBehaviour eBhvr, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); void addModifier(const RlvBehaviourInfo* pBhvrEntry, ERlvBehaviourModifier eModifier, RlvBehaviourModifier* pModifierEntry); diff --git a/indra/newview/tests/llslurl_test.cpp b/indra/newview/tests/llslurl_test.cpp index eae2646a619..2c85ab7c10d 100644 --- a/indra/newview/tests/llslurl_test.cpp +++ b/indra/newview/tests/llslurl_test.cpp @@ -183,12 +183,10 @@ namespace tut { slurlTest() { - LLGridManager::createInstance(); LLGridManager::getInstance()->initialize(std::string("")); } ~slurlTest() { - LLGridManager::deleteSingleton(); } }; diff --git a/indra/newview/tests/llviewernetwork_test.cpp b/indra/newview/tests/llviewernetwork_test.cpp index 78aeb1c48eb..1cbb8b50eb3 100644 --- a/indra/newview/tests/llviewernetwork_test.cpp +++ b/indra/newview/tests/llviewernetwork_test.cpp @@ -175,8 +175,6 @@ namespace tut { viewerNetworkTest() { - LLGridManager::createInstance(); - LLFile::remove(TEST_FILENAME); gCmdLineLoginURI.clear(); gCmdLineGridChoice.clear(); @@ -187,8 +185,6 @@ namespace tut ~viewerNetworkTest() { LLFile::remove(TEST_FILENAME); - - LLGridManager::deleteSingleton(); } }; diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp index cab68ed4390..60172b39602 100644 --- a/indra/newview/tests/llworldmap_test.cpp +++ b/indra/newview/tests/llworldmap_test.cpp @@ -137,13 +137,11 @@ namespace tut // Constructor and destructor of the test wrapper worldmap_test() { - LLWorldMap::createInstance(); mWorld = LLWorldMap::getInstance(); } ~worldmap_test() { - mWorld = nullptr; - LLWorldMap::deleteSingleton(); + mWorld = NULL; } }; diff --git a/indra/viewer_components/login/tests/lllogin_test.cpp b/indra/viewer_components/login/tests/lllogin_test.cpp index 4d71dc1e812..8aea3b37aa7 100644 --- a/indra/viewer_components/login/tests/lllogin_test.cpp +++ b/indra/viewer_components/login/tests/lllogin_test.cpp @@ -206,12 +206,9 @@ namespace tut { llviewerlogin_data() : pumps(LLEventPumps::instance()) - { - LLCoros::createInstance(); - } + {} ~llviewerlogin_data() { - LLCoros::deleteSingleton(); pumps.clear(); } LLEventPumps& pumps; From f84f63328cedd57bdeb9019d91a4080f8e27d383 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 05:19:43 -0400 Subject: [PATCH 3/9] Extern template build opt for LLCoros --- indra/llcommon/llcoros.cpp | 3 +++ indra/llcommon/llcoros.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 9e95d9c85f1..b68bf00885a 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -31,6 +31,7 @@ // Precompiled header #include "linden_common.h" // associated header +#define LLCOROS_CPP #include "llcoros.h" // STL headers // std headers @@ -460,3 +461,5 @@ LLCoros::CoroData::CoroData(int n): mCreationTime(LLTimer::getTotalSeconds()) { } + +template class LL_COMMON_API LLCoros* LLSingleton::getInstance(); diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index bb66ae66bab..d36cf21954a 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -373,4 +373,8 @@ std::string logname() { return LLCoros::logname(); } } // llcoro +#ifndef LLCOROS_CPP +extern template class LL_COMMON_API LLCoros* LLSingleton::getInstance(); +#endif + #endif /* ! defined(LL_LLCOROS_H) */ From c35f460b876d0005e6a2bbca44bee702892e4b68 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 05:20:22 -0400 Subject: [PATCH 4/9] Update vcpkg baseline to cd61e1e26a038e82d6550a3ebbe0fbbfe7da78e3 --- indra/vcpkg.json | 2 +- vcpkg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/vcpkg.json b/indra/vcpkg.json index 72a7b425eb3..7c7cea027f2 100644 --- a/indra/vcpkg.json +++ b/indra/vcpkg.json @@ -1,5 +1,5 @@ { - "builtin-baseline": "58613d018f126ccaa9dac9a02b11142cb0f4f4ea", + "builtin-baseline": "cd61e1e26a038e82d6550a3ebbe0fbbfe7da78e3", "dependencies": [ "alchemy-branding", "alchemy-dictionaries", diff --git a/vcpkg b/vcpkg index 58613d018f1..cd61e1e26a0 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit 58613d018f126ccaa9dac9a02b11142cb0f4f4ea +Subproject commit cd61e1e26a038e82d6550a3ebbe0fbbfe7da78e3 From 2ec32d88f622fb78ebabf726980e4ceb49f9e3f1 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 05:20:35 -0400 Subject: [PATCH 5/9] Clean up stray LL_COMMON_API outside of llcommon --- indra/llinventory/llfoldertype.h | 2 +- indra/llwindow/llcursortypes.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/indra/llinventory/llfoldertype.h b/indra/llinventory/llfoldertype.h index 7d3732fa954..ad1d84c6c7b 100644 --- a/indra/llinventory/llfoldertype.h +++ b/indra/llinventory/llfoldertype.h @@ -32,7 +32,7 @@ // This class handles folder types (similar to assettype, except for folders) // and operations on those. -class LL_COMMON_API LLFolderType +class LLFolderType { public: // ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums. diff --git a/indra/llwindow/llcursortypes.h b/indra/llwindow/llcursortypes.h index 9a0c2909bf8..619e07b5a0b 100644 --- a/indra/llwindow/llcursortypes.h +++ b/indra/llwindow/llcursortypes.h @@ -76,6 +76,6 @@ enum ECursorType { UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) }; -LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string); +ECursorType getCursorFromString(const std::string& cursor_string); #endif // LL_LLCURSORTYPES_H From 5b39c500731e13291268bb00725bec0a7dd8cdf2 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 05:54:29 -0400 Subject: [PATCH 6/9] Untangle llcommon and llmath circular dependency --- indra/llcommon/CMakeLists.txt | 3 +- indra/llcommon/tests/llsdutil_test.cpp | 74 +---------- indra/llmath/CMakeLists.txt | 1 + indra/llmath/tests/llsdutil_math_test.cpp | 153 ++++++++++++++++++++++ indra/llprecompiled/CMakeLists.txt | 10 -- 5 files changed, 156 insertions(+), 85 deletions(-) create mode 100644 indra/llmath/tests/llsdutil_math_test.cpp diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 5ea1c7f09b0..e8d93d8fa6b 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -287,7 +287,6 @@ target_link_libraries( ) target_include_directories(llcommon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(llcommon PRIVATE ${INDRA_SOURCE_DIR}/llmath) target_precompile_headers(llcommon REUSE_FROM llprecompiled) @@ -334,7 +333,7 @@ if (BUILD_TESTING) LL_ADD_INTEGRATION_TEST(llsd "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llsdjson "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}" "${test_project}") - LL_ADD_INTEGRATION_TEST(llsdutil "" "llcommon;llmath" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsdutil "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llstreamtools "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}" "${test_project}") diff --git a/indra/llcommon/tests/llsdutil_test.cpp b/indra/llcommon/tests/llsdutil_test.cpp index 4b25a02f30e..de6e0bede53 100644 --- a/indra/llcommon/tests/llsdutil_test.cpp +++ b/indra/llcommon/tests/llsdutil_test.cpp @@ -114,78 +114,6 @@ namespace tut template<> template<> void llsdutil_object::test<4>() - { - LLSD sd; - LLVector3 vec1(-1.0, 2.0, -3.0); - sd = ll_sd_from_vector3(vec1); - LLVector3 vec2 = ll_vector3_from_sd(sd); - ensure_equals("vector3 -> sd -> vector3: 1", vec1, vec2); - - LLVector3 vec3(sd); - ensure_equals("vector3 -> sd -> vector3: 2", vec1, vec3); - - sd.clear(); - vec1.setVec(0., 0., 0.); - sd = ll_sd_from_vector3(vec1); - vec2 = ll_vector3_from_sd(sd); - ensure_equals("vector3 -> sd -> vector3: 3", vec1, vec2); - sd.clear(); - } - - template<> template<> - void llsdutil_object::test<5>() - { - LLSD sd; - LLVector3d vec1((F64)(U64L(0xFEDCBA9876543210) << 2), -1., 0); - sd = ll_sd_from_vector3d(vec1); - LLVector3d vec2 = ll_vector3d_from_sd(sd); - ensure_equals("vector3d -> sd -> vector3d: 1", vec1, vec2); - - LLVector3d vec3(sd); - ensure_equals("vector3d -> sd -> vector3d : 2", vec1, vec3); - } - - template<> template<> - void llsdutil_object::test<6>() - { - LLSD sd; - LLVector2 vec((F32) -3., (F32) 4.2); - sd = ll_sd_from_vector2(vec); - LLVector2 vec1 = ll_vector2_from_sd(sd); - ensure_equals("vector2 -> sd -> vector2", vec, vec1); - - LLSD sd2 = ll_sd_from_vector2(vec1); - ensure_equals("sd -> vector2 -> sd: 2", sd, sd2); - } - - template<> template<> - void llsdutil_object::test<7>() - { - LLSD sd; - LLQuaternion quat((F32) 1., (F32) -0.98, (F32) 2.3, (F32) 0xffff); - sd = ll_sd_from_quaternion(quat); - LLQuaternion quat1 = ll_quaternion_from_sd(sd); - ensure_equals("LLQuaternion -> sd -> LLQuaternion", quat, quat1); - - LLSD sd2 = ll_sd_from_quaternion(quat1); - ensure_equals("sd -> LLQuaternion -> sd ", sd, sd2); - } - - template<> template<> - void llsdutil_object::test<8>() - { - LLSD sd; - LLColor4 c(1.0f, 2.2f, 4.0f, 7.f); - sd = ll_sd_from_color4(c); - LLColor4 c1 =ll_color4_from_sd(sd); - ensure_equals("LLColor4 -> sd -> LLColor4", c, c1); - - LLSD sd1 = ll_sd_from_color4(c1); - ensure_equals("sd -> LLColor4 -> sd", sd, sd1); - } - - template<> template<> - void llsdutil_object::test<9>() { set_test_name("llsd_matches"); @@ -388,7 +316,7 @@ namespace tut } template<> template<> - void llsdutil_object::test<10>() + void llsdutil_object::test<5>() { set_test_name("llsd_hashing"); diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index e885c9f06bb..ea48bf25c0a 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -117,6 +117,7 @@ if (BUILD_TESTING) LL_ADD_INTEGRATION_TEST(alignment "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llbbox llbbox.cpp "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(llquaternion llquaternion.cpp "${test_libs}" "${test_project}") + LL_ADD_INTEGRATION_TEST(llsdutil_math "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(mathmisc "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(m3math "" "${test_libs}" "${test_project}") LL_ADD_INTEGRATION_TEST(v3dmath v3dmath.cpp "${test_libs}" "${test_project}") diff --git a/indra/llmath/tests/llsdutil_math_test.cpp b/indra/llmath/tests/llsdutil_math_test.cpp new file mode 100644 index 00000000000..f7f096e59a2 --- /dev/null +++ b/indra/llmath/tests/llsdutil_math_test.cpp @@ -0,0 +1,153 @@ +/** + * @file llsdutil_tut.cpp + * @author Adroit + * @date 2007-02 + * @brief LLSD conversion routines test cases. + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, 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 "linden_common.h" +#include "lltut.h" +#include "m4math.h" +#include "v2math.h" +#include "v2math.h" +#include "v3color.h" +#include "v3math.h" +#include "v3dmath.h" +#include "v4coloru.h" +#include "v4math.h" +#include "llquaternion.h" +#include "llsdutil.h" +#include "llsdutil_math.h" +#include "stringize.h" +#include +#include + +namespace tut +{ + struct llsdutil_math_data + { + void test_matches(const std::string& proto_key, const LLSD& possibles, + const char** begin, const char** end) + { + std::set succeed(begin, end); + LLSD prototype(possibles[proto_key]); + for (LLSD::map_const_iterator pi(possibles.beginMap()), pend(possibles.endMap()); + pi != pend; ++pi) + { + std::string match(llsd_matches(prototype, pi->second)); + std::set::const_iterator found = succeed.find(pi->first); + if (found != succeed.end()) + { + // This test is supposed to succeed. Comparing to the + // empty string ensures that if the test fails, it will + // display the string received so we can tell what failed. + ensure_equals("match", match, ""); + } + else + { + // This test is supposed to fail. If we get a false match, + // the string 'match' will be empty, which doesn't tell us + // much about which case went awry. So construct a more + // detailed description string. + ensure(proto_key + " shouldn't match " + pi->first, ! match.empty()); + } + } + } + }; + typedef test_group llsdutil_math_test; + typedef llsdutil_math_test::object llsdutil_math_object; + tut::llsdutil_math_test tutil("llsdutil_math"); + + template<> template<> + void llsdutil_math_object::test<1>() + { + LLSD sd; + LLVector3 vec1(-1.0, 2.0, -3.0); + sd = ll_sd_from_vector3(vec1); + LLVector3 vec2 = ll_vector3_from_sd(sd); + ensure_equals("vector3 -> sd -> vector3: 1", vec1, vec2); + + LLVector3 vec3(sd); + ensure_equals("vector3 -> sd -> vector3: 2", vec1, vec3); + + sd.clear(); + vec1.setVec(0., 0., 0.); + sd = ll_sd_from_vector3(vec1); + vec2 = ll_vector3_from_sd(sd); + ensure_equals("vector3 -> sd -> vector3: 3", vec1, vec2); + sd.clear(); + } + + template<> template<> + void llsdutil_math_object::test<2>() + { + LLSD sd; + LLVector3d vec1((F64)(U64L(0xFEDCBA9876543210) << 2), -1., 0); + sd = ll_sd_from_vector3d(vec1); + LLVector3d vec2 = ll_vector3d_from_sd(sd); + ensure_equals("vector3d -> sd -> vector3d: 1", vec1, vec2); + + LLVector3d vec3(sd); + ensure_equals("vector3d -> sd -> vector3d : 2", vec1, vec3); + } + + template<> template<> + void llsdutil_math_object::test<3>() + { + LLSD sd; + LLVector2 vec((F32) -3., (F32) 4.2); + sd = ll_sd_from_vector2(vec); + LLVector2 vec1 = ll_vector2_from_sd(sd); + ensure_equals("vector2 -> sd -> vector2", vec, vec1); + + LLSD sd2 = ll_sd_from_vector2(vec1); + ensure_equals("sd -> vector2 -> sd: 2", sd, sd2); + } + + template<> template<> + void llsdutil_math_object::test<4>() + { + LLSD sd; + LLQuaternion quat((F32) 1., (F32) -0.98, (F32) 2.3, (F32) 0xffff); + sd = ll_sd_from_quaternion(quat); + LLQuaternion quat1 = ll_quaternion_from_sd(sd); + ensure_equals("LLQuaternion -> sd -> LLQuaternion", quat, quat1); + + LLSD sd2 = ll_sd_from_quaternion(quat1); + ensure_equals("sd -> LLQuaternion -> sd ", sd, sd2); + } + + template<> template<> + void llsdutil_math_object::test<5>() + { + LLSD sd; + LLColor4 c(1.0f, 2.2f, 4.0f, 7.f); + sd = ll_sd_from_color4(c); + LLColor4 c1 =ll_color4_from_sd(sd); + ensure_equals("LLColor4 -> sd -> LLColor4", c, c1); + + LLSD sd1 = ll_sd_from_color4(c1); + ensure_equals("sd -> LLColor4 -> sd", sd, sd1); + } +} diff --git a/indra/llprecompiled/CMakeLists.txt b/indra/llprecompiled/CMakeLists.txt index f3303cb8c1e..813b1afa6d4 100644 --- a/indra/llprecompiled/CMakeLists.txt +++ b/indra/llprecompiled/CMakeLists.txt @@ -6,10 +6,6 @@ set(llprecompiled_SOURCE_FILES add_library (llprecompiled STATIC ${llprecompiled_SOURCE_FILES}) -target_include_directories(llprecompiled PRIVATE - ${INDRA_SOURCE_DIR}/llmath - ) - target_link_libraries(llprecompiled llcommon ll::apr @@ -25,7 +21,6 @@ target_precompile_headers(llprecompiled PRIVATE [["linden_common.h"]] [["llwin32headers.h"]] [["llprofiler.h"]] - [["llmath.h"]] @@ -41,10 +36,6 @@ target_precompile_headers(llprecompiled PRIVATE add_executable(llprecompiled_exe ${llprecompiled_SOURCE_FILES}) -target_include_directories(llprecompiled_exe PRIVATE - ${INDRA_SOURCE_DIR}/llmath - ) - target_link_libraries(llprecompiled_exe llcommon ll::apr @@ -60,7 +51,6 @@ target_precompile_headers(llprecompiled_exe PRIVATE [["linden_common.h"]] [["llwin32headers.h"]] [["llprofiler.h"]] - [["llmath.h"]] From bf269275423e2ff60865e64f8468959169bf0c24 Mon Sep 17 00:00:00 2001 From: Rye Date: Fri, 26 Jun 2026 06:29:11 -0400 Subject: [PATCH 7/9] Initial changes required to build llcommon as a shared library --- indra/cmake/LLAddBuildTest.cmake | 3 - indra/llcommon/CMakeLists.txt | 28 ++++++- indra/llcommon/apply.h | 2 +- indra/llcommon/hbxxh.h | 4 +- indra/llcommon/lazyeventapi.h | 2 +- indra/llcommon/llapp.h | 2 +- indra/llcommon/llcallbacklist.h | 12 +-- indra/llcommon/llcleanup.h | 2 +- indra/llcommon/llerror.h | 6 +- indra/llcommon/lleventcoro.h | 10 +-- indra/llcommon/lleventfilter.h | 10 +-- indra/llcommon/llexception.h | 12 +-- indra/llcommon/llfasttimer.h | 29 ++++--- indra/llcommon/llfile.h | 6 +- indra/llcommon/llheteromap.h | 2 +- indra/llcommon/llinitdestroyclass.h | 2 +- indra/llcommon/llinitparam.h | 2 +- indra/llcommon/llinstancetracker.h | 2 +- indra/llcommon/llkeybind.h | 4 +- indra/llcommon/llmutex.cpp | 39 ---------- indra/llcommon/llmutex.h | 28 ++++++- indra/llcommon/llpointer.h | 2 +- indra/llcommon/llpredicate.h | 2 +- indra/llcommon/llprocess.cpp | 2 + indra/llcommon/llprocess.h | 1 + indra/llcommon/llrand.cpp | 2 + indra/llcommon/llregex.h | 8 +- indra/llcommon/llsdjson.h | 8 +- indra/llcommon/llsdserialize.cpp | 2 + indra/llcommon/llsdutil.h | 12 +-- indra/llcommon/llstaticstringtable.h | 8 +- indra/llcommon/llstring.cpp | 2 +- indra/llcommon/llstring.h | 29 ++++--- indra/llcommon/llthread.cpp | 72 ++++++++++++++++++ indra/llcommon/llthread.h | 2 +- indra/llcommon/llthreadlocalstorage.h | 25 ++++-- indra/llcommon/lltimer.h | 4 +- indra/llcommon/lltrace.h | 2 +- indra/llcommon/lltraceaccumulators.h | 76 ++++++++++++------- indra/llcommon/lltracerecording.h | 11 +-- indra/llcommon/lltracethreadrecorder.h | 8 +- indra/llcommon/lluuid.cpp | 10 +++ indra/llcommon/lluuid.h | 13 +++- indra/llcommon/llwatchdog.h | 11 ++- indra/llcommon/llwin32headers.h | 2 +- indra/llcommon/lockstatic.h | 57 +++++++++----- indra/llcommon/tests/lleventfilter_test.cpp | 7 +- indra/llcommon/tests/lluuid_test.cpp | 9 ++- indra/llcommon/threadpool.h | 4 +- indra/llcommon/workqueue.h | 10 ++- indra/llmessage/llpumpio.h | 1 + indra/llmessage/tests/io_test.cpp | 1 + indra/llplugin/slplugin/CMakeLists.txt | 2 - .../llprimitive/tests/llgltfmaterial_test.cpp | 1 - indra/llprimitive/tests/llmaterial_test.cpp | 1 - indra/llprimitive/tests/llmaterialid_test.cpp | 1 - indra/newview/llappviewer.cpp | 2 +- indra/newview/llappviewer.h | 1 - indra/newview/llfloaterabout.cpp | 1 - 59 files changed, 394 insertions(+), 225 deletions(-) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index f9e66951af6..78db3d98805 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -98,8 +98,6 @@ MACRO(LL_ADD_PROJECT_UNIT_TESTS project sources) ) endif(DARWIN) - target_precompile_headers(PROJECT_${project}_TEST_${name} REUSE_FROM llprecompiled_exe) - # # Per-codefile additional / external project dep and lib dep property extraction # @@ -246,7 +244,6 @@ FUNCTION(LL_ADD_INTEGRATION_TEST target_link_libraries(INTEGRATION_TEST_${testname} ${libraries}) target_include_directories (INTEGRATION_TEST_${testname} PRIVATE ${INDRA_SOURCE_DIR}/test ${INDRA_SOURCE_DIR}/llmath ${INDRA_SOURCE_DIR}/llui) - target_precompile_headers(INTEGRATION_TEST_${testname} REUSE_FROM llprecompiled_exe) # Create the test running command set(test_command ${ARGN}) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index e8d93d8fa6b..0cb1a120c58 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -1,6 +1,30 @@ # -*- cmake -*- -add_library(llcommon STATIC) +if (LL_COMMON_LINK_SHARED) + add_library(llcommon SHARED) + + target_compile_definitions(llcommon PUBLIC LL_COMMON_LINK_SHARED=1) + + add_custom_command( + TARGET llcommon POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "${SHARED_LIB_STAGING_DIR}" + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + TARGET llcommon POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "${VIEWER_STAGING_DIR}" + COMMAND_EXPAND_LISTS + ) + + add_custom_command( + TARGET llcommon POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "${VIEWER_STAGING_DIR}/llplugin" + COMMAND_EXPAND_LISTS + ) +else() + add_library(llcommon STATIC) +endif() target_sources(llcommon PRIVATE @@ -288,8 +312,6 @@ target_link_libraries( target_include_directories(llcommon PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_precompile_headers(llcommon REUSE_FROM llprecompiled) - add_dependencies(llcommon stage_third_party_libs) if (BUILD_TESTING) diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index ec1a39f7b07..0ffc6e85b28 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -194,7 +194,7 @@ auto apply_impl(CALLABLE&& func, const std::vector& args, std::index_sequence } // produce suitable error if apply(func, vector) is the wrong size for func() -void apply_validate_size(size_t size, size_t arity); +LL_COMMON_API void apply_validate_size(size_t size, size_t arity); /// possible exception from apply() validation struct apply_error: public LLException diff --git a/indra/llcommon/hbxxh.h b/indra/llcommon/hbxxh.h index 142e140cf3a..8db17fb444e 100644 --- a/indra/llcommon/hbxxh.h +++ b/indra/llcommon/hbxxh.h @@ -39,7 +39,7 @@ // 64 bits hashing class -class HBXXH64 +class LL_COMMON_API HBXXH64 { friend std::ostream& operator<<(std::ostream&, HBXXH64); @@ -151,7 +151,7 @@ inline bool operator!=(const HBXXH64& a, const HBXXH64& b) // 128 bits hashing class -class HBXXH128 +class LL_COMMON_API HBXXH128 { friend std::ostream& operator<<(std::ostream&, HBXXH128); diff --git a/indra/llcommon/lazyeventapi.h b/indra/llcommon/lazyeventapi.h index 0e5df4e6f46..11f9ae1cd04 100644 --- a/indra/llcommon/lazyeventapi.h +++ b/indra/llcommon/lazyeventapi.h @@ -49,7 +49,7 @@ namespace LL */ // No LLInstanceTracker key: we don't need to find a specific instance, // LLLeapListener just needs to be able to enumerate all instances. - class LazyEventAPIBase: public LLInstanceTracker + class LL_COMMON_API LazyEventAPIBase: public LLInstanceTracker { public: LazyEventAPIBase(const std::string& name, const std::string& desc, diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 58b48c59ba4..d6acd78a044 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -50,7 +50,7 @@ void clear_signals(); #endif -extern bool gDisconnected; +extern LL_COMMON_API bool gDisconnected; class LL_COMMON_API LLApp { diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 036e575117d..66bbfd373a0 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -32,7 +32,7 @@ #include #include -class LLCallbackList +class LL_COMMON_API LLCallbackList { public: typedef void (*callback_t)(void*); @@ -64,17 +64,17 @@ typedef std::function nullary_func_t; typedef std::function bool_func_t; // Call a given callable once in idle loop. -void doOnIdleOneTime(nullary_func_t callable); +LL_COMMON_API void doOnIdleOneTime(nullary_func_t callable); // Repeatedly call a callable in idle loop until it returns true. -void doOnIdleRepeating(bool_func_t callable); +LL_COMMON_API void doOnIdleRepeating(bool_func_t callable); // Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds); +LL_COMMON_API void doAfterInterval(nullary_func_t callable, F32 seconds); // Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds); +LL_COMMON_API void doPeriodically(bool_func_t callable, F32 seconds); -extern LLCallbackList gIdleCallbacks; +extern LL_COMMON_API LLCallbackList gIdleCallbacks; #endif diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h index b120a5c4fe5..6e12af2353b 100644 --- a/indra/llcommon/llcleanup.h +++ b/indra/llcommon/llcleanup.h @@ -33,7 +33,7 @@ // Use ancient do { ... } while (0) macro trick to permit a block of // statements with the same syntax as a single statement. -void log_subsystem_cleanup(LLError::ELevel level, +LL_COMMON_API void log_subsystem_cleanup(LLError::ELevel level, const char* file, int line, const char* function, diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 364b79d9f4d..3be080f2787 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -263,7 +263,7 @@ namespace LLError }; - class End { }; + class LL_COMMON_API End { }; inline std::ostream& operator<<(std::ostream& s, const End&) { return s; } // used to indicate the end of a message @@ -293,14 +293,14 @@ namespace LLError }; // class which, when streamed, inserts the current stack trace - struct LLStacktrace + struct LL_COMMON_API LLStacktrace { friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&); }; // Provides access to OS notification popup on error, since // not everything has access to OS's messages - class LLUserWarningMsg + class LL_COMMON_API LLUserWarningMsg { public: // error codes, tranlates to last_exec states like LAST_EXEC_OTHER_CRASH diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 25a8a98e368..ec56713be45 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -77,17 +77,17 @@ namespace llcoro * runs without suspending for nontrivial time, sprinkle in calls to this * function to avoid stalling the rest of the viewer processing. */ -void suspend(); +LL_COMMON_API void suspend(); /** * Yield control from a coroutine for at least the specified number of seconds */ -void suspendUntilTimeout(float seconds); +LL_COMMON_API void suspendUntilTimeout(float seconds); /** * Yield control from a coroutine until the next mainloop's newFrame event. */ -void suspendUntilNextFrame(); +LL_COMMON_API void suspendUntilNextFrame(); /** * Post specified LLSD event on the specified LLEventPump, then suspend for a @@ -136,7 +136,7 @@ void suspendUntilNextFrame(); * @a replyPumpNamePath specifies the entry in the lowest-level structure in * @a event into which to store replyPump.getName(). */ -LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump, +LL_COMMON_API LLSD postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump, const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath=LLSD()); /// Wait for the next event on the specified LLEventPump. Pass either the @@ -150,7 +150,7 @@ LLSD suspendUntilEventOn(const LLEventPumpOrPumpName& pump) /// Like postAndSuspend(), but if we wait longer than @a timeout seconds, /// stop waiting and return @a timeoutResult instead. -LLSD postAndSuspendWithTimeout(const LLSD& event, +LL_COMMON_API LLSD postAndSuspendWithTimeout(const LLSD& event, const LLEventPumpOrPumpName& requestPump, const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath, diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 8b917c23be1..e62024a93b7 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -62,7 +62,7 @@ class LL_COMMON_API LLEventFilter: public LLEventStream /** * Pass through only events matching a specified pattern */ -class LLEventMatching: public LLEventFilter +class LL_COMMON_API LLEventMatching: public LLEventFilter { public: /// Pass an LLSD map with keys and values the incoming event must match @@ -347,7 +347,7 @@ class LL_COMMON_API LLEventThrottleBase: public LLEventFilter /** * Production implementation of LLEventThrottle. */ -class LLEventThrottle: public LLEventThrottleBase +class LL_COMMON_API LLEventThrottle: public LLEventThrottleBase { public: LLEventThrottle(F32 interval); @@ -374,7 +374,7 @@ class LLEventThrottle: public LLEventThrottleBase * pending events into an LLSD Array, optionally flushing when the batch grows * to a certain size. */ -class LLEventBatchThrottle: public LLEventThrottle +class LL_COMMON_API LLEventBatchThrottle: public LLEventThrottle { public: // pass time interval and (optionally) max batch size; 0 means batch can @@ -408,7 +408,7 @@ class LLEventBatchThrottle: public LLEventThrottle * the iterator. Useful with boost::coroutine2! */ template -class LLStoreListener: public LLEventFilter +class LLStoreListener: public LLEventFilter // template: methods are inline; do NOT tag LL_COMMON_API { public: // pass target and optional path to element @@ -507,7 +507,7 @@ class LLCaptureListener: public LLVarHolder, * The proxy role means that LLEventLogProxy intercepts more of LLEventPump's * API than a typical LLEventFilter subclass. */ -class LLEventLogProxy: public LLEventFilter +class LL_COMMON_API LLEventLogProxy: public LLEventFilter { typedef LLEventFilter super; public: diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 68e609444ec..9b6fdbb5a81 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -39,7 +39,7 @@ * usage. However, most of the value of this base class is in the * diagnostic_information() available via Boost.Exception. */ -struct LLException: +struct LL_COMMON_API LLException : public std::runtime_error, public boost::exception { @@ -55,7 +55,7 @@ struct LLException: * derived from LLContinueError will still be logged, the viewer will attempt * to continue processing. */ -struct LLContinueError: public LLException +struct LL_COMMON_API LLContinueError : public LLException { LLContinueError(const std::string& what): LLException(what) @@ -89,18 +89,18 @@ do { \ /* Use the classic 'do { ... } while (0)' macro trick to wrap */ \ /* our multiple statements. */ \ } while (0) -void annotate_exception_(boost::exception& exc); +LL_COMMON_API void annotate_exception_(boost::exception& exc); /// Call this macro from a catch (...) clause #define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \ crash_on_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT) -void crash_on_unhandled_exception_(const char*, int, const char*, const std::string&); +LL_COMMON_API void crash_on_unhandled_exception_(const char*, int, const char*, const std::string&); /// Call this from a catch (const LLContinueError&) clause, or from a catch /// (...) clause in which you do NOT want the viewer to crash. #define LOG_UNHANDLED_EXCEPTION(CONTEXT) \ log_unhandled_exception_(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, CONTEXT) -void log_unhandled_exception_(const char*, int, const char*, const std::string&); +LL_COMMON_API void log_unhandled_exception_(const char*, int, const char*, const std::string&); #if LL_WINDOWS @@ -108,7 +108,7 @@ void log_unhandled_exception_(const char*, int, const char*, const std::string&) // SEH exception filtering for use in __try __except // Separates C++ exceptions from C SEH exceptions // Todo: might be good idea to do some kind of seh_to_msc_wrapper(function, ARGS&&); -U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop); +LL_COMMON_API U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop); #endif //LL_WINDOWS diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 271dade0979..546661d9fab 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -53,7 +53,7 @@ namespace LLTrace // use to create blocktimer rvalue to be captured in a reference so that the BlockTimer lives to the end of the block. class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer); -class BlockTimer +class LL_COMMON_API BlockTimer { public: typedef BlockTimer self_t; @@ -204,8 +204,10 @@ class BlockTimer BlockTimer(BlockTimerStatHandle& timer); // no-copy - BlockTimer(const BlockTimer& other); - BlockTimer& operator=(const BlockTimer& other); + BlockTimer(const BlockTimer& other) = delete; + BlockTimer(BlockTimer&& other) = delete; + BlockTimer& operator=(const BlockTimer& other) = delete; + BlockTimer& operator=(BlockTimer&& other) = delete; private: U64 mStartTime; @@ -213,9 +215,12 @@ class BlockTimer public: // statics + // NOTE: declared separately (not 'static bool sMetricLog, sLog;'): MSVC + // mis-handles a multi-declarator static in a dllexport class, flagging the + // second name with C2487. static std::string sLogName; - static bool sMetricLog, - sLog; + static bool sMetricLog; + static bool sLog; static U64 sClockResolution; }; @@ -231,7 +236,7 @@ LL_FORCE_INLINE class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer } // stores a "named" timer instance to be reused via multiple BlockTimer stack instances -class BlockTimerStatHandle +class LL_COMMON_API BlockTimerStatHandle : public StatType { public: @@ -266,12 +271,12 @@ typedef LLTreeDFSIter block_timer_tree_df_post_iterator_t; typedef LLTreeBFSIter block_timer_tree_bf_iterator_t; -block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id); -block_timer_tree_df_iterator_t end_block_timer_tree_df(); -block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id); -block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post(); -block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id); -block_timer_tree_bf_iterator_t end_block_timer_tree_bf(); +LL_COMMON_API block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id); +LL_COMMON_API block_timer_tree_df_iterator_t end_block_timer_tree_df(); +LL_COMMON_API block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id); +LL_COMMON_API block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post(); +LL_COMMON_API block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id); +LL_COMMON_API block_timer_tree_bf_iterator_t end_block_timer_tree_bf(); LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer) { diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 8de3f5c9b44..ea67665aa25 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -68,7 +68,7 @@ typedef FILE LLFILE; /// /// @nosubgrouping /// -class LLFile +class LL_COMMON_API LLFile { public: // ================================================================================ @@ -699,7 +699,7 @@ class LLFile * Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't * true of Microsoft's std::ifstream. */ -class llifstream : public std::ifstream +class LL_COMMON_API llifstream : public std::ifstream { // input stream associated with a C stream public: @@ -811,7 +811,7 @@ class LLUniqueFile * Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of * Microsoft's std::ofstream. */ -class llofstream : public std::ofstream +class LL_COMMON_API llofstream : public std::ofstream { public: // Constructors: diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h index 608e839f8b0..8a35007e52e 100644 --- a/indra/llcommon/llheteromap.h +++ b/indra/llcommon/llheteromap.h @@ -32,7 +32,7 @@ * LLHeteroMap collects objects WITHOUT a common base class, retrieves them by * object type and destroys them when the LLHeteroMap is destroyed. */ -class LLHeteroMap +class LL_COMMON_API LLHeteroMap { public: ~LLHeteroMap(); diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h index 7cc9c6b930a..9bdb5f3ae67 100644 --- a/indra/llcommon/llinitdestroyclass.h +++ b/indra/llcommon/llinitdestroyclass.h @@ -47,7 +47,7 @@ * LLInitClassList and LLDestroyClassList. It accumulates the initClass() or * destroyClass() callbacks for registered classes. */ -class LLCallbackRegistry +class LL_COMMON_API LLCallbackRegistry { public: typedef std::function func_t; diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 0dbbc956934..cf5b43dce93 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -615,7 +615,7 @@ namespace LLInitParam typedef LLPredicate::Rule predicate_rule_t; - predicate_rule_t default_parse_rules(); + LL_COMMON_API predicate_rule_t default_parse_rules(); // various callbacks and constraints associated with an individual param struct LL_COMMON_API ParamDescriptor diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index e6a69636850..6211ce4f5ec 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -57,7 +57,7 @@ namespace LLInstanceTrackerPrivate LL_PROFILE_MUTEX_NAMED(std::mutex, mMutex, "InstanceTracker Data"); }; - void logerrs(const char* cls, const std::string&, const std::string&, const std::string&); + LL_COMMON_API void logerrs(const char* cls, const std::string&, const std::string&, const std::string&); } // namespace LLInstanceTrackerPrivate /***************************************************************************** diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 0a9d4600cca..c4aac859237 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -57,10 +57,10 @@ class LL_COMMON_API LLKeyData }; // One function can bind to multiple Key options -class LLKeyBind +class LL_COMMON_API LLKeyBind { public: - LLKeyBind() {} + LLKeyBind() = default; LLKeyBind(const LLSD &key_bind); bool operator==(const LLKeyBind& rhs); diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index be1ae89a259..c4032db6b08 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -355,45 +355,6 @@ void LLCondition::broadcast() mCond.notify_all(); } - -//--------------------------------------------------------------------- -// -// LLMutexTrylock -// -LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) - : mMutex(mutex), - mLocked(false) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - if (mMutex) - mLocked = mMutex->trylock(); -} - -LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) - : mMutex(mutex), - mLocked(false) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - if (!mMutex) - return; - - for (U32 i = 0; i < aTries; ++i) - { - mLocked = mMutex->trylock(); - if (mLocked) - break; - ms_sleep(delay_ms); - } -} - -LLMutexTrylock::~LLMutexTrylock() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - if (mMutex && mLocked) - mMutex->unlock(); -} - - //--------------------------------------------------------------------- // // LLScopedLock diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index bc3d8fed062..7e6ca5da8aa 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -225,9 +225,31 @@ using LLExclusiveMutexLock = LLSharedMutexLockTemplate; class LLMutexTrylock { public: - LLMutexTrylock(LLMutex* mutex); - LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); - ~LLMutexTrylock(); + LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) + { + if (mMutex) + mLocked = mMutex->trylock(); + } + + LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) : mMutex(mutex), mLocked(false) + { + if (!mMutex) + return; + + for (U32 i = 0; i < aTries; ++i) + { + mLocked = mMutex->trylock(); + if (mLocked) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms)); + } + } + + ~LLMutexTrylock() + { + if (mMutex && mLocked) + mMutex->unlock(); + } bool isLocked() const { diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 7897b2b5066..c2f1db44eed 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -44,7 +44,7 @@ //---------------------------------------------------------------------------- -class LLPointerBase +class LL_COMMON_API LLPointerBase { protected: // alert the coder that a referenced type's destructor did something very diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h index 91c623eae13..45c947fbf58 100644 --- a/indra/llcommon/llpredicate.h +++ b/indra/llcommon/llpredicate.h @@ -33,7 +33,7 @@ namespace LLPredicate { template class Rule; - extern const U32 cPredicateFlagsFromEnum[5]; + extern LL_COMMON_API const U32 cPredicateFlagsFromEnum[5]; template class Value diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 39bbfc3eab5..0bf1ac706ae 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -25,6 +25,8 @@ */ #include "linden_common.h" +#include "llwin32headers.h" + #include "llprocess.h" #include "llsdutil.h" #include "llsdserialize.h" diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 0c71cfc4159..ecdedbbaa30 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -30,6 +30,7 @@ #include "llinitparam.h" #include "llsdparam.h" #include "llexception.h" +#include "llwin32headers.h" #include "apr_thread_proc.h" #include #include // std::ostream diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 64a8e893ac3..810f32d1a83 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -29,6 +29,8 @@ #include "llrand.h" #include "lluuid.h" +#include + /** * Through analysis, we have decided that we want to take values which * are close enough to 1.0 to map back to 0.0. We came to this diff --git a/indra/llcommon/llregex.h b/indra/llcommon/llregex.h index 18da304aeee..5c1607e7be4 100644 --- a/indra/llcommon/llregex.h +++ b/indra/llcommon/llregex.h @@ -28,7 +28,7 @@ #include template -LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) +inline bool ll_regex_match(const S& string, M& match, const R& regex) { try { @@ -43,7 +43,7 @@ LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) } template -LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) +inline bool ll_regex_match(const S& string, const R& regex) { try { @@ -58,7 +58,7 @@ LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) } template -bool ll_regex_search(const S& string, M& match, const R& regex) +inline bool ll_regex_search(const S& string, M& match, const R& regex) { try { @@ -73,7 +73,7 @@ bool ll_regex_search(const S& string, M& match, const R& regex) } template -bool ll_regex_search(const S& string, const R& regex) +inline bool ll_regex_search(const S& string, const R& regex) { try { diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h index bee9e81b607..5ce80d91467 100644 --- a/indra/llcommon/llsdjson.h +++ b/indra/llcommon/llsdjson.h @@ -52,17 +52,17 @@ /// /// For maps and arrays child entries will be converted and added to the structure. /// Order is preserved for an array but not for objects. -LLSD LlsdFromJson(const simdjson::dom::element& val); +LL_COMMON_API LLSD LlsdFromJson(const simdjson::dom::element& val); /// Parse a JSON document from text and convert it into LLSD as above. /// Returns false (leaving out undefined) on a parse failure; if errmsg is /// non-null it receives a description of the failure. -bool LlsdFromJsonString(std::string_view json, LLSD& out, std::string* errmsg = nullptr); +LL_COMMON_API bool LlsdFromJsonString(std::string_view json, LLSD& out, std::string* errmsg = nullptr); /// As above, but parses the buffer in place with no internal copy. Callers /// that materialize a document from raw bytes should read directly into a /// simdjson::padded_string and use this overload. -bool LlsdFromJsonString(const simdjson::padded_string& json, LLSD& out, std::string* errmsg = nullptr); +LL_COMMON_API bool LlsdFromJsonString(const simdjson::padded_string& json, LLSD& out, std::string* errmsg = nullptr); /// disambiguate std::string and C strings against the string_view and /// padded_string overloads (padded_string converts implicitly from @@ -94,6 +94,6 @@ inline bool LlsdFromJsonString(const char* json, LLSD& out, std::string* errmsg /// TypeMap | object /// TypeArray | array /// TypeBinary | unsupported -std::string LlsdToJson(const LLSD& val); +LL_COMMON_API std::string LlsdToJson(const LLSD& val); #endif // LL_LLSDJSON_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index a70de156553..d2e062f4d29 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -46,6 +46,8 @@ #if !LL_WINDOWS #include // htonl & ntohl +#else +#include "llwin32headers.h" #endif #include "lldate.h" diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 497c0ad3eb7..4f4fa13ea2a 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -85,7 +85,7 @@ LL_COMMON_API bool compare_llsd_with_template( // (3) The element of an array with exactly one element is taken as a template // for *all* the elements of the test array. If the template array is of // different size, compare_llsd_with_template() semantics apply. -bool filter_llsd_with_template( +LL_COMMON_API bool filter_llsd_with_template( const LLSD & llsd_to_test, const LLSD & template_llsd, LLSD & resultant_llsd); @@ -192,8 +192,8 @@ namespace llsd * By implication, if path.isUndefined() or otherwise equivalent to an empty * LLSD::Array, drill[_ref]() returns 'blob' as is. */ -LLSD drill(const LLSD& blob, const LLSD& path); -LLSD& drill_ref( LLSD& blob, const LLSD& path); +LL_COMMON_API LLSD drill(const LLSD& blob, const LLSD& path); +LL_COMMON_API LLSD& drill_ref(LLSD& blob, const LLSD& path); } @@ -535,12 +535,12 @@ class inMap // when encountered in a map. A key name of "*" can be specified as a wild card // and will specify the default behavior. If no wild card is given and the clone // encounters a name not in the filter, that value will be skipped. -LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); +LL_COMMON_API LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); // Creates a shallow copy of a map or array. If passed any other type of LLSD // object it simply returns that value. See llsd_clone for a description of // the filter parameter. -LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); +LL_COMMON_API LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); namespace llsd { @@ -722,7 +722,7 @@ namespace LL *****************************************************************************/ // validate incoming LLSD blob, and return an LLSD array suitable to pass to // the function of interest -LLSD apply_llsd_fix(size_t arity, const LLSD& args); +LL_COMMON_API LLSD apply_llsd_fix(size_t arity, const LLSD& args); // Derived from https://stackoverflow.com/a/20441189 // and https://en.cppreference.com/w/cpp/utility/apply . diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h index 55a966a76f5..514d0fff754 100644 --- a/indra/llcommon/llstaticstringtable.h +++ b/indra/llcommon/llstaticstringtable.h @@ -28,11 +28,16 @@ #ifndef LL_STATIC_STRING_TABLE_H #define LL_STATIC_STRING_TABLE_H +#include "llpreprocessor.h" + #include "lldefs.h" #include "llstl.h" #include +// Header-only: all methods are inline/defaulted, so do NOT tag LL_COMMON_API. +// Tagging would make consumers import a dtor (and, via the table below, boost +// unordered_map methods) that the DLL never emits. class LLStaticHashedString { public: @@ -42,6 +47,7 @@ class LLStaticHashedString string_hash = makehash(s); string = s; } + ~LLStaticHashedString() = default; const std::string& String() const { return string; } size_t Hash() const { return string_hash; } @@ -74,7 +80,7 @@ struct LLStaticStringHasher }; template< typename MappedObject > -class LL_COMMON_API LLStaticStringTable +class LLStaticStringTable : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > { }; diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 51a6990809c..4332ff51c3a 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1084,7 +1084,7 @@ unsigned long windows_get_last_error() } template<> -std::wstring windows_message(DWORD error) +LL_COMMON_API std::wstring windows_message(DWORD error) { // derived from https://stackoverflow.com/a/455533 wchar_t* rawptr = nullptr; diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index bcca233cd4f..83a44fa1081 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -783,26 +783,33 @@ ll_convert_forms(ll_convert_alias, std::wstring, LLWString, ll_convert_wstring_t */ LL_COMMON_API std::string ll_convert_string_to_utf8_string(const std::string& in); -/// Get Windows message string for passed GetLastError() code -// VS 2013 doesn't let us forward-declare this template, which is what we -// started with, so the implementation could reference the specialization we -// haven't yet declared. Somewhat weirdly, just stating the generic -// implementation in terms of the specialization works, even in this order... - -// the general case is just a conversion from the sole implementation +/// Get Windows message string for passed GetLastError() code. // Microsoft says DWORD is a typedef for unsigned long // https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types // so rather than drag windows.h into everybody's include space... +// +// Ordering matters for the DLL build: forward-declare the primary template, +// then declare the exported std::wstring specialization (defined in +// llstring.cpp), then define the primary in terms of that specialization. The +// specialization must be declared BEFORE the primary's body references it, +// else an implicit instantiation is assumed and clashes with the +// specialization's dll linkage (C2375 "different linkage"). The primary itself +// carries no LL_COMMON_API: it is defined inline and instantiated per-consumer, +// so dllexport/dllimport on it is both illegal and unnecessary. template -STRING windows_message(unsigned long error) -{ - return ll_convert(windows_message(error)); -} +STRING windows_message(unsigned long error); /// There's only one real implementation template<> LL_COMMON_API std::wstring windows_message(unsigned long error); +// the general case is just a conversion from the sole implementation +template +STRING windows_message(unsigned long error) +{ + return ll_convert(windows_message(error)); +} + /// Get Windows message string, implicitly calling GetLastError() LL_COMMON_API unsigned long windows_get_last_error(); diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 0f8af1d19fe..893145e5d74 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -34,6 +34,10 @@ #include "lltracethreadrecorder.h" #include "llexception.h" #include "workqueue.h" +#include "lockstatic.h" + +#include +#include #if LL_LINUX #include @@ -156,6 +160,74 @@ LL_COMMON_API bool assert_main_thread() return false; } +namespace llthread +{ +void* getCanonicalStatic(const char* name, void* (*factory)()) +{ + // The canonical per-type statics live here, in a single translation unit -- + // hence a single module even in a multi-DLL build -- so every module that + // instantiates LockStatic for a given Static resolves the SAME + // instance. Keyed by the mangled name string (typeid(Static).name()) rather + // than std::type_index: under -fvisibility=hidden each module has its own + // type_info object, so identity comparison would treat the same type as a + // different key per module and re-introduce the duplication we are removing. + // The mangled name string is identical across modules for one ABI. + // + // Heap-allocated and intentionally never freed so the statics outlive every + // user (LockStatic consumers' own statics may be torn down at process exit). + static std::mutex* sMutex = new std::mutex(); + static auto* sRegistry = new std::unordered_map(); + std::lock_guard lk(*sMutex); + void*& slot = (*sRegistry)[name]; + if (! slot) + { + slot = factory(); + } + return slot; +} + +// ---- DLL-safe thread-local slots (see lockstatic.h) ---- +namespace +{ + constexpr size_t MAX_THREAD_LOCAL_SLOTS = 256; + // The one and only thread_local store, owned by this module. Reached from + // every module through the exported accessors below, so all modules share a + // single per-thread value per slot. + thread_local void* sThreadLocalSlots[MAX_THREAD_LOCAL_SLOTS] = {}; +} + +size_t allocThreadLocalSlot(const char* name) +{ + // Assign a stable slot index per type name, once, shared across all modules. + // (The mangled name string is identical across modules for one ABI -- see + // getCanonicalStatic() above for the hidden-visibility rationale.) + static std::mutex* sMutex = new std::mutex(); + static auto* sIndices = new std::unordered_map(); + std::lock_guard lk(*sMutex); + auto it = sIndices->find(name); + if (it != sIndices->end()) + return it->second; + size_t index = sIndices->size(); + if (index >= MAX_THREAD_LOCAL_SLOTS) + { + LL_ERRS() << "Exceeded MAX_THREAD_LOCAL_SLOTS (" << MAX_THREAD_LOCAL_SLOTS + << ") allocating thread-local slot for " << name << LL_ENDL; + } + (*sIndices)[name] = index; + return index; +} + +void* getThreadLocalSlot(size_t slot) +{ + return sThreadLocalSlots[slot]; +} + +void setThreadLocalSlot(size_t slot, void* value) +{ + sThreadLocalSlots[slot] = value; +} +} // namespace llthread + // // Handed to the APR thread creation function // diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 3952dde719c..97565590bb6 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -30,7 +30,7 @@ #include "llrefcount.h" #include -extern void set_thread_name(const char* threadName); +extern LL_COMMON_API void set_thread_name(const char* threadName); namespace LLTrace { diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h index 151d8a666b9..84e18c7930c 100644 --- a/indra/llcommon/llthreadlocalstorage.h +++ b/indra/llcommon/llthreadlocalstorage.h @@ -29,26 +29,39 @@ #define LL_LLTHREADLOCALSTORAGE_H #include "llinstancetracker.h" +#include "lockstatic.h" // llthread DLL-safe thread-local slots +#include +// A per-DERIVED_TYPE thread-local pointer. The actual thread_local storage is +// NOT a member here: a plain `thread_local DERIVED_TYPE* sInstance;` would be +// duplicated once per module in a shared-library build, so setInstance() in one +// module and getInstance() inlined into another would see different storage. +// (And a thread_local cannot be dllexport'd to share it -- MSVC C2492.) Instead +// we key into a single canonical thread-local slot array owned by llcommon, +// reached through exported accessors -- one extra (non-inlinable) call per +// access, the price of cross-module correctness. template class LLThreadLocalSingletonPointer { public: LL_FORCE_INLINE static DERIVED_TYPE* getInstance() { - return sInstance; + return static_cast(llthread::getThreadLocalSlot(slot())); } static void setInstance(DERIVED_TYPE* instance) { - sInstance = instance; + llthread::setThreadLocalSlot(slot(), instance); } private: - static thread_local DERIVED_TYPE* sInstance; + // Stable slot index for DERIVED_TYPE, cached per module; the value is + // canonical (identical) across modules. + static size_t slot() + { + static size_t sSlot = llthread::allocThreadLocalSlot(typeid(DERIVED_TYPE).name()); + return sSlot; + } }; -template -thread_local DERIVED_TYPE* LLThreadLocalSingletonPointer::sInstance = NULL; - #endif // LL_LLTHREADLOCALSTORAGE_H diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index d79f2505856..d8893c25261 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -114,7 +114,7 @@ class LL_COMMON_API LLTimer // // Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work. // -struct TimerInfo +struct LL_COMMON_API TimerInfo { TimerInfo(); void update(); @@ -126,7 +126,7 @@ struct TimerInfo U64 mLastTotalTimeClockCount; }; -TimerInfo& get_timer_info(); +LL_COMMON_API TimerInfo& get_timer_info(); LL_COMMON_API U64 get_clock_count(); diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index edb010b0a4d..c459bdf51e1 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -53,7 +53,7 @@ STORAGE_TYPE storage_value(LLUnit val) { return val.val template STORAGE_TYPE storage_value(LLUnitImplicit val) { return val.value(); } -class StatBase +class LL_COMMON_API StatBase { public: StatBase(const char* name, const char* description); diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index 0a2e2bf997a..f524ee5a928 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -35,7 +35,9 @@ #include "llrefcount.h" #include "llthreadlocalstorage.h" #include "llmemory.h" +#include "lockstatic.h" // llthread::getCanonicalStatic (DLL-safe statics) #include +#include namespace LLTrace { @@ -67,8 +69,8 @@ namespace LLTrace { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; const AccumulatorBuffer& other = *getDefaultBuffer(); - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) + resize(statics().mNextStorageSlot); + for (S32 i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i] = other.mStorage[i]; } @@ -100,8 +102,8 @@ namespace LLTrace mStorage(NULL) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) + resize(statics().mNextStorageSlot); + for (S32 i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i] = other.mStorage[i]; } @@ -110,8 +112,8 @@ namespace LLTrace void addSamples(const AccumulatorBuffer& other, EBufferAppendType append_type) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) + llassert(mStorageSize >= statics().mNextStorageSlot && other.mStorageSize >= statics().mNextStorageSlot); + for (size_t i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i].addSamples(other.mStorage[i], append_type); } @@ -120,8 +122,8 @@ namespace LLTrace void copyFrom(const AccumulatorBuffer& other) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) + llassert(mStorageSize >= statics().mNextStorageSlot && other.mStorageSize >= statics().mNextStorageSlot); + for (size_t i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i] = other.mStorage[i]; } @@ -130,8 +132,8 @@ namespace LLTrace void reset(const AccumulatorBuffer* other = NULL) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) + llassert(mStorageSize >= statics().mNextStorageSlot); + for (size_t i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i].reset(other ? &other->mStorage[i] : NULL); } @@ -140,8 +142,8 @@ namespace LLTrace void sync(F64SecondsImplicit time_stamp) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) + llassert(mStorageSize >= statics().mNextStorageSlot); + for (size_t i = 0; i < statics().mNextStorageSlot; i++) { mStorage[i].sync(time_stamp); } @@ -166,7 +168,7 @@ namespace LLTrace size_t reserveSlot() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - size_t next_slot = sNextStorageSlot++; + size_t next_slot = statics().mNextStorageSlot++; if (next_slot >= mStorageSize) { // don't perform doubling, as this should only happen during startup @@ -215,35 +217,51 @@ namespace LLTrace static size_t getNumIndices() { - return sNextStorageSlot; + return statics().mNextStorageSlot; } static self_t* getDefaultBuffer() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - static bool sInitialized = false; - if (!sInitialized) + // (Previously gated on a function-local `static bool sInitialized`, + // which is per-module and would re-init the shared buffer from a + // second module. Gate on the shared pointer itself instead.) + Statics& s = statics(); + if (!s.mDefaultBuffer) { // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data // so as not to trigger an access violation - sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); - sInitialized = true; - sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); + s.mDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); + s.mDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); } - return sDefaultBuffer; + return s.mDefaultBuffer; } private: ACCUMULATOR* mStorage; size_t mStorageSize; - static size_t sNextStorageSlot; - static self_t* sDefaultBuffer; - }; - template size_t AccumulatorBuffer::sNextStorageSlot = 0; - template AccumulatorBuffer* AccumulatorBuffer::sDefaultBuffer = NULL; + // Per-ACCUMULATOR statics, kept as ONE canonical instance shared across + // all modules (DLLs). A plain template static member duplicates per + // module in a shared-library build, which splits slot numbering and + // buffer sizing across modules and crashes (out-of-bounds accumulator + // access). getCanonicalStatic() lives in a single TU, so every module + // resolves the same instance. Keyed by typeid(self_t).name(). + struct Statics + { + size_t mNextStorageSlot = 0; + self_t* mDefaultBuffer = nullptr; + }; + static Statics& statics() + { + static Statics* s = static_cast( + llthread::getCanonicalStatic(typeid(self_t).name(), + []() -> void* { return new Statics(); })); + return *s; + } + }; - class EventAccumulator + class LL_COMMON_API EventAccumulator { public: typedef F64 value_t; @@ -314,7 +332,7 @@ namespace LLTrace }; - class SampleAccumulator + class LL_COMMON_API SampleAccumulator { public: typedef F64 value_t; @@ -411,7 +429,7 @@ namespace LLTrace bool mHasValue; }; - class CountAccumulator + class LL_COMMON_API CountAccumulator { public: typedef F64 value_t; @@ -454,7 +472,7 @@ namespace LLTrace S32 mNumSamples; }; - class alignas(32) TimeBlockAccumulator + class LL_COMMON_API alignas(32) TimeBlockAccumulator { public: typedef F64Seconds value_t; diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index ad4c91d85be..5fd5ac24f43 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -40,7 +40,7 @@ #pragma warning(disable : 4244) // possible loss of data on conversions #endif -class LLStopWatchControlsMixinCommon +class LL_COMMON_API LLStopWatchControlsMixinCommon { public: virtual ~LLStopWatchControlsMixinCommon() {} @@ -112,6 +112,7 @@ class LLStopWatchControlsMixin self_t& operator = (const self_t& other) { // don't do anything, derived class must implement logic + return *this; } // atomically stop this object while starting the other @@ -154,7 +155,7 @@ namespace LLTrace typedef S32 sum_t; }; - class Recording + class LL_COMMON_API Recording : public LLStopWatchControlsMixin { public: @@ -668,9 +669,9 @@ namespace LLTrace size_t mNumRecordedPeriods; }; - PeriodicRecording& get_frame_recording(); + LL_COMMON_API PeriodicRecording& get_frame_recording(); - class ExtendableRecording + class LL_COMMON_API ExtendableRecording : public LLStopWatchControlsMixin { public: @@ -694,7 +695,7 @@ namespace LLTrace Recording mPotentialRecording; }; - class ExtendablePeriodicRecording + class LL_COMMON_API ExtendablePeriodicRecording : public LLStopWatchControlsMixin { public: diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index e3eadfb0bd2..2322e60243e 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -91,11 +91,11 @@ namespace LLTrace }; - ThreadRecorder* get_thread_recorder(); - void set_thread_recorder(ThreadRecorder*); + LL_COMMON_API ThreadRecorder* get_thread_recorder(); + LL_COMMON_API void set_thread_recorder(ThreadRecorder*); - void set_master_thread_recorder(ThreadRecorder*); - ThreadRecorder* get_master_thread_recorder(); + LL_COMMON_API void set_master_thread_recorder(ThreadRecorder*); + LL_COMMON_API ThreadRecorder* get_master_thread_recorder(); } #endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 7164a6f2b84..17c16342130 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -49,6 +49,16 @@ // static LLMutex* LLUUID::mMutex = NULL; +// Defined here rather than as an inline constexpr in lluuid.h: LLUUID / +// LLTransactionID are exported (LL_COMMON_API), so these static members are +// dllimport in consumers and may not have an in-header definition. Both are +// constant-initialized (constexpr default ctors), so no static-init-order +// hazard -- they hold the all-zero UUID before any dynamic initialization runs. +// static +const LLUUID LLUUID::null; +// static +const LLTransactionID LLTransactionID::tnull; + /* diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index f5dc1b0c648..4d073cce21a 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -148,9 +148,12 @@ static_assert(std::is_trivially_copyable::value, "LLUUID must be trivial static_assert(std::is_trivially_move_assignable::value, "LLUUID must be trivial move"); static_assert(std::is_standard_layout::value, "LLUUID must be a standard layout type"); -// Defined as inline constexpr after the class definition because the static -// data member is of LLUUID type, which is incomplete inside the class body. -inline constexpr LLUUID LLUUID::null{}; +// LLUUID::null is defined out-of-line in lluuid.cpp, NOT as an inline constexpr +// variable here. LLUUID is exported (class LL_COMMON_API), which makes this +// static member dllimport in consumer modules, and a dllimport member may not +// have an in-header (inline) definition. So it is an ordinary exported constant +// defined once in the DLL. It is still constant-initialized (LLUUID has a +// constexpr default ctor), so there is no static-init-order hazard. typedef std::vector uuid_vec_t; typedef std::set uuid_set_t; @@ -185,7 +188,9 @@ class LL_COMMON_API LLTransactionID : public LLUUID LLAssetID makeAssetID(const LLUUID& session) const; }; -inline constexpr LLTransactionID LLTransactionID::tnull{}; +// As with LLUUID::null above: defined out-of-line in lluuid.cpp because an +// exported (dllimport-in-consumers) static member can't have an inline +// definition. // Canonical hash for LLUUID (also used by boost::container_hash via ADL). // Golden-ratio multiply with avalanche mixing: shift by 31 mixes the upper diff --git a/indra/llcommon/llwatchdog.h b/indra/llcommon/llwatchdog.h index f138fbccb05..467374eb5b4 100644 --- a/indra/llcommon/llwatchdog.h +++ b/indra/llcommon/llwatchdog.h @@ -37,7 +37,7 @@ // LLWatchdogEntry is the interface used by the tasks that // need to be watched. -class LLWatchdogEntry +class LL_COMMON_API LLWatchdogEntry { public: LLWatchdogEntry(const std::string &thread_name); @@ -59,7 +59,7 @@ class LLWatchdogEntry std::string mThreadName; }; -class LLWatchdogTimeout : public LLWatchdogEntry +class LL_COMMON_API LLWatchdogTimeout : public LLWatchdogEntry { public: LLWatchdogTimeout(const std::string& thread_name); @@ -83,12 +83,11 @@ class LLWatchdogTimeout : public LLWatchdogEntry }; class LLWatchdogTimerThread; // Defined in the cpp -class LLWatchdog : public LLSimpleton +class LL_COMMON_API LLWatchdog : public LLSingleton { -public: - LLWatchdog(); + LLSINGLETON(LLWatchdog); ~LLWatchdog(); - +public: // Add an entry to the watchdog. void add(LLWatchdogEntry* e); void remove(LLWatchdogEntry* e); diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h index 1ff373bca87..b948adee127 100644 --- a/indra/llcommon/llwin32headers.h +++ b/indra/llcommon/llwin32headers.h @@ -30,7 +30,7 @@ #ifdef LL_WINDOWS #include // Does not include winsock.h because WIN32_LEAN_AND_MEAN is defined #include // Requires windows.h -#include +#include #endif #endif diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h index db4c7af0ec4..4d240f37aa3 100644 --- a/indra/llcommon/lockstatic.h +++ b/indra/llcommon/lockstatic.h @@ -14,10 +14,32 @@ #define LL_LOCKSTATIC_H #include // std::unique_lock +#include // typeid +#include // size_t +#include "llpreprocessor.h" // LL_COMMON_API namespace llthread { +// Return THE canonical instance of the Static identified by 'name' +// (typeid(Static).name()), creating it once via factory() on first request. +// Defined in llthread.cpp -- a single translation unit -- so every module in a +// multi-DLL build shares one instance instead of each getting its own +// function-local static copy. Keyed by the mangled NAME STRING (not type_info +// identity), which is stable across modules even under -fvisibility=hidden. +LL_COMMON_API void* getCanonicalStatic(const char* name, void* (*factory)()); + +// DLL-safe thread-local slot store. A thread_local variable cannot carry a dll +// interface on MSVC (C2492), so it cannot simply be exported to share one +// instance across modules. Instead the underlying thread_local array lives in a +// single module (llcommon) and is reached through these exported accessors, so +// every module shares one per-thread value per slot. allocThreadLocalSlot() +// assigns a stable slot index per 'name' (pass typeid(T).name()), consistent +// across modules; the index is then used with get/setThreadLocalSlot(). +LL_COMMON_API size_t allocThreadLocalSlot(const char* name); +LL_COMMON_API void* getThreadLocalSlot(size_t slot); +LL_COMMON_API void setThreadLocalSlot(size_t slot, void* value); + // Instantiate this template to obtain a pointer to the canonical static // instance of Static while holding a lock on that instance. Use of // Static::mMutex presumes that Static declares some suitable mMutex. @@ -46,25 +68,24 @@ class LockStatic private: Static* getStatic() { - // Static::mMutex must be function-local static rather than class- - // static. Some of our consumers must function properly (therefore - // lock properly) even when the containing module's static variables - // have not yet been runtime-initialized. A mutex requires - // construction. A static class member might not yet have been - // constructed. - // - // We could store a dumb mutex_t*, notice when it's NULL and allocate a - // heap mutex -- but that's vulnerable to race conditions. And we can't - // defend the dumb pointer with another mutex. - // - // We could store a std::atomic -- but a default-constructed - // std::atomic does not contain a valid T, even a default-constructed - // T! Which means std::atomic, too, requires runtime initialization. + // One canonical Static per process, shared across module (DLL) + // boundaries: getCanonicalStatic() lives in a single translation unit, + // so every module resolves the SAME instance. This matters because a + // plain `static Static sData;` is duplicated once per module in a + // multi-DLL build -- each DLL would get its own copy of the tracked + // data, which (e.g. for LLInstanceTracker / LLTrace) silently splits + // registrations across modules. // - // But a function-local static is guaranteed to be initialized exactly - // once: the first time control reaches that declaration. - static Static sData; - return &sData; + // The cached pointer below is itself a function-local static, so it + // retains the original guarantee that matters: it is constructed + // exactly once, on first reach -- even when the containing module's + // other static variables have not yet been runtime-initialized -- and + // the underlying Static (with its mMutex) is created lazily at that + // same point. It simply now converges to the one canonical instance. + static Static* sData = static_cast( + getCanonicalStatic(typeid(Static).name(), + []() -> void* { return new Static(); })); + return sData; } }; diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index d7b80e2545f..2a93d1946c5 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -478,7 +478,6 @@ namespace tut } } // namespace tut -/***************************************************************************** -* Link dependencies -*****************************************************************************/ -#include "llsdutil.cpp" +// (llsdutil symbols formerly pulled in via #include "llsdutil.cpp" now come from +// the linked llcommon library -- including the .cpp here double-defines them and +// clashes with their dllimport declarations when llcommon is built shared.) diff --git a/indra/llcommon/tests/lluuid_test.cpp b/indra/llcommon/tests/lluuid_test.cpp index d22101b8ae4..2525fad1b18 100644 --- a/indra/llcommon/tests/lluuid_test.cpp +++ b/indra/llcommon/tests/lluuid_test.cpp @@ -38,8 +38,9 @@ namespace tut // Compile-time verification that LLUUID is constexpr-constructible. static_assert(LLUUID{}.mData[0] == 0, "default LLUUID is zero-initialised at compile time"); - static_assert(LLUUID::null.mData[0] == 0, "LLUUID::null is a compile-time constant"); - static_assert(LLTransactionID::tnull.mData[0] == 0, "LLTransactionID::tnull is a compile-time constant"); + // LLUUID::null / LLTransactionID::tnull are exported out-of-line constants + // (dllimport in consumers), so they are no longer constexpr. Their all-zero + // value is verified at runtime in test<1> instead. constexpr U8 kConstexprBytes[UUID_BYTES] = { 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, @@ -63,6 +64,10 @@ namespace tut ensure("default-constructed isNull", id.isNull()); ensure("default-constructed !notNull", !id.notNull()); ensure("default-constructed == LLUUID::null", id == LLUUID::null); + // null / tnull are the all-zero UUID (verified at runtime since they are + // exported out-of-line constants, no longer constexpr). + ensure("LLUUID::null isNull", LLUUID::null.isNull()); + ensure("LLTransactionID::tnull isNull", LLTransactionID::tnull.isNull()); for (int i = 0; i < UUID_BYTES; ++i) { ensure_equals("default byte zero", (int)id.mData[i], 0); diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index ac4f415f3ed..a9046a86bfa 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -24,7 +24,7 @@ namespace LL { - class ThreadPoolBase: public LLInstanceTracker + class LL_COMMON_API ThreadPoolBase: public LLInstanceTracker { private: using super = LLInstanceTracker; @@ -101,7 +101,7 @@ namespace LL * Specialize with WorkQueue or, for timestamped tasks, WorkSchedule */ template - struct ThreadPoolUsing: public ThreadPoolBase + struct LL_COMMON_API ThreadPoolUsing : public ThreadPoolBase { using queue_t = QUEUE; diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index 69f3286c1b9..13170035092 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -35,7 +35,7 @@ namespace LL /** * A typical WorkQueue has a string name that can be used to find it. */ - class WorkQueueBase: public LLInstanceTracker + class LL_COMMON_API WorkQueueBase : public LLInstanceTracker { private: using super = LLInstanceTracker; @@ -213,7 +213,7 @@ namespace LL /***************************************************************************** * WorkQueue: no timestamped task support *****************************************************************************/ - class WorkQueue: public LLInstanceTrackerSubclass + class LL_COMMON_API WorkQueue : public LLInstanceTrackerSubclass { private: using super = LLInstanceTrackerSubclass; @@ -276,12 +276,16 @@ namespace LL /***************************************************************************** * WorkSchedule: add support for timestamped tasks *****************************************************************************/ - class WorkSchedule: public LLInstanceTrackerSubclass + class LL_COMMON_API WorkSchedule : public LLInstanceTrackerSubclass { private: using super = LLInstanceTrackerSubclass; using Queue = ThreadSafeSchedule; // helper for postEvery() + // NOT LL_COMMON_API: BackJack is instantiated with caller-local types + // (the lambda passed to postEvery()), so each consumer must emit its own + // instantiation -- tagging it makes consumers try to import an + // instantiation the DLL can never contain. template class BackJack; diff --git a/indra/llmessage/llpumpio.h b/indra/llmessage/llpumpio.h index 54820330fd1..22bcb523a90 100644 --- a/indra/llmessage/llpumpio.h +++ b/indra/llmessage/llpumpio.h @@ -34,6 +34,7 @@ #include #endif +#include "llwin32headers.h" #include "apr_poll.h" #include "apr_pools.h" #include "llbuffer.h" diff --git a/indra/llmessage/tests/io_test.cpp b/indra/llmessage/tests/io_test.cpp index f77402065a7..68a5c100602 100644 --- a/indra/llmessage/tests/io_test.cpp +++ b/indra/llmessage/tests/io_test.cpp @@ -31,6 +31,7 @@ #include +#include "llwin32headers.h" #include "apr_pools.h" #include "llbuffer.h" diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt index 9ea8c19a32f..11a165cd145 100644 --- a/indra/llplugin/slplugin/CMakeLists.txt +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -44,8 +44,6 @@ target_link_libraries(SLPlugin ll::pluginlibraries ) -target_precompile_headers(SLPlugin REUSE_FROM llprecompiled_exe) - if(WINDOWS) set_target_properties(SLPlugin PROPERTIES diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp index 7e84249082e..dbeea1a1f5e 100644 --- a/indra/llprimitive/tests/llgltfmaterial_test.cpp +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -29,7 +29,6 @@ #include #include "../llgltfmaterial.h" -#include "lluuid.cpp" // Import & define single-header gltf import/export lib #define TINYGLTF_IMPLEMENTATION diff --git a/indra/llprimitive/tests/llmaterial_test.cpp b/indra/llprimitive/tests/llmaterial_test.cpp index c24492e5f67..dfc44840ff9 100644 --- a/indra/llprimitive/tests/llmaterial_test.cpp +++ b/indra/llprimitive/tests/llmaterial_test.cpp @@ -22,7 +22,6 @@ #include "lltut.h" #include "../llmaterial.h" -#include "lluuid.cpp" namespace tut { diff --git a/indra/llprimitive/tests/llmaterialid_test.cpp b/indra/llprimitive/tests/llmaterialid_test.cpp index 04683fff8c1..89c5883287d 100644 --- a/indra/llprimitive/tests/llmaterialid_test.cpp +++ b/indra/llprimitive/tests/llmaterialid_test.cpp @@ -24,7 +24,6 @@ #include #include "../llmaterialid.h" -#include "lluuid.cpp" namespace tut { diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0f320a53f31..9b11a63fd81 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1024,7 +1024,7 @@ bool LLAppViewer::init() // Initialize event recorder LLViewerEventRecorder::createInstance(); - LLWatchdog::createInstance(); + LLWatchdog::getInstance(); // Initialize watchdog timer // // Initialize the window diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 616a7202bd4..3f05e3b873c 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -426,7 +426,6 @@ extern LLFrameTimer gRestoreGLTimer; extern bool gRestoreGL; extern bool gUseWireframe; -extern LLMemoryInfo gSysMemory; extern U64Bytes gMemoryAllocated; extern std::string gLastVersionChannel; diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 3392669f9a4..419e2af94f9 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -69,7 +69,6 @@ #include "lldxhardware.h" #endif -extern LLMemoryInfo gSysMemory; extern U32 gPacketsIn; ///---------------------------------------------------------------------------- From 6d170d7534567cf1cb561f47c0b872c40ccb6343 Mon Sep 17 00:00:00 2001 From: Rye Date: Thu, 25 Jun 2026 11:11:11 -0400 Subject: [PATCH 8/9] Remove remaining LLFastTimer/LLBlockTimer usage --- indra/llappearance/llavatarappearance.cpp | 2 +- .../llappappearanceutility.cpp | 163 +- .../llappappearanceutility.h | 3 - .../llappearanceutility/llbakingtexlayer.cpp | 6 +- .../llappearanceutility/llprocesstexture.cpp | 3 +- indra/llcommon/llfasttimer.cpp | 4 +- indra/llfilesystem/llfilesystem.cpp | 2 - indra/llmessage/lltemplatemessagereader.cpp | 4 +- indra/llui/llfolderview.cpp | 4 +- indra/llui/llfolderviewitem.cpp | 9 +- indra/llui/llkeywords.cpp | 3 +- indra/llui/llpanel.cpp | 20 +- indra/llui/lluistring.cpp | 9 +- indra/llui/llxuiparser.cpp | 5 +- indra/llwindow/llwindowwin32.cpp | 13 - indra/newview/CMakeLists.txt | 2 - indra/newview/llagent.cpp | 2 + indra/newview/llagentcamera.cpp | 4 +- indra/newview/llappviewer.cpp | 69 +- indra/newview/llchathistory.cpp | 4 +- indra/newview/lldebugview.cpp | 4 - indra/newview/lldebugview.h | 2 - .../lldonotdisturbnotificationstorage.cpp | 4 +- indra/newview/lldrawable.cpp | 1 + indra/newview/lldrawpoolavatar.cpp | 2 - indra/newview/lldrawpoolsimple.cpp | 9 - indra/newview/lldrawpoolterrain.cpp | 2 - indra/newview/lldrawpooltree.cpp | 4 +- indra/newview/llenvironment.cpp | 2 - indra/newview/llfasttimerview.cpp | 1667 ----------------- indra/newview/llfasttimerview.h | 151 -- indra/newview/llfilteredwearablelist.cpp | 4 +- indra/newview/llfloaterimsessiontab.cpp | 3 +- indra/newview/llfloaterlagmeter.cpp | 4 +- indra/newview/llfolderviewmodelinventory.cpp | 3 +- indra/newview/llgesturemgr.cpp | 2 + indra/newview/llhudmanager.cpp | 4 +- indra/newview/llhudobject.cpp | 4 +- .../llinventorymodelbackgroundfetch.cpp | 6 +- indra/newview/llsceneview.cpp | 5 - indra/newview/llstartup.cpp | 1 - indra/newview/llviewerfloaterreg.cpp | 3 - indra/newview/llviewermedia.cpp | 18 +- indra/newview/llviewermenu.cpp | 8 - indra/newview/llviewerobjectlist.cpp | 6 +- indra/newview/llviewerpartsim.cpp | 6 +- indra/newview/llviewerregion.cpp | 6 +- indra/newview/llviewerstats.cpp | 4 - indra/newview/llviewerstats.h | 15 +- indra/newview/llviewerwindow.cpp | 11 +- indra/newview/llvlmanager.cpp | 2 + indra/newview/llvograss.cpp | 4 +- indra/newview/pipeline.cpp | 62 +- indra/newview/pipeline.h | 25 - indra/newview/rlveffects.cpp | 4 +- .../skins/default/xui/da/menu_viewer.xml | 1 - .../default/xui/de/floater_fast_timers.xml | 21 - .../skins/default/xui/de/menu_viewer.xml | 1 - .../default/xui/en/floater_fast_timers.xml | 109 -- .../skins/default/xui/en/menu_viewer.xml | 12 - .../default/xui/es/floater_fast_timers.xml | 21 - .../skins/default/xui/es/menu_viewer.xml | 1 - .../default/xui/fr/floater_fast_timers.xml | 21 - .../skins/default/xui/fr/menu_viewer.xml | 1 - .../default/xui/it/floater_fast_timers.xml | 21 - .../skins/default/xui/it/menu_viewer.xml | 1 - .../default/xui/ja/floater_fast_timers.xml | 21 - .../skins/default/xui/ja/menu_viewer.xml | 1 - .../default/xui/pl/floater_fast_timers.xml | 19 - .../skins/default/xui/pl/menu_viewer.xml | 1 - .../default/xui/pt/floater_fast_timers.xml | 21 - .../skins/default/xui/pt/menu_viewer.xml | 1 - .../default/xui/ru/floater_fast_timers.xml | 21 - .../skins/default/xui/ru/menu_viewer.xml | 1 - .../default/xui/tr/floater_fast_timers.xml | 21 - .../skins/default/xui/tr/menu_viewer.xml | 1 - .../default/xui/zh/floater_fast_timers.xml | 21 - .../skins/default/xui/zh/menu_viewer.xml | 1 - 78 files changed, 79 insertions(+), 2650 deletions(-) delete mode 100644 indra/newview/llfasttimerview.cpp delete mode 100644 indra/newview/llfasttimerview.h delete mode 100644 indra/newview/skins/default/xui/de/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/en/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/es/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/fr/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/ja/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/pl/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/pt/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/ru/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/tr/floater_fast_timers.xml delete mode 100644 indra/newview/skins/default/xui/zh/floater_fast_timers.xml diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 97f4ccef5ab..53478b68ff5 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -884,7 +884,7 @@ void LLAvatarAppearance::buildCharacter() bool LLAvatarAppearance::loadAvatar() { -// LL_RECORD_BLOCK_TIME(FTM_LOAD_AVATAR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // avatar_skeleton.xml if( !buildSkeleton(sAvatarSkeletonInfo) ) diff --git a/indra/llappearanceutility/llappappearanceutility.cpp b/indra/llappearanceutility/llappappearanceutility.cpp index 2fa0b0b32d5..ce9c97ea015 100644 --- a/indra/llappearanceutility/llappappearanceutility.cpp +++ b/indra/llappearanceutility/llappappearanceutility.cpp @@ -34,7 +34,6 @@ #include "llapr.h" #include "llerrorcontrol.h" -#include "llfasttimer.h" #include "llgl.h" #include "llmd5.h" #include "llsd.h" @@ -44,7 +43,6 @@ #include "lltreeiterators.h" #include "v3color.h" #include "llwindow.h" -#include "lltrace.h" // appearance includes #include "llavatarappearance.h" @@ -208,7 +206,6 @@ LLAppAppearanceUtility::LLAppAppearanceUtility(int argc, char** argv) : mOutput(nullptr), mAppName(argv[0]), mDebugMode(false), - mTreeMapThreshold(1), mBakeTextureSize(512) { } @@ -301,12 +298,6 @@ void LLAppAppearanceUtility::parseArguments() case 'd': mDebugMode = true; break; - case 'm': - mTreeMapFilename.assign(opt_arg); - break; - case 's': - mTreeMapThreshold = atoi(opt_arg); - break; default: usage(std::cerr); throw LLAppException(RV_BAD_ARGUMENTS, "Unknown option."); @@ -459,7 +450,6 @@ bool LLAppAppearanceUtility::init() LLError::initForApplication(".", ".", true); if (mDebugMode) { - mRecording.start(); LLError::setDefaultLevel(LLError::LEVEL_DEBUG); } else @@ -479,7 +469,7 @@ bool LLAppAppearanceUtility::init() const bool SKIP_ANALYZE_ALPHA=true; LLTranslationBridge::ptr_t trans = std::make_shared(); - LLWearableType::createInstance(trans); + LLWearableType::initParamSingleton(trans); // *TODO: Create a texture bridge? LLAvatarAppearance::initClass(); @@ -492,91 +482,6 @@ bool LLAppAppearanceUtility::init() return true; } - -void add_cluster(LLTrace::Recording& recording, std::ostream& tree, LLTrace::BlockTimerStatHandle& node, std::vector < S32 > & clusters, F64Milliseconds threshold) -{ - LLMD5 hash; - hash.update((const unsigned char*)node.getName().c_str(), node.getName().size()); - hash.finalize(); - char buf[33]; - hash.hex_digest(buf); - buf[6] = 0; - LLColor3 color(buf); - if (color.brightness() < 0.25f) - { - color.normalize(); - } - std::ostringstream color_str; - color_str << "#" << std::hex << std::setfill('0') << std::setw(2) - << (S32) F32_to_U8(color.mV[0], 0.0f, 1.0f) - << (S32) F32_to_U8(color.mV[1], 0.0f, 1.0f) - << (S32) F32_to_U8(color.mV[2], 0.0f, 1.0f); - - std::vector::iterator iter = clusters.begin(); - std::vector::iterator end = clusters.end(); - std::ostringstream padding; - for(; iter != end; ++iter) - { - padding << " "; - } - - std::ostringstream node_id; - bool first = true; - iter = clusters.begin(); - for(; iter != end; ++iter) - { - if (!first) - { - node_id << "_"; - } - first = false; - node_id << (*iter); - } - - if (node.getChildren().size() == 0) - { - F64Milliseconds leaf_time_ms(recording.getSum(node)); - if (leaf_time_ms > threshold) - { - tree << padding.str() << "n" << node_id.str() << " [" - << "label=\"" << node.getName() << " (" << leaf_time_ms.value() << ")\" " - << "fillcolor=\"" << color_str.str() << "\" " - << "area=" << leaf_time_ms.value() / 10 << "]" << std::endl; - } - } - else - { - if (clusters.size()) - { - tree << padding.str() << "subgraph cluster" << node_id.str(); - tree << " {" << std::endl; - } - - S32Milliseconds node_area(recording.getSum(node)); - std::vector::iterator child_iter = node.getChildren().begin(); - for (S32 num=0; child_iter != node.getChildren().end(); ++child_iter, ++num) - { - clusters.push_back(num); - add_cluster(recording, tree, *(*child_iter), clusters, threshold); - clusters.pop_back(); - node_area -= recording.getSum(*(*child_iter)); - } - - S32Milliseconds node_time_ms(node_area); - if (node_time_ms > threshold) - { - tree << padding.str() << "n" << node_id.str() << " [" - << "label=\"" << node.getName() << " (" << node_time_ms.value() << ")\" " - << "fillcolor=\"" << color_str.str() << "\" " - << "area=" << node_time_ms.value() / 10 << "]" << std::endl; - } - if (clusters.size()) - { - tree << padding.str() << "}" << std::endl;; - } - } -} - bool LLAppAppearanceUtility::cleanup() { if (mProcess) @@ -584,72 +489,6 @@ bool LLAppAppearanceUtility::cleanup() mProcess->cleanup(); } - // Spam fast timer information in debug mode. - if (mDebugMode) - { - mRecording.stop(); - LLTrace::BlockTimer::processTimes(); - - S32Milliseconds max_time_ms(0); - for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(LLTrace::BlockTimer::getRootTimeBlock()); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - LLTrace::BlockTimerStatHandle* idp = (*it); - // Skip near-zero time leafs. - S32Milliseconds leaf_time_ms(mRecording.getSum(*idp)); - if (leaf_time_ms > max_time_ms) max_time_ms = leaf_time_ms; - if ((S32Milliseconds)0 == leaf_time_ms) continue; - - std::vector< LLTrace::BlockTimerStatHandle* > parents; - LLTrace::BlockTimerStatHandle* parentp = idp->getParent(); - while (parentp) - { - parents.push_back(parentp); - if (parentp->getParent() == parentp) break; - parentp = parentp->getParent(); - } - - std::ostringstream fullname; - bool is_first = true; - for ( std::vector< LLTrace::BlockTimerStatHandle* >::reverse_iterator iter = parents.rbegin(); - iter != parents.rend(); ++iter) - { - // Skip root - if (is_first) - { - is_first = false; - continue; - } - LLTrace::BlockTimerStatHandle* parent_idp = (*iter); - U32Milliseconds time_ms(mRecording.getSum(parent_idp->selfTime())); - fullname << parent_idp->getName() << " "; - fullname << "("; - if (time_ms > (U32Milliseconds)0) - { - fullname << time_ms.value() << " ms, "; - } - fullname << mRecording.getSum(parent_idp->callCount()) << " call)-> "; - } - LL_DEBUGS() << fullname.str() << LL_ENDL; - } - if (!mTreeMapFilename.empty()) - { - std::ofstream tree(mTreeMapFilename.c_str()); - tree << "graph G {" << std::endl; - tree << " node[style=filled]" << std::endl; - - LLTrace::BlockTimerStatHandle& root = LLTrace::BlockTimer::getRootTimeBlock(); - std::vector clusters; - add_cluster(mRecording, tree, root, clusters, (((F32) mTreeMapThreshold / 100.f) * max_time_ms) ); - - tree << "}" << std::endl; - - LL_DEBUGS() << "To generate a treemap of LLFrameTimer results, run:" << LL_ENDL; - LL_DEBUGS() << "patchwork " << mTreeMapFilename << " -Tpng > rendered.png" << LL_ENDL; - } - } - LLAvatarAppearance::cleanupClass(); LLImageGL::cleanupClass(); LLImage::cleanupClass(); diff --git a/indra/llappearanceutility/llappappearanceutility.h b/indra/llappearanceutility/llappappearanceutility.h index 80d1e8b1bf6..de67f100774 100644 --- a/indra/llappearanceutility/llappappearanceutility.h +++ b/indra/llappearanceutility/llappappearanceutility.h @@ -98,9 +98,6 @@ class LLAppAppearanceUtility : public LLApp LLUUID mAgentID; S32 mBakeTextureSize; bool mDebugMode; - LLTrace::Recording mRecording; - S32 mTreeMapThreshold; - std::string mTreeMapFilename; }; diff --git a/indra/llappearanceutility/llbakingtexlayer.cpp b/indra/llappearanceutility/llbakingtexlayer.cpp index 3427331a964..ae285060360 100644 --- a/indra/llappearanceutility/llbakingtexlayer.cpp +++ b/indra/llappearanceutility/llbakingtexlayer.cpp @@ -66,11 +66,9 @@ bool LLBakingTexLayerSetBuffer::render() return result; } -static LLFastTimer::DeclareTimer FTM_MID_RENDER("midRenderTexLayerSet"); -static LLFastTimer::DeclareTimer FTM_CREATE_J2C("Encode J2C image."); void LLBakingTexLayerSetBuffer::midRenderTexLayerSet(bool success) { - LL_RECORD_BLOCK_TIME(FTM_MID_RENDER); + LL_PROFILE_ZONE_SCOPED; if (!mTexLayerSet->isVisible()) { // Should have used IMG_INVISIBLE during hash id generation? @@ -124,7 +122,7 @@ void LLBakingTexLayerSetBuffer::midRenderTexLayerSet(bool success) } { - LL_RECORD_BLOCK_TIME(FTM_CREATE_J2C); + LL_PROFILE_ZONE_NAMED("Encode J2C image."); LL_DEBUGS() << "Creating J2C..." << LL_ENDL; mCompressedImage = new LLImageJ2C; const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) diff --git a/indra/llappearanceutility/llprocesstexture.cpp b/indra/llappearanceutility/llprocesstexture.cpp index 527a6822f2f..f12c49f35bc 100644 --- a/indra/llappearanceutility/llprocesstexture.cpp +++ b/indra/llappearanceutility/llprocesstexture.cpp @@ -68,12 +68,11 @@ void LLProcessTexture::cleanup() delete mWindow; } -static LLFastTimer::DeclareTimer FTM_CREATE_TEXTURE_FROM_STREAM("Create texture from stream."); static LLPointer create_texture_from_stream(std::istream& input, S32 texture_size, const LLUUID& id) { - LL_RECORD_BLOCK_TIME(FTM_CREATE_TEXTURE_FROM_STREAM); + LL_PROFILE_ZONE_SCOPED; // Read compressed j2c texture data from the input stream. U8* buffer = (U8*) ll_aligned_malloc_16(texture_size); input.read((char*) buffer, texture_size); diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index c5a7a0e56b5..430ffa11132 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -290,14 +290,12 @@ void BlockTimer::updateTimes() } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times"); - // not thread safe, so only call on main thread //static void BlockTimer::processTimes() { #if LL_TRACE_ENABLED - LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); + LL_PROFILE_ZONE_SCOPED; get_clock_count(); // good place to calculate clock frequency // set up initial tree diff --git a/indra/llfilesystem/llfilesystem.cpp b/indra/llfilesystem/llfilesystem.cpp index 9c87ac7dcc4..21691cef395 100644 --- a/indra/llfilesystem/llfilesystem.cpp +++ b/indra/llfilesystem/llfilesystem.cpp @@ -39,8 +39,6 @@ constexpr S32 LLFileSystem::WRITE = 0x00000002; constexpr S32 LLFileSystem::READ_WRITE = 0x00000003; // LLFileSystem::READ & LLFileSystem::WRITE constexpr S32 LLFileSystem::APPEND = 0x00000006; // 0x00000004 & LLFileSystem::WRITE -static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait"); - LLFileSystem::LLFileSystem(const LLUUID& file_id, const LLAssetType::EType file_type, S32 mode) { mFileType = file_type; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 012f6bfea01..79182eef6ff 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -525,12 +525,10 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3 gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET); } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages"); - // decode a given message bool LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender, bool custom ) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; llassert( mReceiveSize >= 0 ); llassert( mCurrentRMessageTemplate); diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index aa31b64b8a1..af9f771e0ba 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -1717,14 +1717,12 @@ void LLFolderView::setShowSingleSelection(bool show) } } -static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory"); - // Main idle routine void LLFolderView::update() { // If this is associated with the user's inventory, don't do anything // until that inventory is loaded up. - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated if (getFolderViewModel() == NULL) diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp index 0bf4a5fa8d4..1eecdffab92 100644 --- a/indra/llui/llfolderviewitem.cpp +++ b/indra/llui/llfolderviewitem.cpp @@ -1320,8 +1320,6 @@ void LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder) } } -static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange"); - // Make everything right and in the right place ready for drawing (CHUI-849) // * Sort everything correctly if necessary // * Turn widgets visible/invisible according to their model filtering state @@ -1331,6 +1329,8 @@ static LLTrace::BlockTimerStatHandle FTM_ARRANGE("Arrange"); // * Makes sure that this view and its children are the right size S32 LLFolderViewFolder::arrange( S32* width, S32* height ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + // Sort before laying out contents // Note that we sort from the root (CHUI-849) if (mAreChildrenInited) @@ -1338,8 +1338,6 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) getRoot()->getFolderViewModel()->sort(this); } - LL_RECORD_BLOCK_TIME(FTM_ARRANGE); - // evaluate mHasVisibleChildren mHasVisibleChildren = false; if (mAreChildrenInited && getViewModelItem()->descendantsPassedFilter()) @@ -1368,13 +1366,12 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height ) mHasVisibleChildren = found; } + if (!mIsFolderComplete && mAreChildrenInited) { mIsFolderComplete = getFolderViewModel()->isFolderComplete(this); } - - // calculate height as a single item (without any children), and reshapes rectangle to match LLFolderViewItem::arrange( width, height ); diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index a390b2a348c..37526ee1eae 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -494,7 +494,6 @@ bool LLKeywords::WStringMapIndex::operator<(const LLKeywords::WStringMapIndex &o return result; } -LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring"); constexpr size_t AVERAGE_SEGMENT_LENGTH = 8; void LLKeywords::collectSegmentOps(segment_ops_t& ops, const LLWString& wtext, bool disable_syntax_highlighting) const @@ -894,7 +893,7 @@ void LLKeywords::applySegmentOps(std::vector *seg_list, // create a list of color segments. void LLKeywords::findSegments(std::vector* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style) { - LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if( wtext.empty() ) { diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 3059f6c6d7e..a9bb27007f7 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -360,10 +360,10 @@ void LLPanel::setBorderVisible(bool b) } } -LLTrace::BlockTimerStatHandle FTM_PANEL_CONSTRUCTION("Panel Construction"); - LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_node) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + std::string name("panel"); node->getAttributeString("name", name); @@ -372,8 +372,7 @@ LLView* LLPanel::fromXML(LLXMLNodePtr node, LLView* parent, LLXMLNodePtr output_ LLPanel* panelp = NULL; - { LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); - + { if(!class_attr.empty()) { panelp = LLRegisterPanelClass::instance().createPanelClass(class_attr); @@ -476,16 +475,11 @@ void LLPanel::initFromParams(const LLPanel::Params& p) setAcceptsBadge(p.accepts_badge); } -static LLTrace::BlockTimerStatHandle FTM_PANEL_SETUP("Panel Setup"); -static LLTrace::BlockTimerStatHandle FTM_EXTERNAL_PANEL_LOAD("Load Extern Panel Reference"); -static LLTrace::BlockTimerStatHandle FTM_PANEL_POSTBUILD("Panel PostBuild"); - bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node, const LLPanel::Params& default_params) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; Params params(default_params); { - LL_RECORD_BLOCK_TIME(FTM_PANEL_SETUP); - LLXMLNodePtr referenced_xml; std::string xml_filename = mXMLFilename; @@ -514,7 +508,7 @@ bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu LLUICtrlFactory::instance().pushFileName(xml_filename); - LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_PANEL_LOAD); + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("Load Extern Panel Reference"); if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) { LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; @@ -545,7 +539,7 @@ bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu params.from_xui = true; applyXUILayout(params, parent); { - LL_RECORD_BLOCK_TIME(FTM_PANEL_CONSTRUCTION); + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("Panel Construction"); initFromParams(params); } @@ -562,7 +556,7 @@ bool LLPanel::initPanelXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr outpu } { - LL_RECORD_BLOCK_TIME(FTM_PANEL_POSTBUILD); + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("Panel PostBuild"); postBuild(); } } diff --git a/indra/llui/lluistring.cpp b/indra/llui/lluistring.cpp index ab6de16639b..0d9c66d4cf7 100644 --- a/indra/llui/lluistring.cpp +++ b/indra/llui/lluistring.cpp @@ -31,9 +31,6 @@ #include "llsd.h" #include "lltrans.h" -LLTrace::BlockTimerStatHandle FTM_UI_STRING("UI String"); - - LLUIString::LLUIString(const std::string& instring, const LLStringUtil::format_map_t& args) : mOrig(instring), mArgs(new LLStringUtil::format_map_t(args)) @@ -62,7 +59,7 @@ void LLUIString::setArgList(const LLStringUtil::format_map_t& args) void LLUIString::setArgs(const LLSD& sd) { - LL_RECORD_BLOCK_TIME(FTM_UI_STRING); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (!sd.isMap()) return; for(LLSD::map_const_iterator sd_it = sd.beginMap(); @@ -123,9 +120,9 @@ void LLUIString::dirty() void LLUIString::updateResult() const { - mNeedsResult = false; + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; - LL_RECORD_BLOCK_TIME(FTM_UI_STRING); + mNeedsResult = false; // optimize for empty strings (don't attempt string replacement) if (mOrig.empty()) diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp index a818a5fec13..035c9450b09 100644 --- a/indra/llui/llxuiparser.cpp +++ b/indra/llui/llxuiparser.cpp @@ -672,12 +672,11 @@ LLXUIParser::LLXUIParser() } } -static LLTrace::BlockTimerStatHandle FTM_PARSE_XUI("XUI Parsing"); const LLXMLNodePtr DUMMY_NODE = new LLXMLNode(); void LLXUIParser::readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, const std::string& filename, bool silent) { - LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (node.isNull()) { @@ -1389,7 +1388,7 @@ LLSimpleXUIParser::~LLSimpleXUIParser() bool LLSimpleXUIParser::readXUI(const std::string& filename, LLInitParam::BaseBlock& block, bool silent) { - LL_RECORD_BLOCK_TIME(FTM_PARSE_XUI); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; mParser = XML_ParserCreate(NULL); XML_SetUserData(mParser, this); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 5fa1708d476..4abff070dd1 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2308,9 +2308,6 @@ void LLWindowWin32::gatherInput() updateCursor(); } -static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); -static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); - #define WINDOW_IMP_POST(x) window_imp->post([=]() { x; }) LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) @@ -2709,7 +2706,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN"); { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { sHandleLeftMouseUp = true; @@ -2757,7 +2753,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { window_imp->postMouseButtonEvent([=]() { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); if (!sHandleLeftMouseUp) { sHandleLeftMouseUp = true; @@ -2779,7 +2774,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN"); { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->post([=]() { if (LLWinImm::isAvailable() && window_imp->mPreeditor) @@ -2802,7 +2796,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP"); { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { MASK mask = gKeyboard->currentMask(true); @@ -2817,7 +2810,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { if (LLWinImm::isAvailable() && window_imp->mPreeditor) @@ -2836,7 +2828,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP"); { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { MASK mask = gKeyboard->currentMask(true); @@ -2850,7 +2841,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN"); window_imp->postMouseButtonEvent([=]() { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); S32 button = GET_XBUTTON_WPARAM(w_param); if (LLWinImm::isAvailable() && window_imp->mPreeditor) { @@ -2870,9 +2860,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP"); window_imp->postMouseButtonEvent([=]() { - - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - S32 button = GET_XBUTTON_WPARAM(w_param); MASK mask = gKeyboard->currentMask(true); // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d5746890610..662af9a61b9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -312,7 +312,6 @@ set(viewer_SOURCE_FILES llexperiencelog.cpp llexternaleditor.cpp llface.cpp - llfasttimerview.cpp llfavoritesbar.cpp llfeaturemanager.cpp llfetchedgltfmaterial.cpp @@ -1081,7 +1080,6 @@ set(viewer_HEADER_FILES llexperiencelog.h llexternaleditor.h llface.h - llfasttimerview.h llfavoritesbar.h llfeaturemanager.h llfetchedgltfmaterial.h diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d7f1344a8db..a0e2434c109 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2131,6 +2131,8 @@ void LLAgent::propagate(const F32 dt) //----------------------------------------------------------------------------- void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; + static LLCachedControl hint_timeout(gSavedSettings, "NotMovingHintTimeout"); if (mMoveTimer.getStarted() && mMoveTimer.getElapsedTimeF32() > hint_timeout) { diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 6bfba67e565..41f349b148e 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -1245,8 +1245,6 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y) } } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_CAMERA("Camera"); - extern bool gCubeSnapshot; //----------------------------------------------------------------------------- @@ -1254,7 +1252,7 @@ extern bool gCubeSnapshot; //----------------------------------------------------------------------------- void LLAgentCamera::updateCamera() { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_CAMERA); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER; if (gCubeSnapshot) { return; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 9b11a63fd81..20ff45d332f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -92,7 +92,6 @@ #include "lltoast.h" #include "llsdutil_math.h" #include "lllocationhistory.h" -#include "llfasttimerview.h" #include "llvector4a.h" #include "llviewermenufile.h" #include "llvoicechannel.h" @@ -1334,8 +1333,6 @@ void LLAppViewer::initMaxHeapSize() // externally visible timers -LLTrace::BlockTimerStatHandle FTM_FRAME("Frame"); - bool LLAppViewer::frame() { bool ret = false; @@ -1378,8 +1375,8 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { - LL_RECORD_BLOCK_TIME(FTM_FRAME); - LL_PROFILE_GPU_ZONE("Frame"); + LL_PROFILE_ZONE_SCOPED; + LL_PROFILE_GPU_ZONE("doFrame"); resumeMainloopTimeout("Main:doFrameStart"); @@ -1409,11 +1406,6 @@ bool LLAppViewer::doFrame() LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); // perf stats { LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); - if (LLFloaterReg::instanceVisible("block_timers")) - { - LLTrace::BlockTimer::processTimes(); - } - LLTrace::get_frame_recording().nextPeriod(); LLTrace::BlockTimer::logStats(); } @@ -1776,13 +1768,6 @@ bool LLAppViewer::cleanup() LLSceneMonitor::deleteSingleton(); } - // There used to be an 'if (LLFastTimerView::sAnalyzePerformance)' block - // here, completely redundant with the one that occurs later in this same - // function. Presumably the duplication was due to an automated merge gone - // bad. Not knowing which instance to prefer, we chose to retain the later - // one because it happens just after mFastTimerLogThread is deleted. This - // comment is in case we guessed wrong, so we can move it here instead. - #if LL_LINUX // remove any old breakpad minidump files from the log directory if (! isError()) @@ -2148,20 +2133,6 @@ bool LLAppViewer::cleanup() delete mGeneralThreadPool; mGeneralThreadPool = NULL; - if (LLFastTimerView::sAnalyzePerformance) - { - LL_INFOS() << "Analyzing performance" << LL_ENDL; - - std::string baseline_name = LLTrace::BlockTimer::sLogName + "_baseline.slp"; - std::string current_name = LLTrace::BlockTimer::sLogName + ".slp"; - std::string report_name = LLTrace::BlockTimer::sLogName + "_report.csv"; - - LLFastTimerView::doAnalysis( - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name), - gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name)); - } - SUBSYSTEM_CLEANUP(LLMetricPerformanceTesterBasic) ; LL_INFOS() << "Cleaning up Media and Textures" << LL_ENDL; @@ -2891,7 +2862,6 @@ bool LLAppViewer::initConfiguration() mForceGraphicsLevel = gSavedSettings.getU32("RenderQualityPerformance"); } - LLFastTimerView::sAnalyzePerformance = gSavedSettings.getBOOL("AnalyzePerformance"); gAgentPilot.setReplaySession(gSavedSettings.getBOOL("ReplaySession")); if (gSavedSettings.getBOOL("DebugSession")) @@ -5024,20 +4994,6 @@ class LLFrameStatsTimer : public LLFrameTimer } }; -static LLTrace::BlockTimerStatHandle FTM_AUDIO_UPDATE("Update Audio"); -static LLTrace::BlockTimerStatHandle FTM_CLEANUP("Cleanup"); -static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLES("Drawables"); -static LLTrace::BlockTimerStatHandle FTM_IDLE_CB("Idle Callbacks"); -static LLTrace::BlockTimerStatHandle FTM_LOD_UPDATE("Update LOD"); -static LLTrace::BlockTimerStatHandle FTM_OBJECTLIST_UPDATE("Update Objectlist"); -static LLTrace::BlockTimerStatHandle FTM_REGION_UPDATE("Update Region"); -static LLTrace::BlockTimerStatHandle FTM_WORLD_UPDATE("Update World"); -static LLTrace::BlockTimerStatHandle FTM_NETWORK("Network"); -static LLTrace::BlockTimerStatHandle FTM_AGENT_NETWORK("Agent Network"); -static LLTrace::BlockTimerStatHandle FTM_VLMANAGER("VL Manager"); -static LLTrace::BlockTimerStatHandle FTM_AGENT_POSITION("Agent Position"); -static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); - /////////////////////////////////////////////////////// // idle() // @@ -5285,11 +5241,9 @@ void LLAppViewer::idle() { // Teleported, but waiting for things to load, start processing surface data { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); gVLManager.unpackData(); } { - LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); const F32 max_region_update_time = .001f; // 1ms LLWorld::getInstance()->updateRegions(max_region_update_time); } @@ -5312,15 +5266,12 @@ void LLAppViewer::idle() { // Handle pending gesture processing - LL_RECORD_BLOCK_TIME(FTM_AGENT_POSITION); LLGestureMgr::instance().update(); gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); } { - LL_RECORD_BLOCK_TIME(FTM_OBJECTLIST_UPDATE); - if (!(logoutRequestSent() && hasSavedFinalSnapshot())) { gObjectList.update(gAgent); @@ -5334,12 +5285,10 @@ void LLAppViewer::idle() // { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP); { gObjectList.cleanDeadObjects(); } { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLES); LLDrawable::cleanupDeadDrawables(); } } @@ -5358,7 +5307,7 @@ void LLAppViewer::idle() // { - LL_RECORD_BLOCK_TIME(FTM_HUD_EFFECTS); + LL_PROFILE_ZONE_NAMED("Update HUD Effects"); LLSelectMgr::getInstance()->updateEffects(); LLHUDManager::getInstance()->cleanupEffects(); LLHUDManager::getInstance()->sendEffects(); @@ -5370,7 +5319,6 @@ void LLAppViewer::idle() // { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); gVLManager.unpackData(); } @@ -5382,7 +5330,6 @@ void LLAppViewer::idle() LLWorld::getInstance()->updateVisibilities(); { const F32 max_region_update_time = .001f; // 1ms - LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE); LLWorld::getInstance()->updateRegions(max_region_update_time); } @@ -5452,7 +5399,6 @@ void LLAppViewer::idle() // objects and camera should be in sync, do LOD calculations now { - LL_RECORD_BLOCK_TIME(FTM_LOD_UPDATE); gObjectList.updateApparentAngles(gAgent); } @@ -5804,13 +5750,6 @@ void LLAppViewer::idleNameCache() constexpr F32 CHECK_MESSAGES_DEFAULT_MAX_TIME = 0.020f; // 50 ms = 50 fps (just for messages!) static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; -static LLTrace::BlockTimerStatHandle FTM_IDLE_NETWORK("Idle Network"); -static LLTrace::BlockTimerStatHandle FTM_MESSAGE_ACKS("Message Acks"); -static LLTrace::BlockTimerStatHandle FTM_RETRANSMIT("Retransmit"); -static LLTrace::BlockTimerStatHandle FTM_TIMEOUT_CHECK("Timeout Check"); -static LLTrace::BlockTimerStatHandle FTM_DYNAMIC_THROTTLE("Dynamic Throttle"); -static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circuit"); - void LLAppViewer::idleNetwork() { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; @@ -5822,7 +5761,7 @@ void LLAppViewer::idleNetwork() static LLCachedControl speed_test(gSavedSettings, "SpeedTest", false); if (!speed_test()) { - LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); // decode LLTimer check_message_timer; // Read all available packets from network diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 39a31fb630f..013709363bd 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1299,11 +1299,9 @@ void LLChatHistory::clear() mLastFromID = LLUUID::null; } -static LLTrace::BlockTimerStatHandle FTM_APPEND_MESSAGE("Append Chat Message"); - void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LLStyle::Params& input_append_params) { - LL_RECORD_BLOCK_TIME(FTM_APPEND_MESSAGE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; bool use_plain_text_chat_history = args["chat_history_style"].asInteger() >= 1; bool use_irssi_text_chat_history = args["chat_history_style"].asInteger() >= 2; bool square_brackets = false; // square brackets necessary for a system messages diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index 53da9826ed7..b77195928bb 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -29,7 +29,6 @@ #include "lldebugview.h" // library includes -#include "llfasttimerview.h" #include "llconsole.h" #include "lltextureview.h" #include "llresmgr.h" @@ -53,7 +52,6 @@ static LLDefaultChildRegistry::Register r("debug_view"); LLDebugView::LLDebugView(const LLDebugView::Params& p) : LLView(p), - mFastTimerView(NULL), mDebugConsolep(NULL), mFloaterSnapRegion(NULL) {} @@ -89,8 +87,6 @@ void LLDebugView::init() r.setLeftTopAndSize(25, rect.getHeight() - 50, (S32) (gViewerWindow->getWindowRectScaled().getWidth() * 0.75f), (S32) (gViewerWindow->getWindowRectScaled().getHeight() * 0.75f)); - mFastTimerView = dynamic_cast(LLFloaterReg::getInstance("block_timers")); - gSceneView = new LLSceneView(r); gSceneView->setFollowsTop(); gSceneView->setFollowsLeft(); diff --git a/indra/newview/lldebugview.h b/indra/newview/lldebugview.h index 8fa2acc3c9d..4ba9cb360bc 100644 --- a/indra/newview/lldebugview.h +++ b/indra/newview/lldebugview.h @@ -35,7 +35,6 @@ // declarations class LLButton; class LLStatusPanel; -class LLFastTimerView; class LLConsole; class LLTextureView; class LLFloaterStats; @@ -59,7 +58,6 @@ class LLDebugView : public LLView void setStatsVisible(bool visible); - LLFastTimerView* mFastTimerView; LLConsole* mDebugConsolep; LLView* mFloaterSnapRegion; }; diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index b4ced668d01..2039bab8437 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -130,11 +130,9 @@ void LLDoNotDisturbNotificationStorage::saveNotifications() resetDirty(); } -static LLTrace::BlockTimerStatHandle FTM_LOAD_DND_NOTIFICATIONS("Load DND Notifications"); - void LLDoNotDisturbNotificationStorage::loadNotifications() { - LL_RECORD_BLOCK_TIME(FTM_LOAD_DND_NOTIFICATIONS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LL_INFOS("LLDoNotDisturbNotificationStorage") << "start loading notifications" << LL_ENDL; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index da9378ad129..eef20cec763 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -287,6 +287,7 @@ void LLDrawable::removeFromOctree() void LLDrawable::cleanupDeadDrawables() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; /* S32 i; for (i = 0; i < sDeadList.size(); i++) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 1cca08c20bc..728f00c260a 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -853,8 +853,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } -static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO"); - //----------------------------------------------------------------------------- // getDebugTexture() //----------------------------------------------------------------------------- diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 6de7a968d0f..a66b2280660 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -37,10 +37,6 @@ #include "llviewershadermgr.h" #include "llrender.h" -static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass"); - - void LLDrawPoolGlow::renderPostDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -107,8 +103,6 @@ LLDrawPoolSimple::LLDrawPoolSimple() : { } -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK("Alpha Mask"); - LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() : LLRenderPass(POOL_ALPHA_MASK) { @@ -142,9 +136,6 @@ void LLDrawPoolSimple::renderDeferred(S32 pass) pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, true, true); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask"); - - void LLDrawPoolAlphaMask::renderDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index d0536b0b406..8b5ce00fc46 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -58,8 +58,6 @@ S32 LLDrawPoolTerrain::sPBRDetailMode = 0; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; F32 LLDrawPoolTerrain::sPBRDetailScale = DETAIL_SCALE; static LLGLSLShader* sShader = NULL; -static LLTrace::BlockTimerStatHandle FTM_SHADOW_TERRAIN("Terrain Shadow"); - LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) : LLFacePool(POOL_TERRAIN), diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 5e675003d6c..489a2e27b83 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -55,7 +55,7 @@ LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : //============================================ void LLDrawPoolTree::beginDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; shader = &gDeferredTreeProgram; shader->bind(); @@ -99,7 +99,7 @@ void LLDrawPoolTree::renderDeferred(S32 pass) void LLDrawPoolTree::endDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TREES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; shader->unbind(); } diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 9d24ac2b1c0..e58dfe1e6af 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -105,8 +105,6 @@ namespace const std::string LOCAL_ENV_STORAGE_FILE("local_environment_data.bin"); //--------------------------------------------------------------------- - LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); - LLSettingsBase::Seconds DEFAULT_UPDATE_THRESHOLD(10.0); const LLSettingsBase::Seconds MINIMUM_SPANLENGTH(0.01f); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp deleted file mode 100644 index e3acb8e9268..00000000000 --- a/indra/newview/llfasttimerview.cpp +++ /dev/null @@ -1,1667 +0,0 @@ -/** - * @file llfasttimerview.cpp - * @brief LLFastTimerView class implementation - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "llfasttimerview.h" - -#include "llviewerwindow.h" -#include "llrect.h" -#include "llcombobox.h" -#include "llerror.h" -#include "llgl.h" -#include "llimagepng.h" -#include "llrender.h" -#include "llrendertarget.h" -#include "lllocalcliprect.h" -#include "lllayoutstack.h" -#include "llmath.h" -#include "llfontgl.h" -#include "llsdserialize.h" -#include "lltooltip.h" -#include "llbutton.h" -#include "llscrollbar.h" - -#include "llappviewer.h" -#include "llviewertexturelist.h" -#include "llui.h" -#include "llviewercontrol.h" - -#include "llfasttimer.h" -#include "lltreeiterators.h" -#include "llmetricperformancetester.h" -#include "llviewerstats.h" - -////////////////////////////////////////////////////////////////////////////// - -using namespace LLTrace; - -extern LLTrace::BlockTimerStatHandle FTM_FRAME; - -static constexpr S32 MAX_VISIBLE_HISTORY = 12; -static constexpr S32 LINE_GRAPH_HEIGHT = 240; -static constexpr S32 MIN_BAR_HEIGHT = 3; -static constexpr S32 RUNNING_AVERAGE_WIDTH = 100; -static constexpr S32 NUM_FRAMES_HISTORY = 200; - -std::vector ft_display_idx; // line of table entry for display purposes (for collapse) - -bool LLFastTimerView::sAnalyzePerformance = false; - -S32 get_depth(const BlockTimerStatHandle* blockp) -{ - S32 depth = 0; - BlockTimerStatHandle* timerp = blockp->getParent(); - while(timerp) - { - depth++; - if (timerp->getParent() == timerp) break; - timerp = timerp->getParent(); - } - return depth; -} - -LLFastTimerView::LLFastTimerView(const LLSD& key) -: LLFloater(key), - mHoverTimer(NULL), - mDisplayMode(0), - mDisplayType(DISPLAY_TIME), - mScrollIndex(0), - mHoverID(NULL), - mHoverBarIndex(-1), - mStatsIndex(-1), - mPauseHistory(false), - mRecording(NUM_FRAMES_HISTORY) -{ - mTimerBarRows.resize(NUM_FRAMES_HISTORY); -} - -LLFastTimerView::~LLFastTimerView() -{ -} - -void LLFastTimerView::onPause() -{ - setPauseState(!mPauseHistory); -} - -void LLFastTimerView::setPauseState(bool pause_state) -{ - if (pause_state == mPauseHistory) return; - - // reset scroll to bottom when unpausing - if (!pause_state) - { - - getChild("pause_btn")->setLabel(getString("pause")); - } - else - { - mScrollIndex = 0; - - getChild("pause_btn")->setLabel(getString("run")); - } - - mPauseHistory = pause_state; -} - -bool LLFastTimerView::postBuild() -{ - LLButton& pause_btn = getChildRef("pause_btn"); - mScrollBar = getChild("scroll_vert"); - - pause_btn.setCommitCallback(boost::bind(&LLFastTimerView::onPause, this)); - return true; -} - -bool LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - if (mHoverTimer ) - { - // right click collapses timers - if (!mHoverTimer->getTreeNode().mCollapsed) - { - mHoverTimer->getTreeNode().mCollapsed = true; - } - else if (mHoverTimer->getParent()) - { - mHoverTimer->getParent()->getTreeNode().mCollapsed = true; - } - return true; - } - else if (mBarRect.pointInRect(x, y)) - { - S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); - bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY); - mStatsIndex = mScrollIndex + bar_idx; - return true; - } - return LLFloater::handleRightMouseDown(x, y, mask); -} - -BlockTimerStatHandle* LLFastTimerView::getLegendID(S32 y) -{ - S32 idx = (mLegendRect.mTop - y) / (LLFontGL::getFontMonospace()->getLineHeight() + 2); - - if (idx >= 0 && idx < (S32)ft_display_idx.size()) - { - return ft_display_idx[idx]; - } - - return NULL; -} - -bool LLFastTimerView::handleDoubleClick(S32 x, S32 y, MASK mask) -{ - for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - (*it)->getTreeNode().mCollapsed = false; - } - return true; -} - -bool LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) -{ - if (x < mScrollBar->getRect().mLeft) - { - BlockTimerStatHandle* idp = getLegendID(y); - if (idp) - { - idp->getTreeNode().mCollapsed = !idp->getTreeNode().mCollapsed; - } - } - else if (mHoverTimer) - { - //left click drills down by expanding timers - mHoverTimer->getTreeNode().mCollapsed = false; - } - else if (mGraphRect.pointInRect(x, y)) - { - gFocusMgr.setMouseCapture(this); - return true; - } - - return LLFloater::handleMouseDown(x, y, mask); -} - -bool LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask) -{ - if (hasMouseCapture()) - { - gFocusMgr.setMouseCapture(NULL); - } - return LLFloater::handleMouseUp(x, y, mask);; -} - -bool LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) -{ - if (hasMouseCapture()) - { - F32 lerp = llclamp(1.f - (F32) (x - mGraphRect.mLeft) / (F32) mGraphRect.getWidth(), 0.f, 1.f); - mScrollIndex = ll_round( lerp * (F32)(mRecording.getNumRecordedPeriods() - MAX_VISIBLE_HISTORY)); - mScrollIndex = llclamp( mScrollIndex, 0, (S32)mRecording.getNumRecordedPeriods()); - return true; - } - mHoverTimer = NULL; - mHoverID = NULL; - - if(mPauseHistory && mBarRect.pointInRect(x, y)) - { - //const S32 bars_top = mBarRect.mTop; - const S32 bars_top = mBarRect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4); - - mHoverBarIndex = llmin((bars_top - y) / (mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2)) - 1, - (S32)mRecording.getNumRecordedPeriods() - 1, - MAX_VISIBLE_HISTORY); - if (mHoverBarIndex == 0) - { - return true; - } - else if (mHoverBarIndex < 0) - { - mHoverBarIndex = 0; - } - - TimerBarRow& row = mHoverBarIndex == 0 ? mAverageTimerRow : mTimerBarRows[mScrollIndex + mHoverBarIndex - 1]; - - TimerBar* hover_bar = NULL; - F32Seconds mouse_time_offset = ((F32)(x - mBarRect.mLeft) / (F32)mBarRect.getWidth()) * mTotalTimeDisplay; - for (size_t bar_index = 0, end_index = LLTrace::BlockTimerStatHandle::instance_tracker_t::instanceCount(); - bar_index < end_index; - ++bar_index) - { - TimerBar& bar = row.mBars[bar_index]; - if (bar.mSelfStart > mouse_time_offset) - { - break; - } - if (bar.mSelfEnd > mouse_time_offset) - { - hover_bar = &bar; - if (bar.mTimeBlock->getTreeNode().mCollapsed) - { - // stop on first collapsed BlockTimerStatHandle, since we can't select any children - break; - } - } - } - - if (hover_bar) - { - mHoverID = hover_bar->mTimeBlock; - if (mHoverTimer != mHoverID) - { - // could be that existing tooltip is for a parent and is thus - // covering region for this new timer, go ahead and unblock - // so we can create a new tooltip - LLToolTipMgr::instance().unblockToolTips(); - mHoverTimer = mHoverID; - mToolTipRect.set((S32)(mBarRect.mLeft + (hover_bar->mSelfStart / mTotalTimeDisplay) * mBarRect.getWidth()), - row.mTop, - (S32)(mBarRect.mLeft + (hover_bar->mSelfEnd / mTotalTimeDisplay) * mBarRect.getWidth()), - row.mBottom); - } - } - } - else if (x < mScrollBar->getRect().mLeft) - { - BlockTimerStatHandle* timer_id = getLegendID(y); - if (timer_id) - { - mHoverID = timer_id; - } - } - - return LLFloater::handleHover(x, y, mask); -} - - -static std::string get_tooltip(BlockTimerStatHandle& timer, S32 history_index, PeriodicRecording& frame_recording) -{ - std::string tooltip; - if (history_index == 0) - { - // by default, show average number of call - tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)F64Milliseconds(frame_recording.getPeriodMean (timer, RUNNING_AVERAGE_WIDTH)).value(), (S32)frame_recording.getPeriodMean(timer.callCount(), RUNNING_AVERAGE_WIDTH)); - } - else - { - tooltip = llformat("%s (%d ms, %d calls)", timer.getName().c_str(), (S32)F64Milliseconds(frame_recording.getPrevRecording(history_index).getSum(timer)).value(), (S32)frame_recording.getPrevRecording(history_index).getSum(timer.callCount())); - } - return tooltip; -} - -bool LLFastTimerView::handleToolTip(S32 x, S32 y, MASK mask) -{ - if(mPauseHistory && mBarRect.pointInRect(x, y)) - { - // tooltips for timer bars - if (mHoverTimer) - { - LLRect screen_rect; - localRectToScreen(mToolTipRect, &screen_rect); - - std::string tooltip = get_tooltip(*mHoverTimer, mHoverBarIndex > 0 ? mScrollIndex + mHoverBarIndex : 0, mRecording); - - LLToolTipMgr::instance().show(LLToolTip::Params() - .message(tooltip) - .sticky_rect(screen_rect) - .delay_time(0.f)); - - return true; - } - } - else - { - // tooltips for timer legend - if (x < mScrollBar->getRect().mLeft) - { - BlockTimerStatHandle* idp = getLegendID(y); - if (idp) - { - LLToolTipMgr::instance().show(get_tooltip(*idp, 0, mRecording)); - - return true; - } - } - } - - return LLFloater::handleToolTip(x, y, mask); -} - -bool LLFastTimerView::handleScrollWheel(S32 x, S32 y, LLScrollDelta delta) -{ - if (x < mBarRect.mLeft) - { - // Inside mScrollBar and list of timers - mScrollBar->handleScrollWheel(x,y,delta); - } - else - { - setPauseState(true); - mScrollIndex = llclamp( mScrollIndex + delta.mClicks, - 0, - llmin((S32)mRecording.getNumRecordedPeriods(), (S32)mRecording.getNumRecordedPeriods() - MAX_VISIBLE_HISTORY)); - } - return true; -} - -static BlockTimerStatHandle FTM_RENDER_TIMER("Timers"); -static const S32 MARGIN = 10; - -static std::vector sTimerColors; - -void LLFastTimerView::draw() -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_TIMER); - - if (!mPauseHistory) - { - mRecording.appendRecording(LLTrace::get_frame_recording().getLastRecording()); - mTimerBarRows.pop_back(); - mTimerBarRows.push_front(TimerBarRow()); - } - - mDisplayMode = llclamp(getChild("time_scale_combo")->getCurrentIndex(), 0, 3); - mDisplayType = (EDisplayType)llclamp(getChild("metric_combo")->getCurrentIndex(), 0, 2); - - generateUniqueColors(); - - LLView::drawChildren(); - //getChild("timer_bars_stack")->updateLayout(); - //getChild("legend_stack")->updateLayout(); - LLView* bars_panel = getChildView("bars_panel"); - bars_panel->localRectToOtherView(bars_panel->getLocalRect(), &mBarRect, this); - - LLView* lines_panel = getChildView("lines_panel"); - lines_panel->localRectToOtherView(lines_panel->getLocalRect(), &mGraphRect, this); - - LLView* legend_panel = getChildView("legend"); - legend_panel->localRectToOtherView(legend_panel->getLocalRect(), &mLegendRect, this); - - // Draw the window background - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(getLocalRect(), LLColor4(0.f, 0.f, 0.f, 0.25f)); - - drawHelp(getRect().getHeight() - MARGIN); - drawLegend(); - - //mBarRect.mLeft = MARGIN + LEGEND_WIDTH + 8; - //mBarRect.mTop = y; - //mBarRect.mRight = getRect().getWidth() - MARGIN; - //mBarRect.mBottom = MARGIN + LINE_GRAPH_HEIGHT; - - drawBars(); - drawLineGraph(); - printLineStats(); - LLView::draw(); - - mAllTimeMax = llmax(mAllTimeMax, mRecording.getLastRecording().getSum(FTM_FRAME)); - mHoverID = NULL; - mHoverBarIndex = -1; -} - -void LLFastTimerView::onOpen(const LLSD& key) -{ - setPauseState(false); - mRecording.reset(); - mRecording.appendPeriodicRecording(LLTrace::get_frame_recording()); - for(std::deque::iterator it = mTimerBarRows.begin(), end_it = mTimerBarRows.end(); - it != end_it; - ++it) - { - delete []it->mBars; - it->mBars = NULL; - } -} - -void LLFastTimerView::onClose(bool app_quitting) -{ - setVisible(false); -} - -void saveChart(const std::string& label, const char* suffix, LLImageRaw* scratch) -{ - // disable use of glReadPixels which messes up nVidia nSight graphics debugging - if (!LLRender::sNsightDebugSupport) - { - LLImageDataSharedLock lock(scratch); - - //read result back into raw image - glReadPixels(0, 0, 1024, 512, GL_RGB, GL_UNSIGNED_BYTE, scratch->getData()); - - //write results to disk - LLPointer result = new LLImagePNG(); - result->encode(scratch, 0.f); - - std::string ext = result->getExtension(); - std::string filename = llformat("%s_%s.%s", label.c_str(), suffix, ext.c_str()); - - std::string out_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, filename); - result->save(out_file); - } -} - -//static -void LLFastTimerView::exportCharts(const std::string& base, const std::string& target) -{ - //allocate render target for drawing charts - LLRenderTarget buffer; - buffer.allocate(1024,512, GL_RGB); - - - LLSD cur; - - LLSD base_data; - - { //read base log into memory - S32 i = 0; - llifstream is(base.c_str()); - while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) - { - base_data[i++] = cur; - } - is.close(); - } - - LLSD cur_data; - std::set chart_names; - - { //read current log into memory - S32 i = 0; - llifstream is(target.c_str()); - while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) - { - cur_data[i++] = cur; - - for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) - { - std::string label = iter->first; - chart_names.insert(label); - } - } - is.close(); - } - - //allocate raw scratch space - LLPointer scratch = new LLImageRaw(1024, 512, 3); - - gGL.pushMatrix(); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.loadIdentity(); - gGL.ortho(-0.05f, 1.05f, -0.05f, 1.05f, -1.0f, 1.0f); - - //render charts - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - buffer.bindTarget(); - - for (std::set::iterator iter = chart_names.begin(); iter != chart_names.end(); ++iter) - { - std::string label = *iter; - - LLSD::Real max_time = 0.0; - LLSD::Integer max_calls = 0; - LLSD::Real max_execution = 0.0; - - std::vector cur_execution; - std::vector cur_times; - std::vector cur_calls; - - std::vector base_execution; - std::vector base_times; - std::vector base_calls; - - for (U32 i = 0; i < cur_data.size(); ++i) - { - LLSD::Real time = cur_data[i][label]["Time"].asReal(); - LLSD::Integer calls = cur_data[i][label]["Calls"].asInteger(); - - LLSD::Real execution = 0.0; - if (calls > 0) - { - execution = time/calls; - cur_execution.push_back(execution); - cur_times.push_back(time); - } - - cur_calls.push_back(calls); - } - - for (U32 i = 0; i < base_data.size(); ++i) - { - LLSD::Real time = base_data[i][label]["Time"].asReal(); - LLSD::Integer calls = base_data[i][label]["Calls"].asInteger(); - - LLSD::Real execution = 0.0; - if (calls > 0) - { - execution = time/calls; - base_execution.push_back(execution); - base_times.push_back(time); - } - - base_calls.push_back(calls); - } - - std::sort(base_calls.begin(), base_calls.end()); - std::sort(base_times.begin(), base_times.end()); - std::sort(base_execution.begin(), base_execution.end()); - - std::sort(cur_calls.begin(), cur_calls.end()); - std::sort(cur_times.begin(), cur_times.end()); - std::sort(cur_execution.begin(), cur_execution.end()); - - //remove outliers - const U32 OUTLIER_CUTOFF = 512; - if (base_times.size() > OUTLIER_CUTOFF) - { - ll_remove_outliers(base_times, 1.f); - } - - if (base_execution.size() > OUTLIER_CUTOFF) - { - ll_remove_outliers(base_execution, 1.f); - } - - if (cur_times.size() > OUTLIER_CUTOFF) - { - ll_remove_outliers(cur_times, 1.f); - } - - if (cur_execution.size() > OUTLIER_CUTOFF) - { - ll_remove_outliers(cur_execution, 1.f); - } - - - max_time = llmax(base_times.empty() ? 0.0 : *base_times.rbegin(), cur_times.empty() ? 0.0 : *cur_times.rbegin()); - max_calls = llmax(base_calls.empty() ? 0 : *base_calls.rbegin(), cur_calls.empty() ? 0 : *cur_calls.rbegin()); - max_execution = llmax(base_execution.empty() ? 0.0 : *base_execution.rbegin(), cur_execution.empty() ? 0.0 : *cur_execution.rbegin()); - - - LLVector3 last_p; - - //==================================== - // basic - //==================================== - buffer.clear(); - - last_p.clear(); - - LLGLDisable cull(GL_CULL_FACE); - - LLVector3 base_col(0, 0.7f, 0.f); - LLVector3 cur_col(1.f, 0.f, 0.f); - - gGL.setSceneBlendType(LLRender::BT_ADD); - - gGL.color3fv(base_col.mV); - for (U32 i = 0; i < base_times.size(); ++i) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - last_p.set((F32)i/(F32) base_times.size(), (F32)(base_times[i]/max_time), 0.f); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.end(); - } - - gGL.flush(); - - - last_p.clear(); - { - LLGLEnable blend(GL_BLEND); - - gGL.color3fv(cur_col.mV); - for (U32 i = 0; i < cur_times.size(); ++i) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - last_p.set((F32) i / (F32) cur_times.size(), (F32)(cur_times[i]/max_time), 0.f); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - gGL.end(); - } - - gGL.flush(); - } - - saveChart(label, "time", scratch); - - //====================================== - // calls - //====================================== - buffer.clear(); - - last_p.clear(); - - gGL.color3fv(base_col.mV); - for (U32 i = 0; i < base_calls.size(); ++i) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - last_p.set((F32) i / (F32) base_calls.size(), (F32)base_calls[i]/max_calls, 0.f); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.end(); - } - - gGL.flush(); - - { - LLGLEnable blend(GL_BLEND); - gGL.color3fv(cur_col.mV); - last_p.clear(); - - for (U32 i = 0; i < cur_calls.size(); ++i) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - last_p.set((F32) i / (F32) cur_calls.size(), (F32) cur_calls[i]/max_calls, 0.f); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - gGL.end(); - - } - - gGL.flush(); - } - - saveChart(label, "calls", scratch); - - //====================================== - // execution - //====================================== - buffer.clear(); - - gGL.color3fv(base_col.mV); - U32 count = 0; - U32 total_count = static_cast(base_execution.size()); - - last_p.clear(); - - for (std::vector::iterator iter = base_execution.begin(); iter != base_execution.end(); ++iter) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - last_p.set((F32)count/(F32)total_count, (F32)(*iter/max_execution), 0.f); - gGL.vertex3fv(last_p.mV); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.end(); - count++; - } - - last_p.clear(); - - { - LLGLEnable blend(GL_BLEND); - gGL.color3fv(cur_col.mV); - count = 0; - total_count = static_cast(cur_execution.size()); - - for (std::vector::iterator iter = cur_execution.begin(); iter != cur_execution.end(); ++iter) - { - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - last_p.set((F32)count/(F32)total_count, (F32)(*iter/max_execution), 0.f); - gGL.vertex3f(last_p.mV[0], 0.f, 0.f); - gGL.vertex3fv(last_p.mV); - gGL.end(); - count++; - } - - gGL.flush(); - } - - saveChart(label, "execution", scratch); - } - - buffer.flush(); - - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); -} - -//static -LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is) -{ - LLSD ret; - - LLSD cur; - - LLSD::Real total_time = 0.0; - LLSD::Integer total_frames = 0; - - typedef std::map stats_map_t; - stats_map_t time_stats; - stats_map_t sample_stats; - - while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) - { - for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) - { - std::string label = iter->first; - - F64 time = iter->second["Time"].asReal(); - - // Skip the total figure - if(label.compare("Total") != 0) - { - total_time += time; - } - - if (time > 0.0) - { - LLSD::Integer samples = iter->second["Calls"].asInteger(); - - time_stats[label].push((F32)time); - sample_stats[label].push((F32)samples); - } - } - total_frames++; - } - - for(stats_map_t::iterator it = time_stats.begin(); it != time_stats.end(); ++it) - { - std::string label = it->first; - ret[label]["TotalTime"] = time_stats[label].getSum(); - ret[label]["MeanTime"] = time_stats[label].getMean(); - ret[label]["MaxTime"] = time_stats[label].getMaxValue(); - ret[label]["MinTime"] = time_stats[label].getMinValue(); - ret[label]["StdDevTime"] = time_stats[label].getStdDev(); - - ret[label]["Samples"] = sample_stats[label].getSum(); - ret[label]["MaxSamples"] = sample_stats[label].getMaxValue(); - ret[label]["MinSamples"] = sample_stats[label].getMinValue(); - ret[label]["StdDevSamples"] = sample_stats[label].getStdDev(); - - ret[label]["Frames"] = (LLSD::Integer)time_stats[label].getCount(); - } - - ret["SessionTime"] = total_time; - ret["FrameCount"] = total_frames; - - return ret; - -} - -//static -void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output) -{ - // Open baseline and current target, exit if one is inexistent - llifstream base_is(baseline.c_str()); - llifstream target_is(target.c_str()); - if (!base_is.is_open() || !target_is.is_open()) - { - LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; - base_is.close(); - target_is.close(); - return; - } - - //analyze baseline - LLSD base = analyzePerformanceLogDefault(base_is); - base_is.close(); - - //analyze current - LLSD current = analyzePerformanceLogDefault(target_is); - target_is.close(); - - //output comparison - llofstream os(output.c_str()); - - LLSD::Real session_time = current["SessionTime"].asReal(); - os << - "Label, " - "% Change, " - "% of Session, " - "Cur Min, " - "Cur Max, " - "Cur Mean/sample, " - "Cur Mean/frame, " - "Cur StdDev/frame, " - "Cur Total, " - "Cur Frames, " - "Cur Samples, " - "Base Min, " - "Base Max, " - "Base Mean/sample, " - "Base Mean/frame, " - "Base StdDev/frame, " - "Base Total, " - "Base Frames, " - "Base Samples\n"; - - for (LLSD::map_iterator iter = base.beginMap(); iter != base.endMap(); ++iter) - { - LLSD::String label = iter->first; - - if (current[label]["Samples"].asInteger() == 0 || - base[label]["Samples"].asInteger() == 0) - { - //cannot compare - continue; - } - LLSD::Real a = base[label]["TotalTime"].asReal() / base[label]["Samples"].asReal(); - LLSD::Real b = current[label]["TotalTime"].asReal() / current[label]["Samples"].asReal(); - - LLSD::Real diff = b-a; - - LLSD::Real perc = diff/a * 100; - - os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %d\n", - label.c_str(), - (F32) perc, - (F32) (current[label]["TotalTime"].asReal()/session_time * 100.0), - - (F32) current[label]["MinTime"].asReal(), - (F32) current[label]["MaxTime"].asReal(), - (F32) b, - (F32) current[label]["MeanTime"].asReal(), - (F32) current[label]["StdDevTime"].asReal(), - (F32) current[label]["TotalTime"].asReal(), - current[label]["Frames"].asInteger(), - current[label]["Samples"].asInteger(), - (F32) base[label]["MinTime"].asReal(), - (F32) base[label]["MaxTime"].asReal(), - (F32) a, - (F32) base[label]["MeanTime"].asReal(), - (F32) base[label]["StdDevTime"].asReal(), - (F32) base[label]["TotalTime"].asReal(), - base[label]["Frames"].asInteger(), - base[label]["Samples"].asInteger()); - } - - exportCharts(baseline, target); - - os.flush(); - os.close(); -} - -//static -void LLFastTimerView::outputAllMetrics() -{ - if (LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) - { - for (LLMetricPerformanceTesterBasic::name_tester_map_t::iterator iter = LLMetricPerformanceTesterBasic::sTesterMap.begin(); - iter != LLMetricPerformanceTesterBasic::sTesterMap.end(); ++iter) - { - LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)iter->second); - tester->outputTestResults(); - } - } -} - -//static -void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output) -{ - if(BlockTimer::sLog) - { - doAnalysisDefault(baseline, target, output) ; - return ; - } - - if(BlockTimer::sMetricLog) - { - LLMetricPerformanceTesterBasic::doAnalysisMetrics(baseline, target, output) ; - return ; - } -} - - -void LLFastTimerView::printLineStats() -{ - // Output stats for clicked bar to log - if (mStatsIndex >= 0) - { - std::string legend_stat; - bool first = true; - for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - BlockTimerStatHandle* idp = (*it); - - if (!first) - { - legend_stat += ", "; - } - first = false; - legend_stat += idp->getName(); - - //if (idp->getTreeNode().mCollapsed) - //{ - // it.skipDescendants(); - //} - } - LL_INFOS() << legend_stat << LL_ENDL; - - std::string timer_stat; - first = true; - for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - BlockTimerStatHandle* idp = (*it); - - if (!first) - { - timer_stat += ", "; - } - first = false; - - F32Seconds ticks; - if (mStatsIndex == 0) - { - ticks = mRecording.getPeriodMean(*idp, RUNNING_AVERAGE_WIDTH); - } - else - { - ticks = mRecording.getPrevRecording(mStatsIndex).getSum(*idp); - } - F32Milliseconds ms = ticks; - - timer_stat += llformat("%.1f",ms.value()); - - //if (idp->getTreeNode().mCollapsed) - //{ - // it.skipDescendants(); - //} - } - LL_INFOS() << timer_stat << LL_ENDL; - mStatsIndex = -1; - } -} - -void LLFastTimerView::drawLineGraph() -{ - LL_PROFILE_ZONE_SCOPED; - //draw line graph history - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLLocalClipRect clip(mGraphRect); - - //normalize based on last frame's maximum - static F32Seconds max_time(0.000001f); - static U32 max_calls = 0; - static F32 alpha_interp = 0.f; - - //highlight visible range - { - S32 first_frame = static_cast(mRecording.getNumRecordedPeriods()) - mScrollIndex; - S32 last_frame = first_frame - MAX_VISIBLE_HISTORY; - - F32 frame_delta = ((F32) (mGraphRect.getWidth()))/(mRecording.getNumRecordedPeriods()-1); - - F32 right = (F32) mGraphRect.mLeft + frame_delta*first_frame; - F32 left = (F32) mGraphRect.mLeft + frame_delta*last_frame; - - gGL.color4f(0.5f,0.5f,0.5f,0.3f); - gl_rect_2d((S32) left, mGraphRect.mTop, (S32) right, mGraphRect.mBottom); - - if (mHoverBarIndex > 0) - { - S32 bar_frame = first_frame - (mScrollIndex + mHoverBarIndex) - 1; - F32 bar = (F32) mGraphRect.mLeft + frame_delta*bar_frame; - - gGL.color4f(0.5f,0.5f,0.5f,1); - - gGL.begin(LLRender::LINES); - gGL.vertex2i((S32)bar, mGraphRect.mBottom); - gGL.vertex2i((S32)bar, mGraphRect.mTop); - gGL.end(); - } - } - - F32Seconds cur_max(0); - U32 cur_max_calls = 0; - - for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - BlockTimerStatHandle* idp = (*it); - - //fatten highlighted timer - if (mHoverID == idp) - { - gGL.setLineWidth(3); - } - - llassert(idp->getIndex() < sTimerColors.size()); - const F32 * col = sTimerColors[idp->getIndex()].mV;// ft_display_table[idx].color->mV; - - F32 alpha = 1.f; - bool is_hover_timer = true; - - if (mHoverID != NULL && - mHoverID != idp) - { //fade out non-highlighted timers - if (idp->getParent() != mHoverID) - { - alpha = alpha_interp; - is_hover_timer = false; - } - } - - gGL.color4f(col[0], col[1], col[2], alpha); - gGL.begin(LLRender::TRIANGLE_STRIP); - F32 call_scale_factor = (F32)mGraphRect.getHeight() / (F32)max_calls; - F32 time_scale_factor = (F32)mGraphRect.getHeight() / max_time.value(); - F32 hz_scale_factor = (F32) mGraphRect.getHeight() / (1.f / max_time.value()); - - for (U32 j = static_cast(mRecording.getNumRecordedPeriods()); - j > 0; - j--) - { - LLTrace::Recording& recording = mRecording.getPrevRecording(j); - F32Seconds time = llmax(recording.getSum(*idp), F64Seconds(0.000001)); - U32 calls = recording.getSum(idp->callCount()); - - if (is_hover_timer) - { - //normalize to highlighted timer - cur_max = llmax(cur_max, time); - cur_max_calls = llmax(cur_max_calls, calls); - } - F32 x = mGraphRect.mRight - j * (F32)(mGraphRect.getWidth())/(mRecording.getNumRecordedPeriods()-1); - F32 y; - switch(mDisplayType) -{ - case DISPLAY_TIME: - y = mGraphRect.mBottom + time.value() * time_scale_factor; - break; - case DISPLAY_CALLS: - y = mGraphRect.mBottom + (F32)calls * call_scale_factor; - break; - case DISPLAY_HZ: - y = mGraphRect.mBottom + (1.f / time.value()) * hz_scale_factor; - break; - } - gGL.vertex2f(x,y); - gGL.vertex2f(x,(GLfloat)mGraphRect.mBottom); - } - gGL.end(); - - if (mHoverID == idp) - { - gGL.setLineWidth(1.f); - } - - if (idp->getTreeNode().mCollapsed) - { - //skip hidden timers - it.skipDescendants(); - } - } - - //interpolate towards new maximum - max_time = (F32Seconds)lerp(max_time.value(), cur_max.value(), LLSmoothInterpolation::getInterpolant(0.1f)); - if (llabs((max_time - cur_max).value()) <= 1) - { - max_time = llmax(F32Microseconds(1.f), F32Microseconds(cur_max)); - } - - max_calls = ll_round(lerp((F32)max_calls, (F32) cur_max_calls, LLSmoothInterpolation::getInterpolant(0.1f))); - if (llabs((S32)(max_calls - cur_max_calls)) <= 1) - { - max_calls = cur_max_calls; - } - - // TODO: make sure alpha is correct in DisplayHz mode - F32 alpha_target = (max_time > cur_max) - ? llmin(max_time / cur_max - 1.f,1.f) - : llmin(cur_max/ max_time - 1.f,1.f); - alpha_interp = lerp(alpha_interp, alpha_target, LLSmoothInterpolation::getInterpolant(0.1f)); - - if (mHoverID != NULL) - { - S32 x = (mGraphRect.mRight + mGraphRect.mLeft)/2; - S32 y = mGraphRect.mBottom + 8; - - LLFontGL::getFontMonospace()->renderUTF8( - mHoverID->getName(), - 0, - x, y, - LLColor4::white, - LLFontGL::LEFT, LLFontGL::BOTTOM); - } - - //display y-axis range - std::string axis_label; - switch(mDisplayType) - { - case DISPLAY_TIME: - axis_label = llformat("%4.2f ms", F32Milliseconds(max_time).value()); - break; - case DISPLAY_CALLS: - axis_label = llformat("%d calls", (int)max_calls); - break; - case DISPLAY_HZ: - axis_label = llformat("%4.2f Hz", max_time.value() ? 1.f / max_time.value() : 0.f); - break; - } - - LLFontGL* font = LLFontGL::getFontMonospace(); - S32 x = mGraphRect.mRight - font->getWidth(axis_label)-5; - S32 y = mGraphRect.mTop - font->getLineHeight();; - - font->renderUTF8(axis_label, 0, x, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); -} - -void LLFastTimerView::drawLegend() -{ - // draw legend - S32 dx; - S32 x = mLegendRect.mLeft; - S32 y = mLegendRect.mTop; - const S32 TEXT_HEIGHT = (S32)LLFontGL::getFontMonospace()->getLineHeight(); - - { - LLLocalClipRect clip(mLegendRect); - S32 cur_line = 0; - S32 scroll_offset = 0; // element's y offset from top of the inner scroll's rect - ft_display_idx.clear(); - std::map display_line; - for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - BlockTimerStatHandle* idp = (*it); - // Needed to figure out offsets and parenting - display_line[idp] = cur_line; - cur_line++; - if (scroll_offset < mScrollBar->getDocPos()) - { - // only offset for visible items - scroll_offset += TEXT_HEIGHT + 2; - if (idp->getTreeNode().mCollapsed) - { - it.skipDescendants(); - } - continue; - } - - // used for mouse clicks - ft_display_idx.push_back(idp); - - // Actual draw, first bar (square), then text - x = MARGIN; - - LLRect bar_rect(x, y, x + TEXT_HEIGHT, y - TEXT_HEIGHT); - S32 scale_offset = 0; - if (idp == mHoverID) - { - scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f); - } - bar_rect.stretch(scale_offset); - llassert(idp->getIndex() < sTimerColors.size()); - gl_rect_2d(bar_rect, sTimerColors[idp->getIndex()]); - - F32Milliseconds ms(0); - S32 calls = 0; - if (mHoverBarIndex > 0 && mHoverID) - { - S32 hidx = mScrollIndex + mHoverBarIndex; - ms = mRecording.getPrevRecording(hidx).getSum(*idp); - calls = mRecording.getPrevRecording(hidx).getSum(idp->callCount()); - } - else - { - ms = F64Seconds(mRecording.getPeriodMean(*idp, RUNNING_AVERAGE_WIDTH)); - calls = (S32)mRecording.getPeriodMean(idp->callCount(), RUNNING_AVERAGE_WIDTH); - } - - std::string timer_label; - switch(mDisplayType) - { - case DISPLAY_TIME: - timer_label = llformat("%s [%.1f]",idp->getName().c_str(),ms.value()); - break; - case DISPLAY_CALLS: - timer_label = llformat("%s (%d)",idp->getName().c_str(),calls); - break; - case DISPLAY_HZ: - timer_label = llformat("%.1f", ms.value() ? (1.f / ms.value()) : 0.f); - break; - } - dx = (TEXT_HEIGHT+4) + get_depth(idp)*8; - - LLColor4 color = LLColor4::white; - if (get_depth(idp) > 0) - { - S32 line_start_y = bar_rect.getCenterY(); - S32 line_end_y = line_start_y + ((TEXT_HEIGHT + 2) * (cur_line - display_line[idp->getParent()])) - TEXT_HEIGHT; - gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); - S32 line_x = x + (TEXT_HEIGHT + 4) + ((get_depth(idp) - 1) * 8); - gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); - if (idp->getTreeNode().mCollapsed && !idp->getChildren().empty()) - { - gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); - } - } - - x += dx; - bool is_child_of_hover_item = (idp == mHoverID); - BlockTimerStatHandle* next_parent = idp->getParent(); - while(!is_child_of_hover_item && next_parent) - { - is_child_of_hover_item = (mHoverID == next_parent); - if (next_parent->getParent() == next_parent) break; - next_parent = next_parent->getParent(); - } - - LLFontGL::getFontMonospace()->renderUTF8(timer_label, 0, - x, y, - color, - LLFontGL::LEFT, LLFontGL::TOP, - is_child_of_hover_item ? LLFontGL::BOLD : LLFontGL::NORMAL); - - y -= (TEXT_HEIGHT + 2); - - scroll_offset += TEXT_HEIGHT + 2; - if (idp->getTreeNode().mCollapsed) - { - it.skipDescendants(); - } - } - // Recalculate scroll size - mScrollBar->setDocSize(scroll_offset - mLegendRect.getHeight()); - } -} - -void LLFastTimerView::generateUniqueColors() -{ - // generate unique colors - { - sTimerColors.resize(LLTrace::BlockTimerStatHandle::getNumIndices()); - sTimerColors[FTM_FRAME.getIndex()] = LLColor4::grey; - - F32 hue = 0.f; - - for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); - it != LLTrace::end_block_timer_tree_df(); - ++it) - { - BlockTimerStatHandle* idp = (*it); - - const F32 HUE_INCREMENT = 0.23f; - hue = fmodf(hue + HUE_INCREMENT, 1.f); - // saturation increases with depth - F32 saturation = clamp_rescale((F32)get_depth(idp), 0.f, 3.f, 0.f, 1.f); - // lightness alternates with depth - F32 lightness = get_depth(idp) % 2 ? 0.5f : 0.6f; - - LLColor4 child_color; - child_color.setHSL(hue, saturation, lightness); - - llassert(idp->getIndex() < sTimerColors.size()); - sTimerColors[idp->getIndex()] = child_color; - } - } -} - -void LLFastTimerView::drawHelp( S32 y ) -{ - // Draw some help - const S32 texth = (S32)LLFontGL::getFontMonospace()->getLineHeight(); - - y -= (texth + 2); - y -= (texth + 2); - - LLFontGL::getFontMonospace()->renderUTF8(std::string("[Right-Click log selected]"), - 0, MARGIN, y, LLColor4::white, LLFontGL::LEFT, LLFontGL::TOP); -} - -void LLFastTimerView::drawTicks() -{ - // Draw MS ticks - { - U32Milliseconds ms = mTotalTimeDisplay; - std::string tick_label; - S32 x; - S32 barw = mBarRect.getWidth(); - - tick_label = llformat("%.1f ms |", (F32)ms.value()*.25f); - x = mBarRect.mLeft + barw/4 - LLFontGL::getFontMonospace()->getWidth(tick_label); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, x, mBarRect.mTop, LLColor4::white, - LLFontGL::LEFT, LLFontGL::TOP); - - tick_label = llformat("%.1f ms |", (F32)ms.value()*.50f); - x = mBarRect.mLeft + barw/2 - LLFontGL::getFontMonospace()->getWidth(tick_label); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, x, mBarRect.mTop, LLColor4::white, - LLFontGL::LEFT, LLFontGL::TOP); - - tick_label = llformat("%.1f ms |", (F32)ms.value()*.75f); - x = mBarRect.mLeft + (barw*3)/4 - LLFontGL::getFontMonospace()->getWidth(tick_label); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, x, mBarRect.mTop, LLColor4::white, - LLFontGL::LEFT, LLFontGL::TOP); - - tick_label = llformat( "%d ms |", (U32)ms.value()); - x = mBarRect.mLeft + barw - LLFontGL::getFontMonospace()->getWidth(tick_label); - LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, x, mBarRect.mTop, LLColor4::white, - LLFontGL::LEFT, LLFontGL::TOP); - } -} - -void LLFastTimerView::drawBorders( S32 y, const S32 x_start, S32 bar_height, S32 dy ) -{ - // Draw borders - { - S32 by = y + 6 + (S32)LLFontGL::getFontMonospace()->getLineHeight(); - - //heading - gl_rect_2d(x_start-5, by, getRect().getWidth()-5, y+5, LLColor4::grey, false); - - //tree view - gl_rect_2d(5, by, x_start-10, 5, LLColor4::grey, false); - - by = y + 5; - //average bar - gl_rect_2d(x_start-5, by, getRect().getWidth()-5, by-bar_height-dy-5, LLColor4::grey, false); - - by -= bar_height*2+dy; - - //current frame bar - gl_rect_2d(x_start-5, by, getRect().getWidth()-5, by-bar_height-dy-2, LLColor4::grey, false); - - by -= bar_height+dy+1; - - //history bars - gl_rect_2d(x_start-5, by, getRect().getWidth()-5, LINE_GRAPH_HEIGHT-bar_height-dy-2, LLColor4::grey, false); - - by = LINE_GRAPH_HEIGHT-dy; - - //line graph - //mGraphRect = LLRect(x_start-5, by, getRect().getWidth()-5, 5); - - gl_rect_2d(mGraphRect, false); - } -} - -void LLFastTimerView::updateTotalTime() -{ - switch(mDisplayMode) - { - case 0: - mTotalTimeDisplay = mRecording.getPeriodMean(FTM_FRAME, RUNNING_AVERAGE_WIDTH)*2; - break; - case 1: - mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME); - break; - case 2: - // Calculate the max total ticks for the current history - mTotalTimeDisplay = mRecording.getPeriodMax(FTM_FRAME, 20); - break; - default: - mTotalTimeDisplay = F64Milliseconds(100); - break; - } - - mTotalTimeDisplay = LLUnits::Milliseconds::fromValue(llceil((F32)mTotalTimeDisplay.valueInUnits() / 20.f) * 20.f); -} - -void LLFastTimerView::drawBars() -{ - LL_PROFILE_ZONE_SCOPED; - LLLocalClipRect clip(mBarRect); - - S32 bar_height = mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2); - const S32 vpad = llmax(1, bar_height / 4); // spacing between bars - bar_height -= vpad; - - updateTotalTime(); - if (mTotalTimeDisplay <= (F32Seconds)0.0) return; - - drawTicks(); - const S32 bars_top = mBarRect.mTop - ((S32)LLFontGL::getFontMonospace()->getLineHeight() + 4); - drawBorders(bars_top, mBarRect.mLeft, bar_height, vpad); - - // Draw bars for each history entry - // Special: 0 = show running average - LLPointer bar_image = LLUI::getUIImage("Rounded_Square"); - - const S32 image_width = bar_image->getTextureWidth(); - const S32 image_height = bar_image->getTextureHeight(); - - gGL.getTexUnit(0)->bind(bar_image->getImage()); - { - const S32 histmax = (S32)mRecording.getNumRecordedPeriods(); - - // update widths - if (!mPauseHistory) - { - U32 bar_index = 0; - if (!mAverageTimerRow.mBars) - { - mAverageTimerRow.mBars = new TimerBar[LLTrace::BlockTimerStatHandle::instance_tracker_t::instanceCount()]; - } - updateTimerBarWidths(&FTM_FRAME, mAverageTimerRow, -1, bar_index); - updateTimerBarOffsets(&FTM_FRAME, mAverageTimerRow); - - for (S32 history_index = 1; history_index <= histmax; history_index++) - { - llassert(history_index <= mTimerBarRows.size()); - TimerBarRow& row = mTimerBarRows[history_index - 1]; - bar_index = 0; - if (!row.mBars) - { - row.mBars = new TimerBar[LLTrace::BlockTimerStatHandle::instance_tracker_t::instanceCount()]; - updateTimerBarWidths(&FTM_FRAME, row, history_index, bar_index); - updateTimerBarOffsets(&FTM_FRAME, row); - } - } - } - - // draw bars - LLRect frame_bar_rect; - frame_bar_rect.setLeftTopAndSize(mBarRect.mLeft, - bars_top, - (S32)ll_round((mAverageTimerRow.mBars[0].mTotalTime / mTotalTimeDisplay) * mBarRect.getWidth()), - bar_height); - mAverageTimerRow.mTop = frame_bar_rect.mTop; - mAverageTimerRow.mBottom = frame_bar_rect.mBottom; - drawBar(frame_bar_rect, mAverageTimerRow, image_width, image_height); - frame_bar_rect.translate(0, -(bar_height + vpad + bar_height)); - - for(S32 bar_index = mScrollIndex; bar_index < llmin(histmax, mScrollIndex + MAX_VISIBLE_HISTORY); ++bar_index) - { - llassert(bar_index < mTimerBarRows.size()); - TimerBarRow& row = mTimerBarRows[bar_index]; - row.mTop = frame_bar_rect.mTop; - row.mBottom = frame_bar_rect.mBottom; - frame_bar_rect.mRight = frame_bar_rect.mLeft - + (S32)ll_round((row.mBars[0].mTotalTime / mTotalTimeDisplay) * mBarRect.getWidth()); - drawBar(frame_bar_rect, row, image_width, image_height); - - frame_bar_rect.translate(0, -(bar_height + vpad)); - } - - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -} - -F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 history_index, U32& bar_index) -{ - LL_PROFILE_ZONE_SCOPED; - const F32Seconds self_time = history_index == -1 - ? mRecording.getPeriodMean(time_block->selfTime(), RUNNING_AVERAGE_WIDTH) - : mRecording.getPrevRecording(history_index).getSum(time_block->selfTime()); - - F32Seconds full_time = self_time; - - // reserve a spot for this bar to be rendered before its children - // even though we don't know its size yet - TimerBar& timer_bar = row.mBars[bar_index]; - bar_index++; - - for (BlockTimerStatHandle::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); it != end_it; ++it) - { - full_time += updateTimerBarWidths(*it, row, history_index, bar_index); - } - - timer_bar.mTotalTime = full_time; - timer_bar.mSelfTime = self_time; - timer_bar.mTimeBlock = time_block; - - return full_time; -} - -S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 timer_bar_index) -{ - LL_PROFILE_ZONE_SCOPED; - - TimerBar& timer_bar = row.mBars[timer_bar_index]; - const F32Seconds bar_time = timer_bar.mTotalTime - timer_bar.mSelfTime; - timer_bar.mChildrenStart = timer_bar.mSelfStart + timer_bar.mSelfTime / 2; - timer_bar.mChildrenEnd = timer_bar.mChildrenStart + timer_bar.mTotalTime - timer_bar.mSelfTime; - - if (timer_bar_index == 0) - { - timer_bar.mSelfStart = F32Seconds(0.f); - timer_bar.mSelfEnd = bar_time; - } - - //now loop through children and figure out portion of bar image covered by each bar, now that we know the - //sum of all children - F32 bar_fraction_start = 0.f; - TimerBar* last_child_timer_bar = NULL; - - bool first_child = true; - for (BlockTimerStatHandle::child_iter it = time_block->beginChildren(), end_it = time_block->endChildren(); - it != end_it; - ++it) - { - timer_bar_index++; - - TimerBar& child_timer_bar = row.mBars[timer_bar_index]; - BlockTimerStatHandle* child_time_block = *it; - - if (last_child_timer_bar) - { - last_child_timer_bar->mLastChild = false; - } - child_timer_bar.mLastChild = true; - last_child_timer_bar = &child_timer_bar; - - child_timer_bar.mFirstChild = first_child; - if (first_child) - { - first_child = false; - } - - child_timer_bar.mStartFraction = bar_fraction_start; - child_timer_bar.mEndFraction = bar_time > (S32Seconds)0 - ? bar_fraction_start + child_timer_bar.mTotalTime / bar_time - : 1.f; - child_timer_bar.mSelfStart = timer_bar.mChildrenStart - + child_timer_bar.mStartFraction - * (timer_bar.mChildrenEnd - timer_bar.mChildrenStart); - child_timer_bar.mSelfEnd = timer_bar.mChildrenStart - + child_timer_bar.mEndFraction - * (timer_bar.mChildrenEnd - timer_bar.mChildrenStart); - - timer_bar_index = updateTimerBarOffsets(child_time_block, row, timer_bar_index); - - bar_fraction_start = child_timer_bar.mEndFraction; - } - return timer_bar_index; -} - -S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, bool visible, S32 bar_index) -{ - LL_PROFILE_ZONE_SCOPED; - TimerBar& timer_bar = row.mBars[bar_index]; - LLTrace::BlockTimerStatHandle* time_block = timer_bar.mTimeBlock; - - hovered |= mHoverID == time_block; - - // animate scale of bar when hovering over that particular timer - if (visible && (F32)bar_rect.getWidth() * (timer_bar.mEndFraction - timer_bar.mStartFraction) > 2.f) - { - LLRect render_rect(bar_rect); - S32 scale_offset = 0; - if (mHoverID == time_block) - { - scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f); - render_rect.mTop += scale_offset; - render_rect.mBottom -= scale_offset; - } - - llassert(time_block->getIndex() < sTimerColors.size()); - LLColor4 color = sTimerColors[time_block->getIndex()]; - if (!hovered) color = lerp(color, LLColor4::grey, 0.2f); - gGL.color4fv(color.mV); - gl_segmented_rect_2d_fragment_tex(render_rect, - image_width, image_height, - 16, - timer_bar.mStartFraction, timer_bar.mEndFraction); - } - - LLRect children_rect; - children_rect.mLeft = (S32)ll_round(timer_bar.mChildrenStart / mTotalTimeDisplay * (F32)mBarRect.getWidth()) + mBarRect.mLeft; - children_rect.mRight = (S32)ll_round(timer_bar.mChildrenEnd / mTotalTimeDisplay * (F32)mBarRect.getWidth()) + mBarRect.mLeft; - - if (bar_rect.getHeight() > MIN_BAR_HEIGHT) - { - // shrink as we go down a level - children_rect.mTop = bar_rect.mTop - 1; - children_rect.mBottom = bar_rect.mBottom + 1; - } - else - { - children_rect.mTop = bar_rect.mTop; - children_rect.mBottom = bar_rect.mBottom; - } - - bool children_visible = visible && !time_block->getTreeNode().mCollapsed; - - bar_index++; - const auto num_bars = LLTrace::BlockTimerStatHandle::instance_tracker_t::instanceCount(); - if (bar_index < num_bars && row.mBars[bar_index].mFirstChild) - { - bool is_last = false; - do - { - is_last = row.mBars[bar_index].mLastChild; - bar_index = drawBar(children_rect, row, image_width, image_height, hovered, children_visible, bar_index); - } - while(!is_last && bar_index < num_bars); - } - - return bar_index; -} diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h deleted file mode 100644 index 2950457c2bf..00000000000 --- a/indra/newview/llfasttimerview.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - * @file llfasttimerview.h - * @brief LLFastTimerView class definition - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_LLFASTTIMERVIEW_H -#define LL_LLFASTTIMERVIEW_H - -#include "llfloater.h" -#include "llfasttimer.h" -#include "llunits.h" -#include "lltracerecording.h" -#include - -class LLScrollbar; - -class LLFastTimerView : public LLFloater -{ -public: - LLFastTimerView(const LLSD&); - ~LLFastTimerView(); - bool postBuild(); - - static bool sAnalyzePerformance; - - static void outputAllMetrics(); - static void doAnalysis(std::string baseline, std::string target, std::string output); - -private: - static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ; - static LLSD analyzePerformanceLogDefault(std::istream& is) ; - static void exportCharts(const std::string& base, const std::string& target); - void onPause(); - -public: - - virtual bool handleMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleDoubleClick(S32 x, S32 y, MASK mask); - virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask); - virtual bool handleMouseUp(S32 x, S32 y, MASK mask); - virtual bool handleHover(S32 x, S32 y, MASK mask); - virtual bool handleToolTip(S32 x, S32 y, MASK mask); - virtual bool handleScrollWheel(S32 x, S32 y, LLScrollDelta delta); - virtual void draw(); - virtual void onOpen(const LLSD& key); - virtual void onClose(bool app_quitting); - LLTrace::BlockTimerStatHandle* getLegendID(S32 y); - -private: - void drawTicks(); - void drawLineGraph(); - void drawLegend(); - void drawHelp(S32 y); - void drawBorders( S32 y, const S32 x_start, S32 barh, S32 dy); - void drawBars(); - - void printLineStats(); - void generateUniqueColors(); - void updateTotalTime(); - - struct TimerBar - { - TimerBar() - : mTotalTime(0), - mSelfTime(0), - mStartFraction(0.f), - mEndFraction(1.f), - mFirstChild(false), - mLastChild(false) - {} - F32Seconds mTotalTime, - mSelfTime, - mChildrenStart, - mChildrenEnd, - mSelfStart, - mSelfEnd; - LLTrace::BlockTimerStatHandle* mTimeBlock; - bool mVisible, - mFirstChild, - mLastChild; - F32 mStartFraction, - mEndFraction; - }; - - struct TimerBarRow - { - TimerBarRow() - : mBottom(0), - mTop(0), - mBars(NULL) - {} - S32 mBottom, - mTop; - TimerBar* mBars; - }; - - F32Seconds updateTimerBarWidths(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 history_index, U32& bar_index); - S32 updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 timer_bar_index = 0); - S32 drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered = false, bool visible = true, S32 bar_index = 0); - void setPauseState(bool pause_state); - - std::deque mTimerBarRows; - TimerBarRow mAverageTimerRow; - - enum EDisplayType - { - DISPLAY_TIME, - DISPLAY_CALLS, - DISPLAY_HZ - } mDisplayType; - bool mPauseHistory; - F64Seconds mAllTimeMax, - mTotalTimeDisplay; - S32 mScrollIndex, - mHoverBarIndex, - mStatsIndex; - S32 mDisplayMode; - LLTrace::BlockTimerStatHandle* mHoverID; - LLTrace::BlockTimerStatHandle* mHoverTimer; - LLRect mToolTipRect, - mGraphRect, - mBarRect, - mLegendRect; - LLFrameTimer mHighlightTimer; - LLTrace::PeriodicRecording mRecording; - - LLScrollbar* mScrollBar; -}; - -#endif diff --git a/indra/newview/llfilteredwearablelist.cpp b/indra/newview/llfilteredwearablelist.cpp index 0f29cbbe3a3..11b32667666 100644 --- a/indra/newview/llfilteredwearablelist.cpp +++ b/indra/newview/llfilteredwearablelist.cpp @@ -92,11 +92,9 @@ void LLFilteredWearableListManager::populateIfNeeded() } } -LLTrace::BlockTimerStatHandle FTM_MANAGER_LIST_POPULATION("Manager List Population"); - void LLFilteredWearableListManager::populateList() { - LL_RECORD_BLOCK_TIME(FTM_MANAGER_LIST_POPULATION); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index a29bad6f8a2..f8ce9f64430 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -713,10 +713,9 @@ void LLFloaterIMSessionTab::updateUsedEmojis(LLWStringView text) } } -static LLTrace::BlockTimerStatHandle FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT("Build Conversation View"); void LLFloaterIMSessionTab::buildConversationViewParticipant() { - LL_RECORD_BLOCK_TIME(FTM_BUILD_CONVERSATION_VIEW_PARTICIPANT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // Clear the widget list since we are rebuilding afresh from the model conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); while (widget_it != mConversationsWidgets.end()) diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp index 1377526f695..edaf4f3e374 100644 --- a/indra/newview/llfloaterlagmeter.cpp +++ b/indra/newview/llfloaterlagmeter.cpp @@ -141,7 +141,7 @@ void LLFloaterLagMeter::draw() void LLFloaterLagMeter::determineClient() { - F32Milliseconds client_frame_time = LLTrace::get_frame_recording().getPeriodMean(LLStatViewer::FRAME_STACKTIME); + F32Milliseconds client_frame_time = LLTrace::get_frame_recording().getPeriodMean(LLStatViewer::FRAMETIME); bool find_cause = false; if (!gFocusMgr.getAppHasFocus()) @@ -198,7 +198,7 @@ void LLFloaterLagMeter::determineNetwork() // particular if the frame rate is low, because a low frame // rate is a sure recipe for bad ping times right now until // the network handlers are de-synched from the rendering. - F32Milliseconds client_frame_time = frame_recording.getPeriodMean(LLStatViewer::FRAME_STACKTIME); + F32Milliseconds client_frame_time = frame_recording.getPeriodMean(LLStatViewer::FRAMETIME); // Todo: account for LLPacketRing dropped packets? viewer drops those when it can't keep up if(packet_loss >= mNetworkPacketLossCritical) diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index a0621bb0157..f851d2edc91 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -35,7 +35,6 @@ // // class LLFolderViewModelInventory // -static LLTrace::BlockTimerStatHandle FTM_INVENTORY_SORT("Inventory Sort"); bool LLFolderViewModelInventory::startDrag(std::vector& items) { @@ -64,7 +63,7 @@ bool LLFolderViewModelInventory::startDrag(std::vector& void LLFolderViewModelInventory::sort( LLFolderViewFolder* folder ) { - LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SORT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (!folder->areChildrenInited() || !needsSort(folder->getViewModelItem())) return; diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 871c119c965..957d5c31886 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -807,6 +807,8 @@ struct IsGesturePlaying void LLGestureMgr::update() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER; + S32 i; for (i = 0; i < (S32)mPlaying.size(); ++i) { diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index d2d6ba7ae6b..91e6e96701e 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -46,11 +46,9 @@ LLHUDManager::~LLHUDManager() { } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_HUD_EFFECTS("Update Hud Effects"); - void LLHUDManager::updateEffects() { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_HUD_EFFECTS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; S32 i; for (i = 0; i < mHUDEffects.size(); i++) { diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index a489d6d32cc..81bab08888e 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -255,12 +255,10 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type) return hud_objectp; } -static LLTrace::BlockTimerStatHandle FTM_HUD_UPDATE("Update Hud"); - // static void LLHUDObject::updateAll() { - LL_RECORD_BLOCK_TIME(FTM_HUD_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; LLHUDText::updateAll(); LLHUDIcon::updateAll(); LLHUDNameTag::updateAll(); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 82eefb50acf..ebf87f1c716 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -734,11 +734,9 @@ void LLInventoryModelBackgroundFetch::onAISFolderCalback(const LLUUID& request_i } } -static LLTrace::BlockTimerStatHandle FTM_BULK_FETCH("Bulk Fetch"); - void LLInventoryModelBackgroundFetch::bulkFetchViaAis() { - LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. if (gDisconnected) { @@ -1054,7 +1052,7 @@ void LLInventoryModelBackgroundFetch::bulkFetchViaAis(const FetchQueueInfo& fetc // Bundle up a bunch of requests to send all at once. void LLInventoryModelBackgroundFetch::bulkFetch() { - LL_RECORD_BLOCK_TIME(FTM_BULK_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. //If there are items in mFetchQueue, we want to check the time since the last bulkFetch was //sent. If it exceeds our retry time, go ahead and fire off another batch. diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 742ab9cefe2..c2d79aa6141 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -37,11 +37,6 @@ LLSceneView* gSceneView = NULL; -//borrow this helper function from llfasttimerview.cpp -template -void removeOutliers(std::vector& data, F32 k); - - LLSceneView::LLSceneView(const LLRect& rect) : LLFloater(LLSD()) { diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 0cac7271ad0..bc3e6e8806b 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -195,7 +195,6 @@ #include "llxfermanager.h" #include "pipeline.h" #include "llappviewer.h" -#include "llfasttimerview.h" #include "llfloatermap.h" #include "llweb.h" #include "llvoiceclient.h" diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 42643fc2c94..e4b68b67334 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -54,7 +54,6 @@ #include "llcommandhandler.h" #include "llcompilequeue.h" -#include "llfasttimerview.h" #include "llfloater360capture.h" #include "llfloaterabout.h" #include "llfloateraddpaymentmethod.h" @@ -272,7 +271,6 @@ class LLFloaterOpenHandler : public LLCommandHandler { const std::list blacklist_untrusted = { "360capture", - "block_timers", "add_payment_method", "appearance", "associate_listing", @@ -359,7 +357,6 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterAboutUtil::registerFloater(); LLFloaterReg::add("360capture", "floater_360capture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("block_timers", "floater_fast_timers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("add_payment_method", "floater_add_payment_method.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("appearance", "floater_my_appearance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 36b3d08ded6..381b1fa498c 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -638,15 +638,6 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi } } -static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc"); - - ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMedia::onIdle(void *dummy_arg) { @@ -2186,7 +2177,7 @@ void LLViewerMediaImpl::setMute(bool mute) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::updateVolume() { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME); + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; if(mMediaSource) { // always scale the volume by the global media volume @@ -2921,11 +2912,6 @@ bool LLViewerMediaImpl::canNavigateBack() } ////////////////////////////////////////////////////////////////////////////////////////// -static LLTrace::BlockTimerStatHandle FTM_MEDIA_DO_UPDATE("Do Update"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_GET_DATA("Get Data"); -static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage"); - - void LLViewerMediaImpl::update() { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE); @@ -3780,8 +3766,6 @@ bool LLViewerMediaImpl::isUpdated() return mIsUpdated ; } -static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Interest"); - void LLViewerMediaImpl::calculateInterest() { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 170273c6e92..1f0fd0ae507 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -754,10 +754,6 @@ class LLAdvancedToggleConsole : public view_listener_t { toggle_visibility(gDebugView->mDebugConsolep); } - else if ("fast timers" == console_type) - { - LLFloaterReg::toggleInstance("block_timers"); - } else if ("scene view" == console_type) { toggle_visibility(gSceneView); @@ -784,10 +780,6 @@ class LLAdvancedCheckConsole : public view_listener_t { new_value = get_visibility(gDebugView->mDebugConsolep); } - else if ("fast timers" == console_type) - { - new_value = LLFloaterReg::instanceVisible("block_timers"); - } else if ("scene view" == console_type) { new_value = get_visibility(gSceneView); diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 0017af79932..01303bc1f19 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -295,8 +295,6 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects"); - LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; @@ -405,7 +403,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, const EObjectUpdateType update_type, bool compressed) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; LLViewerObject *objectp; S32 num_objects; @@ -803,6 +801,8 @@ void LLViewerObjectList::setAllObjectDefaultTextures(U32 nChannel, bool fShowDef void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; + S32 i; LLViewerObject *objectp; diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index 1be62cafecc..c666663fd34 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -656,10 +656,10 @@ void LLViewerPartSim::shift(const LLVector3 &offset) } } -static LLTrace::BlockTimerStatHandle FTM_SIMULATE_PARTICLES("Simulate Particles"); - void LLViewerPartSim::updateSimulation() { + LL_PROFILE_ZONE_SCOPED; + static LLFrameTimer update_timer; const F32 dt = llmin(update_timer.getElapsedTimeAndResetF32(), 0.1f); @@ -669,8 +669,6 @@ void LLViewerPartSim::updateSimulation() return; } - LL_RECORD_BLOCK_TIME(FTM_SIMULATE_PARTICLES); - // Start at a random particle system so the same // particle system doesn't always get first pick at the // particles. Theoretically we'd want to do this in distance diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 27c1482e34c..7de74ab19f2 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -718,9 +718,6 @@ void LLViewerRegion::initStats() mAlive = false; // can become false if circuit disconnects } -static LLTrace::BlockTimerStatHandle FTM_CLEANUP_REGION_OBJECTS("Cleanup Region Objects"); -static LLTrace::BlockTimerStatHandle FTM_SAVE_REGION_CACHE("Save Region Cache"); - LLViewerRegion::~LLViewerRegion() { LL_PROFILE_ZONE_SCOPED; @@ -737,7 +734,6 @@ LLViewerRegion::~LLViewerRegion() LLViewerPartSim::getInstance()->cleanupRegion(this); { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_REGION_OBJECTS); gObjectList.killObjects(this); } @@ -751,7 +747,6 @@ LLViewerRegion::~LLViewerRegion() std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); { - LL_RECORD_BLOCK_TIME(FTM_SAVE_REGION_CACHE); saveObjectCache(); } @@ -807,6 +802,7 @@ void LLViewerRegion::loadObjectCache() void LLViewerRegion::saveObjectCache() { + LL_PROFILE_ZONE_SCOPED; if (!mCacheLoaded) { return; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 3929aee80a2..f7352c40076 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -50,7 +50,6 @@ #include "llversioninfo.h" #include "llfloatertools.h" #include "lldebugview.h" -#include "llfasttimerview.h" #include "llviewerregion.h" #include "llvoavatar.h" #include "llvoavatarself.h" @@ -240,7 +239,6 @@ LLTrace::EventStatHandle > AGENT_POSITION_SNAP("age LLTrace::EventStatHandle<> LOADING_WEARABLES_LONG_DELAY("loadingwearableslongdelay", "Wearables took too long to load"); LLTrace::EventStatHandle REGION_CROSSING_TIME("regioncrossingtime", "CROSSING_AVG"), - FRAME_STACKTIME("framestacktime", "FRAME_SECS"), UPDATE_STACKTIME("updatestacktime", "UPDATE_SECS"), NETWORK_STACKTIME("networkstacktime", "NETWORK_SECS"), IMAGE_STACKTIME("imagestacktime", "IMAGE_SECS"), @@ -489,8 +487,6 @@ void update_statistics() typedef LLTrace::StatType::instance_tracker_t stat_type_t; - record(LLStatViewer::FRAME_STACKTIME, last_frame_recording.getSum(*stat_type_t::getInstance("Frame"))); - if (gAgent.getRegion() && isAgentAvatarValid()) { LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 8ec0dd00247..d76aa00e1b7 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -215,8 +215,21 @@ extern LLTrace::EventStatHandle > AGENT_POSITION_SN extern LLTrace::EventStatHandle<> LOADING_WEARABLES_LONG_DELAY; +extern LLTrace::SampleStatHandle FRAMETIME_JITTER, + FRAMETIME, + FRAMETIME_JITTER_99TH, + FRAMETIME_JITTER_95TH, + FRAMETIME_99TH, + FRAMETIME_95TH, + FRAMETIME_JITTER_CUMULATIVE, + FRAMETIME_JITTER_STDDEV, + FRAMETIME_STDDEV; + +extern LLTrace::SampleStatHandle FRAMETIME_JITTER_EVENTS, + FRAMETIME_JITTER_EVENTS_PER_MINUTE, + FRAMETIME_JITTER_EVENTS_LAST_MINUTE; + extern LLTrace::EventStatHandle REGION_CROSSING_TIME, - FRAME_STACKTIME, UPDATE_STACKTIME, NETWORK_STACKTIME, IMAGE_STACKTIME, diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 7677178d01b..62062de7550 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -417,8 +417,6 @@ void normalized_float_to_string(const float x, char *out_str) // LLDebugText // -static LLTrace::BlockTimerStatHandle FTM_DISPLAY_DEBUG_TEXT("Display Debug Text"); - class LLDebugText { private: @@ -962,7 +960,7 @@ class LLDebugText void draw() { - LL_RECORD_BLOCK_TIME(FTM_DISPLAY_DEBUG_TEXT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // Camera matrix text is hard to see again a white background // Add a dark background underneath the matrices for readability (contrast) @@ -4364,10 +4362,9 @@ void LLViewerWindow::updateKeyboardFocus() } } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_WORLD_VIEW("Update World View"); void LLViewerWindow::updateWorldViewRect(bool use_full_window) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_WORLD_VIEW); + LL_PROFILE_ZONE_SCOPED; // start off using whole window to render world LLRect new_world_rect = mWindowRectRaw; @@ -6430,11 +6427,9 @@ void LLViewerWindow::requestResolutionUpdate() mResDirty = true; } -static LLTrace::BlockTimerStatHandle FTM_WINDOW_CHECK_SETTINGS("Window Settings"); - void LLViewerWindow::checkSettings() { - LL_RECORD_BLOCK_TIME(FTM_WINDOW_CHECK_SETTINGS); + LL_PROFILE_ZONE_SCOPED; if (mStatesDirty) { gGL.refreshState(); diff --git a/indra/newview/llvlmanager.cpp b/indra/newview/llvlmanager.cpp index f4c2c27cee2..07c9b548a53 100644 --- a/indra/newview/llvlmanager.cpp +++ b/indra/newview/llvlmanager.cpp @@ -80,6 +80,8 @@ void LLVLManager::addLayerData(LLVLData *vl_datap, const S32Bytes mesg_size) void LLVLManager::unpackData(const S32 num_packets) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + static LLFrameTimer decode_timer; S32 i; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index b4f2dca5a98..3ca3081340d 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -403,11 +403,9 @@ LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_GRASS("Update Grass"); - bool LLVOGrass::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_GRASS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; dirtySpatialGroup(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index b335217b0ee..af6fb3283ef 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -266,40 +266,6 @@ bool gDebugPipeline = false; LLPipeline gPipeline; const LLMatrix4* gGLLastMatrix = NULL; -LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY("Render Geometry"); -LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS("Grass"); -LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE("Invisible"); -LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY("Shiny"); -LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE("Simple"); -LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN("Terrain"); -LLTrace::BlockTimerStatHandle FTM_RENDER_TREES("Trees"); -LLTrace::BlockTimerStatHandle FTM_RENDER_UI("UI"); -LLTrace::BlockTimerStatHandle FTM_RENDER_WATER("Water"); -LLTrace::BlockTimerStatHandle FTM_RENDER_WL_SKY("Windlight Sky"); -LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA("Alpha Objects"); -LLTrace::BlockTimerStatHandle FTM_RENDER_CHARACTERS("Avatars"); -LLTrace::BlockTimerStatHandle FTM_RENDER_BUMP("Bump"); -LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS("Render Materials"); -LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT("Fullbright"); -LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW("Glow"); -LLTrace::BlockTimerStatHandle FTM_GEO_UPDATE("Geo Update"); -LLTrace::BlockTimerStatHandle FTM_POOLRENDER("RenderPool"); -LLTrace::BlockTimerStatHandle FTM_POOLS("Pools"); -LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); -LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLS("Pools (Deferred)"); -LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); -LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLS("Pools (Post)"); -LLTrace::BlockTimerStatHandle FTM_STATESORT("Sort Draw State"); -LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline"); -LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy"); -LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading"); - -LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD("HUD"); -LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D("3D"); -LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D("2D"); - -static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables"); - static LLStaticHashedString sTint("tint"); static LLStaticHashedString sAmbiance("ambiance"); static LLStaticHashedString sAlphaScale("alpha_scale"); @@ -2775,8 +2741,6 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& return res; } -static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); - // static bool LLPipeline::isWaterClip() { @@ -3128,10 +3092,8 @@ void LLPipeline::rebuildPriorityGroups() void LLPipeline::updateGeom(F32 max_dtime) { - LLTimer update_timer; - LLPointer drawablep; + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; - LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE); if (gCubeSnapshot) { return; @@ -7237,8 +7199,6 @@ void LLPipeline::bindScreenToTexture() } -static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom"); - void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 bufferIndex) { dst->bindTarget(); @@ -8818,15 +8778,15 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) void LLPipeline::renderFinalize() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + LL_PROFILE_GPU_ZONE("renderFinalize"); + llassert(!gCubeSnapshot); LLVertexBuffer::unbind(); LLGLState::checkStates(); assertInitialized(); - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); - LL_PROFILE_GPU_ZONE("renderFinalize"); - gGL.color4f(1, 1, 1, 1); LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -10333,17 +10293,6 @@ glm::mat4 look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up) return glm::make_mat4(ret); } -static LLTrace::BlockTimerStatHandle FTM_SHADOW_RENDER("Render Shadows"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA("Alpha Shadow"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_SIMPLE("Simple Shadow"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_GEOM("Shadow Geom"); - -static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_MASKED("Alpha Masked"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_BLEND("Alpha Blend"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass"); -static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked"); - void LLPipeline::renderShadow(const glm::mat4& view, const glm::mat4& proj, LLCamera& shadow_cam, LLCullResult& result, bool depth_clamp, bool do_cull) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); @@ -10803,9 +10752,6 @@ LLRenderTarget* LLPipeline::getSpotShadowTarget(U32 i) return &mSpotShadow[i]; } -static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); -static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_RENDER("Spot Shadow Render"); - // helper class for disabling occlusion culling for the current stack frame class LLDisableOcclusionCulling { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index f7cc8dd10c3..ad58b799018 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -68,31 +68,6 @@ bool LLRayAABB(const LLVector3 ¢er, const LLVector3 &size, const LLVector3& bool setup_hud_matrices(); // use whole screen to render hud bool setup_hud_matrices(const LLRect& screen_region); // specify portion of screen (in pixels) to render hud attachments from (for picking) - -extern LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_TREES; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_WATER; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_WL_SKY; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_CHARACTERS; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_BUMP; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW; -extern LLTrace::BlockTimerStatHandle FTM_STATESORT; -extern LLTrace::BlockTimerStatHandle FTM_PIPELINE; -extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY; - -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D; - class LLPipeline { public: diff --git a/indra/newview/rlveffects.cpp b/indra/newview/rlveffects.cpp index 90896f5b20f..63be4561de2 100644 --- a/indra/newview/rlveffects.cpp +++ b/indra/newview/rlveffects.cpp @@ -374,11 +374,9 @@ void RlvSphereEffect::renderPass(LLGLSLShader* pShader, const LLShaderEffectPara } } -LLTrace::BlockTimerStatHandle FTM_RLV_EFFECT_SPHERE("Post-process (RLVa sphere)"); - void RlvSphereEffect::run(const LLVisualEffectParams* pParams) { - LL_RECORD_BLOCK_TIME(FTM_RLV_EFFECT_SPHERE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (gRlvSphereProgram.isComplete()) { LLGLDepthTest depth(GL_FALSE, GL_FALSE); diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml index 3bdcb759a2f..f375a9f9704 100644 --- a/indra/newview/skins/default/xui/da/menu_viewer.xml +++ b/indra/newview/skins/default/xui/da/menu_viewer.xml @@ -204,7 +204,6 @@ - diff --git a/indra/newview/skins/default/xui/de/floater_fast_timers.xml b/indra/newview/skins/default/xui/de/floater_fast_timers.xml deleted file mode 100644 index 4b5383c64d4..00000000000 --- a/indra/newview/skins/default/xui/de/floater_fast_timers.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - Pause - - - Rennen - - - - - - - - - - - - -