diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 955558e56e..30855fc823 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -875,8 +875,8 @@ LLMeshRepoThread::LLMeshRepoThread() // Lod processing is expensive due to the number of requests // and a need to do expensive cacheOptimize(). - mLodThreadPool.reset(new LL::ThreadPool("MeshLodProcessing", 2)); - mLodThreadPool->start(); + mMeshThreadPool.reset(new LL::ThreadPool("MeshLodProcessing", 2)); + mMeshThreadPool->start(); } @@ -1473,9 +1473,18 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) LLFileSystem file(mesh_id, LLAssetType::AT_MESH); if (in_cache && file.getSize() >= disk_ofset + size) { - U8* buffer = getDiskCacheBuffer(size); + U8* buffer = new(std::nothrow) U8[size]; if (!buffer) { + LL_WARNS(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL; + + // Not sure what size is reasonable for skin info, + // but if 20MB allocation failed, we definetely have issues + const S32 MAX_SIZE = 30 * 1024 * 1024; //30MB + if (size < MAX_SIZE) + { + LLAppViewer::instance()->outOfMemorySoftQuit(); + } // else ignore failures for anomalously large data LLMutexLock locker(mLoadedMutex); mSkinUnavailableQ.emplace_back(mesh_id); return true; @@ -1493,12 +1502,68 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } if (!zero) - { //attempt to parse - if (skinInfoReceived(mesh_id, buffer, size)) + { + //attempt to parse + bool posted = mMeshThreadPool->getQueue().post( + [mesh_id, buffer, size] + () + { + if (!gMeshRepo.mThread->skinInfoReceived(mesh_id, buffer, size)) + { + // either header is faulty or something else overwrote the cache + S32 header_size = 0; + U32 header_flags = 0; + { + LL_DEBUGS(LOG_MESH) << "Mesh header for ID " << mesh_id << " cache mismatch." << LL_ENDL; + + LLMutexLock lock(gMeshRepo.mThread->mHeaderMutex); + + auto header_it = gMeshRepo.mThread->mMeshHeader.find(mesh_id); + if (header_it != gMeshRepo.mThread->mMeshHeader.end()) + { + LLMeshHeader& header = header_it->second; + // for safety just mark everything as missing + header.mSkinInCache = false; + header.mPhysicsConvexInCache = false; + header.mPhysicsMeshInCache = false; + for (S32 i = 0; i < LLModel::NUM_LODS; ++i) + { + header.mLodInCache[i] = false; + } + header_size = header.mHeaderSize; + header_flags = header.getFlags(); + } + } + + if (header_size > 0) + { + LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ_WRITE); + if (file.getMaxSize() >= CACHE_PREAMBLE_SIZE) + { + write_preamble(file, header_size, header_flags); + } + } + + { + LLMutexLock lock(gMeshRepo.mThread->mMutex); + UUIDBasedRequest req(mesh_id); + gMeshRepo.mThread->mSkinRequests.push_back(req); + } + } + delete[] buffer; + }); + if (posted) { + // lambda owns buffer + return true; + } + else if (skinInfoReceived(mesh_id, buffer, size)) + { + delete[] buffer; return true; } } + delete[] buffer; } //reading from cache failed for whatever reason, fetch from sim @@ -1938,7 +2003,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (!zero) { //attempt to parse - bool posted = mLodThreadPool->getQueue().post( + bool posted = mMeshThreadPool->getQueue().post( [mesh_params, mesh_id, lod, buffer, size] () { @@ -3733,7 +3798,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body && ((data != NULL) == (data_size > 0))) // if we have data but no size or have size but no data, something is wrong { LLMeshHandlerBase::ptr_t shrd_handler = shared_from_this(); - bool posted = gMeshRepo.mThread->mLodThreadPool->getQueue().post( + bool posted = gMeshRepo.mThread->mMeshThreadPool->getQueue().post( [shrd_handler, data, data_size] () { @@ -3750,7 +3815,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body else { // mesh thread dies later than event queue, so this is normal - LL_INFOS_ONCE(LOG_MESH) << "Failed to post work into mLodThreadPool" << LL_ENDL; + LL_INFOS_ONCE(LOG_MESH) << "Failed to post work into mMeshThreadPool" << LL_ENDL; processLod(data, data_size); } } @@ -4038,7 +4103,7 @@ void LLMeshRepository::shutdown() } mThread->mSignal->broadcast(); - mThread->mLodThreadPool->close(); + mThread->mMeshThreadPool->close(); while (!mThread->isStopped()) { diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 3a8b4fb5c5..15bc7575a9 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -495,7 +495,7 @@ class LLMeshRepoThread : public LLThread // workqueue for processing generic requests LL::WorkQueue mWorkQueue; // lods have their own thread due to costly cacheOptimize() calls - std::unique_ptr mLodThreadPool; + std::unique_ptr mMeshThreadPool; // llcorehttp library interface objects. LLCore::HttpStatus mHttpStatus;