From b9fd20501e2cff8831832f00d7ca9fcfc0d9e801 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:37:46 +0200 Subject: #5356 Fix fast texture cache's mutex stall #2 --- indra/newview/llmeshrepository.cpp | 5 +++++ indra/newview/lltexturecache.cpp | 6 ++++-- indra/newview/lltexturecache.h | 4 ++-- indra/newview/llviewertexturelist.cpp | 20 ++++++++++++-------- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index ed342935ad..20bda5039d 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -3331,6 +3331,8 @@ void LLMeshRepoThread::notifyLoadedMeshes() loaded_queue.swap(mLoadedQ); mLoadedMutex->unlock(); + LL_PROFILE_ZONE_NAMED("notify loaded meshes"); + update_metrics = true; // Process the elements free of the lock @@ -3362,6 +3364,8 @@ void LLMeshRepoThread::notifyLoadedMeshes() unavil_queue.swap(mUnavailableQ); mLoadedMutex->unlock(); + LL_PROFILE_ZONE_NAMED("notify unavail meshes"); + update_metrics = true; // Process the elements free of the lock @@ -3380,6 +3384,7 @@ void LLMeshRepoThread::notifyLoadedMeshes() { if (mLoadedMutex->trylock()) { + LL_PROFILE_ZONE_NAMED("notify misc meshes"); std::deque> skin_info_q; std::deque skin_info_unavail_q; std::list decomp_q; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2e7f353e03..8c8734b52f 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -2048,7 +2048,7 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d LL_PROFILE_ZONE_NAMED("Read fast cache"); LLMutexLock lock(&mFastCacheMutex); - openFastCache(); + openFastCache(); // only reopens if needed, lasts 10 seconds mFastCachep->seek(APR_SET, offset); @@ -2079,7 +2079,9 @@ LLPointer LLTextureCache::readFromFastCache(const LLUUID& id, S32& d closeFastCache(); } - LLPointer raw = new LLImageRaw(data, head[0], head[1], head[2], true); + + // directly construct image from new buffer. + LLPointer raw = new LLImageRaw(data, head[0], head[1], head[2], true /*take ownership*/); return raw; } diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 42894383fd..a09bcc1572 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -148,7 +148,7 @@ public: U32 getMaxEntries() { return sCacheMaxEntries; }; bool isInCache(const LLUUID& id) ; bool isInLocal(const LLUUID& id) ; //not thread safe at the moment - + LLMutex* getFastCacheMutex() { return &mFastCacheMutex; } protected: // Accessed by LLTextureCacheWorker std::string getLocalFileName(const LLUUID& id); @@ -194,7 +194,7 @@ private: // Internal LLMutex mWorkersMutex; LLMutex mHeaderMutex; - LLMutex mHeaderIDMapMutex; + LLMutex mHeaderIDMapMutex; // To avoid deadlocks, never lock mFastCacheMutex after mHeaderIDMapMutex. LLMutex mListMutex; LLMutex mFastCacheMutex; LLAPRFile* mHeaderAPRFile; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 11ca3098fd..96962bbeae 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1191,15 +1191,19 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time) LLTimer timer; image_list_t::iterator enditer = mFastCacheList.begin(); - for (image_list_t::iterator iter = mFastCacheList.begin(); - iter != mFastCacheList.end();) { - image_list_t::iterator curiter = iter++; - enditer = iter; - LLViewerFetchedTexture *imagep = *curiter; - imagep->loadFromFastCache(); - if (timer.getElapsedTimeF32() > max_time) - break; + // prelock fast cache mutex to avoid waiting multiple times. + LLMutexLock cache_lock(LLAppViewer::getTextureCache()->getFastCacheMutex()); + for (image_list_t::iterator iter = mFastCacheList.begin(); + iter != mFastCacheList.end();) + { + image_list_t::iterator curiter = iter++; + enditer = iter; + LLViewerFetchedTexture* imagep = *curiter; + imagep->loadFromFastCache(); + if (timer.getElapsedTimeF32() > max_time) + break; + } } mFastCacheList.erase(mFastCacheList.begin(), enditer); return timer.getElapsedTimeF32(); -- cgit v1.3