diff options
31 files changed, 226 insertions, 164 deletions
diff --git a/doc/testplans/terrain_loading.md b/doc/testplans/terrain_loading.md index b84daf6f73..c1b170fcf8 100644 --- a/doc/testplans/terrain_loading.md +++ b/doc/testplans/terrain_loading.md @@ -1,4 +1,29 @@ -- Texture terrain should load -- PBR terrain should load if enabled +# Terrain Loading + +## Behavior overview + +- Texture terrain should load if textures are applied to the region, and no PBR Metallic Roughness materials are applied. +- PBR terrain should load if PBR materials are applied to the region, even if the RenderTerrainPBREnabled feature flag is disabled in debug settings. This setting only disables the display of PBR materials in the Region / Estate > Terrain UI. - Related subsystem: A change to the PBR terrain loading system may affect the texture terrain loading system and vice-versa -- Related subsystem: Minimaps should load if terrain loads (may take longer) +- Related subsystem: Minimap should load if terrain loads + - They may not finish loading at the same time + +## Implementation details + +This section is provided mainly for clarification of how the terrain loading system works. + +The simulator sends 4 terrain composition UUIDs to the viewer for the region. The viewer does not know ahead-of-time if the terrain composition uses textures or materials. Therefore, to expedite terrain loading, the viewer makes up to 8 "top-level" asset requests simultaneously: + +- Up to 4 texture asset requests, one for each UUID +- Up to 4 material asset requests, one for each UUID + +It is therefore expected that half of these asset lookups will fail. + +The viewer inspects the load success of these top-level assets to make the binary decision of whether to render all 4 texture assets or all 4 material assets. This determines the choice of composition for terrain both in-world and on the minimap. + +The minimap also attempts to wait for textures to partially load before it can render a tile for a given region: + +- When rendering texture terrain, the minimap attempts to wait for top-level texture assets to partially load +- When rendering PBR material terrain, the minimap attempts to wait for any base color/emissive textures in the materials to partially load, if they are present + +We don't make guarantees that the minimap tile will render for the region if any aforementioned required textures/materials fail to sufficiently load. However, the minimap may make a best-effort attempt to render the region by ignoring or replacing data. diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 6e988260a9..30aefa3134 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -128,8 +128,7 @@ void LLCommon::initClass() sAprInitialized = TRUE; } LLTimer::initClass(); - LLThreadSafeRefCount::initThreadSafeRefCount(); - assert_main_thread(); // Make sure we record the main thread + assert_main_thread(); // Make sure we record the main thread if (!sMasterThreadRecorder) { sMasterThreadRecorder = new LLTrace::ThreadRecorder(); @@ -143,7 +142,6 @@ void LLCommon::cleanupClass() delete sMasterThreadRecorder; sMasterThreadRecorder = NULL; LLTrace::set_master_thread_recorder(NULL); - LLThreadSafeRefCount::cleanupThreadSafeRefCount(); SUBSYSTEM_CLEANUP_DBG(LLTimer); if (sAprInitialized) { diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c13900f74a..219c65fbb8 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -61,6 +61,23 @@ #include <excpt.h> #endif +// static +bool LLCoros::on_main_coro() +{ + if (!LLCoros::instanceExists() || LLCoros::getName().empty()) + { + return true; + } + + return false; +} + +// static +bool LLCoros::on_main_thread_main_coro() +{ + return on_main_coro() && on_main_thread(); +} + // static LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller) { diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index fd878f20ad..00650a2454 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -94,6 +94,16 @@ class LL_COMMON_API LLCoros: public LLSingleton<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()) + static bool on_main_coro(); + + // For debugging, return true if on the main thread and not in a coroutine + // Non-thread-safe code in the main loop should be protected by + // llassert(LLCoros::on_main_thread_main_coro()) + static bool on_main_thread_main_coro(); + /// The viewer's use of the term "coroutine" became deeply embedded before /// the industry term "fiber" emerged to distinguish userland threads from /// simpler, more transient kinds of coroutines. Semantically they've diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 0f48ce16b2..74b138a53b 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -506,7 +506,7 @@ namespace LLError::TimeFunction mTimeFunction; Recorders mRecorders; - LLMutex mRecorderMutex; + LLCoros::Mutex mRecorderMutex; int mShouldLogCallCounter; @@ -1044,7 +1044,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); + LLCoros::LockType lock(s->mRecorderMutex); s->mRecorders.push_back(recorder); } @@ -1055,7 +1055,7 @@ namespace LLError return; } SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); + LLCoros::LockType lock(s->mRecorderMutex); s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), s->mRecorders.end()); } @@ -1104,7 +1104,7 @@ namespace LLError std::shared_ptr<RECORDER> findRecorder() { SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); + LLCoros::LockType lock(s->mRecorderMutex); return findRecorderPos<RECORDER>(s).first; } @@ -1115,7 +1115,7 @@ namespace LLError bool removeRecorder() { SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); + LLCoros::LockType lock(s->mRecorderMutex); auto found = findRecorderPos<RECORDER>(s); if (found.first) { @@ -1221,7 +1221,7 @@ namespace std::string escaped_message; - LLMutexLock lock(&s->mRecorderMutex); + LLCoros::LockType lock(s->mRecorderMutex); for (LLError::RecorderPtr& r : s->mRecorders) { if (!r->enabled()) diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 70931f3a65..8006f9d059 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -382,7 +382,7 @@ std::string LLEventPump::inventName(const std::string& pfx) void LLEventPump::clear() { - LLMutexLock lock(&mConnectionListMutex); + LLCoros::LockType lock(mConnectionListMutex); // Destroy the original LLStandardSignal instance, replacing it with a // whole new one. mSignal = std::make_shared<LLStandardSignal>(); @@ -394,7 +394,7 @@ void LLEventPump::reset() { // Resetting mSignal is supposed to disconnect everything on its own // But due to crash on 'reset' added explicit cleanup to get more data - LLMutexLock lock(&mConnectionListMutex); + LLCoros::LockType lock(mConnectionListMutex); ConnectionMap::const_iterator iter = mConnections.begin(); ConnectionMap::const_iterator end = mConnections.end(); while (iter!=end) @@ -419,7 +419,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL return LLBoundListener(); } - LLMutexLock lock(&mConnectionListMutex); + LLCoros::LockType lock(mConnectionListMutex); float nodePosition = 1.0; @@ -582,7 +582,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL LLBoundListener LLEventPump::getListener(const std::string& name) { - LLMutexLock lock(&mConnectionListMutex); + LLCoros::LockType lock(mConnectionListMutex); ConnectionMap::const_iterator found = mConnections.find(name); if (found != mConnections.end()) { @@ -594,7 +594,7 @@ LLBoundListener LLEventPump::getListener(const std::string& name) void LLEventPump::stopListening(const std::string& name) { - LLMutexLock lock(&mConnectionListMutex); + LLCoros::LockType lock(mConnectionListMutex); ConnectionMap::iterator found = mConnections.find(name); if (found != mConnections.end()) { diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index bebcfacdcb..df54a6546d 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -61,6 +61,7 @@ #include "llstl.h" #include "llexception.h" #include "llhandle.h" +#include "llcoros.h" /*==========================================================================*| // override this to allow binding free functions with more parameters @@ -601,7 +602,7 @@ private: LLHandle<LLEventPumps> mRegistry; std::string mName; - LLMutex mConnectionListMutex; + LLCoros::Mutex mConnectionListMutex; protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h index 554cf48a4c..b3bef7520b 100644 --- a/indra/llcommon/llfixedbuffer.h +++ b/indra/llcommon/llfixedbuffer.h @@ -33,6 +33,7 @@ #include "llstring.h" #include "llthread.h" #include "llerrorcontrol.h" +#include "llcoros.h" // fixed buffer implementation class LL_COMMON_API LLFixedBuffer : public LLLineBuffer @@ -58,7 +59,7 @@ protected: void addWLine(const LLWString& line); protected: - LLMutex mMutex ; + LLCoros::Mutex mMutex ; }; #endif //LL_FIXED_BUFFER_H diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..5d93d6e72b 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -28,6 +28,7 @@ #include "llmutex.h" #include "llthread.h" #include "lltimer.h" +#include "llcoros.h" //============================================================================ @@ -44,7 +45,17 @@ LLMutex::~LLMutex() void LLMutex::lock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + + // LLMutex is not coroutine aware and should not be used from a coroutine + // If your code is running in a coroutine, you should use LLCoros::Mutex instead + // NOTE: If the stack trace you're staring at contains non-thread-safe code, + // you should use LLAppViewer::instance().postToMainThread() to shuttle execution + // back to the main loop. + // NOTE: If you got here from seeing this assert in your log and you're not seeing + // a stack trace that points here, put a breakpoint in on_main_coro and try again. + llassert(LLCoros::on_main_coro()); + if(isSelfLocked()) { //redundant lock mCount++; @@ -66,7 +77,8 @@ void LLMutex::lock() void LLMutex::unlock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + if (mCount > 0) { //not the root unlock mCount--; @@ -111,7 +123,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if(isSelfLocked()) { //redundant lock mCount++; diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 15e7175fc8..109c29c0c9 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -89,13 +89,6 @@ private: class LL_COMMON_API LLThreadSafeRefCount { -public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex - -private: - static LLMutex* sMutex; - protected: virtual ~LLThreadSafeRefCount(); // use unref() diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index cd4975d9d3..ef66c36827 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -421,30 +421,6 @@ void LLThread::unlockData() //============================================================================ -//---------------------------------------------------------------------------- - -//static -LLMutex* LLThreadSafeRefCount::sMutex = 0; - -//static -void LLThreadSafeRefCount::initThreadSafeRefCount() -{ - if (!sMutex) - { - sMutex = new LLMutex(); - } -} - -//static -void LLThreadSafeRefCount::cleanupThreadSafeRefCount() -{ - delete sMutex; - sMutex = NULL; -} - - -//---------------------------------------------------------------------------- - LLThreadSafeRefCount::LLThreadSafeRefCount() : mRef(0) { diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index f7a9f55685..314e7f0217 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -45,6 +45,7 @@ #include "llcorehttputil.h" #include "llexception.h" #include "stringize.h" +#include "workqueue.h" #include <map> #include <set> @@ -179,19 +180,26 @@ void LLAvatarNameCache::requestAvatarNameCache_(std::string url, std::vector<LLU if (LLAvatarNameCache::instanceExists()) { - if (!success) - { // on any sort of failure add dummy records for any agent IDs - // in this request that we do not have cached already - std::vector<LLUUID>::const_iterator it = agentIds.begin(); - for (; it != agentIds.end(); ++it) - { - const LLUUID& agent_id = *it; - LLAvatarNameCache::getInstance()->handleAgentError(agent_id); - } - return; - } + // dispatch handler execution back to mainloop + auto workqueue = LL::WorkQueue::getInstance("mainloop"); - LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults); + if (workqueue) + { + workqueue->post([=]() + { + if (!success) + { // on any sort of failure add dummy records for any agent IDs + // in this request that we do not have cached already + for (const auto& agent_id : agentIds) + { + LLAvatarNameCache::getInstance()->handleAgentError(agent_id); + } + return; + } + + LLAvatarNameCache::getInstance()->handleAvNameCacheSuccess(results, httpResults); + }); + } } } catch (const LLCoros::Stop&) diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp index f5966b71de..a28f6c648f 100644 --- a/indra/llplugin/llpluginprocessparent.cpp +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -34,7 +34,6 @@ #include "llpluginmessageclasses.h" #include "llsdserialize.h" #include "stringize.h" - #include "llapr.h" //virtual @@ -46,7 +45,7 @@ LLPluginProcessParentOwner::~LLPluginProcessParentOwner() bool LLPluginProcessParent::sUseReadThread = false; apr_pollset_t *LLPluginProcessParent::sPollSet = NULL; bool LLPluginProcessParent::sPollsetNeedsRebuild = false; -LLMutex *LLPluginProcessParent::sInstancesMutex; +LLCoros::Mutex *LLPluginProcessParent::sInstancesMutex; LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances; LLThread *LLPluginProcessParent::sReadThread = NULL; @@ -106,7 +105,7 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner): { if(!sInstancesMutex) { - sInstancesMutex = new LLMutex(); + sInstancesMutex = new LLCoros::Mutex(); } mOwner = owner; @@ -176,7 +175,7 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent // Don't add to the global list until fully constructed. { - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); sInstances.insert(mapInstances_t::value_type(that.get(), that)); } @@ -186,7 +185,7 @@ LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParent /*static*/ void LLPluginProcessParent::shutdown() { - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); mapInstances_t::iterator it; for (it = sInstances.begin(); it != sInstances.end(); ++it) @@ -244,7 +243,7 @@ bool LLPluginProcessParent::pollTick() { // this grabs a copy of the smart pointer to ourselves to ensure that we do not // get destroyed until after this method returns. - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); mapInstances_t::iterator it = sInstances.find(this); if (it != sInstances.end()) that = (*it).second; @@ -263,7 +262,7 @@ void LLPluginProcessParent::removeFromProcessing() // Remove from the global list before beginning destruction. { // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll() - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); { LLMutexLock lock2(&mIncomingQueueMutex); sInstances.erase(this); @@ -845,7 +844,7 @@ void LLPluginProcessParent::updatePollset() return; } - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); if(sPollSet) { @@ -968,7 +967,7 @@ void LLPluginProcessParent::poll(F64 timeout) mapInstances_t::iterator it; { - LLMutexLock lock(sInstancesMutex); + LLCoros::LockType lock(*sInstancesMutex); it = sInstances.find(thatId); if (it != sInstances.end()) that = (*it).second; diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h index 01627925d7..2f9dc921ea 100644 --- a/indra/llplugin/llpluginprocessparent.h +++ b/indra/llplugin/llpluginprocessparent.h @@ -207,7 +207,7 @@ private: apr_pollfd_t mPollFD; static apr_pollset_t *sPollSet; static bool sPollsetNeedsRebuild; - static LLMutex *sInstancesMutex; + static LLCoros::Mutex *sInstancesMutex; static mapInstances_t sInstances; static void dirtyPollSet(); static void updatePollset(); diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 0b20ff6230..636e13719a 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -328,7 +328,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) return FALSE; } } - shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels-1, 1); + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels, 1); } } diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp index 8fc2978bdd..6a44108741 100644 --- a/indra/llui/llconsole.cpp +++ b/indra/llui/llconsole.cpp @@ -380,7 +380,7 @@ void LLConsole::updateClass() void LLConsole::update() { { - LLMutexLock lock(&mMutex); + LLCoros::LockType lock(mMutex); while (!mLines.empty()) { diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e42906e78b..e1eeefa755 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -10712,38 +10712,49 @@ <integer>3</integer> </map> <key>RenderReflectionRes</key> - <map> - <key>Comment</key> - <string>Reflection map resolution.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>64</integer> - </map> - <key>RenderResolutionDivisor</key> - <map> - <key>Comment</key> - <string>Divisor for rendering 3D scene at reduced resolution.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>1</integer> - </map> - <key>RenderShaderLightingMaxLevel</key> - <map> - <key>Comment</key> - <string>Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.)</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>S32</string> - <key>Value</key> - <integer>3</integer> - </map> + <map> + <key>Comment</key> + <string>Reflection map resolution.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>64</integer> + </map> + <key>RenderReservedTextureIndices</key> + <map> + <key>Comment</key> + <string>Count of texture indices to reserve for shadow and reflection maps when using indexed texture rendering. Probably only want to set from the login screen.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>14</integer> + </map> + <key>RenderResolutionDivisor</key> + <map> + <key>Comment</key> + <string>Divisor for rendering 3D scene at reduced resolution.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RenderShaderLightingMaxLevel</key> + <map> + <key>Comment</key> + <string>Max lighting level to use in the shader (class 3 is default, 2 is less lights, 1 is sun/moon only. Works around shader compiler bugs on certain platforms.)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>3</integer> + </map> <key>RenderSkyAutoAdjustLegacy</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl index 183354b9bd..6ef556d7e8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/moonF.glsl @@ -55,7 +55,7 @@ void main() frag_data[0] = vec4(0); frag_data[1] = vec4(0.0); - frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_HAS_ATMOS); + frag_data[2] = vec4(0.0, 0.0, 0.0, GBUFFER_FLAG_SKIP_ATMOS); frag_data[3] = vec4(c.rgb, c.a); // Added and commented out for a ground truth. Do not uncomment - Geenz diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 90f9b38f2d..c966f9cbcc 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5200,6 +5200,11 @@ void LLAppViewer::updateNameLookupUrl(const LLViewerRegion * regionp) } } +void LLAppViewer::postToMainCoro(const LL::WorkQueue::Work& work) +{ + gMainloopWork.post(work); +} + void LLAppViewer::idleNameCache() { // Neither old nor new name cache can function before agent has a region diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 9352dba06d..92976a70af 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -226,6 +226,9 @@ public: void updateNameLookupUrl(const LLViewerRegion* regionp); + // post given work to the "mainloop" work queue for handling on the main thread + void postToMainCoro(const LL::WorkQueue::Work& work); + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index b95b971890..ba9ba4dc64 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -236,8 +236,6 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U !avatar->isControlAvatar() && // Not part of an animated object avatar->getObjectHost() == regionp->getHost()) // Ensure it's on the same region { - avatar->calculateUpdateRenderComplexity(); // Make sure the numbers are up-to-date - LLSD info = LLSD::emptyMap(); U32 avatar_complexity = avatar->getVisualComplexity(); if (avatar_complexity > 0) diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 9418cead76..fd27010877 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -478,7 +478,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material) } } } - + return tex_setup; } @@ -668,7 +668,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; if ((bool)params.mAvatar != rigged) @@ -814,9 +814,10 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) current_shader->setMinimumAlpha(0.f); reset_minimum_alpha = true; } - + params.mVertexBuffer->setBuffer(); params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + stop_glerror(); if (reset_minimum_alpha) { diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 24df11c158..518310476b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -699,6 +699,8 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 void LLBumpImageList::updateImages() { + llassert(LLCoros::on_main_thread_main_coro()); // This code is not thread safe + for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) { LLViewerTexture* image = iter->second; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 69e43bb458..ccee57cf69 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -1855,7 +1855,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, S32* vp = (S32*) &val; *vp = index; - llassert(index <= LLGLSLShader::sIndexedTextureChannels-1); + llassert(index < LLGLSLShader::sIndexedTextureChannels); LLVector4Logical mask; mask.clear(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index a0324ca82a..486b652f07 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -334,10 +334,18 @@ void update_texture_fetch() void set_flags_and_update_appearance() { - LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); - LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); + // this may be called from a coroutine but has many side effects + // in non-thread-safe classes, post to main loop + auto work = []() + { + LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true); + LLAppearanceMgr::instance().updateAppearanceFromCOF(true, true, no_op); + + LLInventoryModelBackgroundFetch::instance().start(); + }; + + LLAppViewer::instance()->postToMainCoro(work); - LLInventoryModelBackgroundFetch::instance().start(); } // Returns false to skip other idle processing. Should only return diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 02108e861a..85891744ef 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -1667,7 +1667,7 @@ void LLViewerMediaImpl::destroyMediaSource() cancelMimeTypeProbe(); { - LLMutexLock lock(&mLock); // Delay tear-down while bg thread is updating + LLCoros::LockType lock(mLock); // Delay tear-down while bg thread is updating if(mMediaSource) { mMediaSource->setDeleteOK(true) ; @@ -2968,7 +2968,7 @@ bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - LLMutexLock lock(&mLock); // don't allow media source tear-down during update + LLCoros::LockType lock(mLock); // don't allow media source tear-down during update // wrap "data" in an LLImageRaw but do NOT make a copy LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true); diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 03899b6b8f..378297bf91 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -182,7 +182,7 @@ private: // Implementation functions not exported into header file class LLViewerMediaImpl - : public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler + : public LLMouseHandler, public LLThreadSafeRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler { LOG_CLASS(LLViewerMediaImpl); public: @@ -432,7 +432,7 @@ private: private: // a single media url with some data and an impl. std::shared_ptr<LLPluginClassMedia> mMediaSource; - LLMutex mLock; + LLCoros::Mutex mLock; F64 mZoomFactor; LLUUID mTextureId; bool mMovieImageHasMips; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 29dce088f5..210d5f84bd 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -2498,11 +2498,8 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features) } }; - auto workqueue = LL::WorkQueue::getInstance("mainloop"); - if (workqueue) - { - LL::WorkQueue::postMaybe(workqueue, work); - } + + LLAppViewer::instance()->postToMainCoro(work); } //this is called when the parent is not cacheable. diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 289c0d7567..5144b28ce9 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -423,7 +423,10 @@ void LLViewerShaderMgr::setShaders() static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); // when using indexed texture rendering, leave some texture units available for shadow and reflection maps - LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits-12, (S32) max_texture_index), 1); + static LLCachedControl<S32> reserved_texture_units(gSavedSettings, "RenderReservedTextureIndices", 14); + + LLGLSLShader::sIndexedTextureChannels = + llclamp<S32>(max_texture_index, 1, gGLManager.mNumTextureImageUnits-reserved_texture_units); reentrance = true; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 310c9ee297..9a0aae944c 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -6437,37 +6437,43 @@ void LLVivoxVoiceClient::notifyStatusObservers(LLVoiceClientStatusObserver::ESta } } } - + LL_DEBUGS("Voice") << " " << LLVoiceClientStatusObserver::status2string(status) << ", session URI " << getAudioSessionURI() << ", proximal is " << inSpatialChannel() << LL_ENDL; - for (status_observer_set_t::iterator it = mStatusObservers.begin(); - it != mStatusObservers.end(); - ) - { - LLVoiceClientStatusObserver* observer = *it; - observer->onChange(status, getAudioSessionURI(), inSpatialChannel()); - // In case onError() deleted an entry. - it = mStatusObservers.upper_bound(observer); - } + // this function is called from a coroutine, shuttle application hook back to main loop + auto work = [=]() + { + for (status_observer_set_t::iterator it = mStatusObservers.begin(); + it != mStatusObservers.end(); + ) + { + LLVoiceClientStatusObserver* observer = *it; + observer->onChange(status, getAudioSessionURI(), inSpatialChannel()); + // In case onError() deleted an entry. + it = mStatusObservers.upper_bound(observer); + } - // skipped to avoid speak button blinking - if ( status != LLVoiceClientStatusObserver::STATUS_JOINING - && status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL - && status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED) - { - bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); + // skipped to avoid speak button blinking + if (status != LLVoiceClientStatusObserver::STATUS_JOINING + && status != LLVoiceClientStatusObserver::STATUS_LEFT_CHANNEL + && status != LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED) + { + bool voice_status = LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); - gAgent.setVoiceConnected(voice_status); + gAgent.setVoiceConnected(voice_status); - if (voice_status) - { - LLFirstUse::speak(true); - } - } + if (voice_status) + { + LLFirstUse::speak(true); + } + } + }; + + LLAppViewer::instance()->postToMainCoro(work); } void LLVivoxVoiceClient::addObserver(LLFriendObserver* observer) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index b886b922de..1b816b88fb 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6248,19 +6248,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLViewerTexture* last_tex = NULL; - S32 texture_index_channels = 1; - - if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) - { - texture_index_channels = LLGLSLShader::sIndexedTextureChannels-1; //always reserve one for shiny for now just for simplicity; - } - - if (distance_sort) - { - texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; - } - - texture_index_channels = LLGLSLShader::sIndexedTextureChannels; + S32 texture_index_channels = LLGLSLShader::sIndexedTextureChannels; bool flexi = false; |