diff options
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rw-r--r-- | indra/newview/llmeshrepository.cpp | 520 |
1 files changed, 302 insertions, 218 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 5a6010d5e4..e8411dd573 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -77,6 +77,8 @@ #include "lluploaddialog.h" #include "llfloaterreg.h" +#include "boost/iostreams/device/array.hpp" +#include "boost/iostreams/stream.hpp" #include "boost/lexical_cast.hpp" #ifndef LL_WINDOWS @@ -138,7 +140,7 @@ // data copied // headerReceived() invoked // LLSD parsed -// mMeshHeader, mMeshHeaderSize updated +// mMeshHeader updated // scan mPendingLOD for LOD request // push LODRequest to mLODReqQ // ... @@ -246,7 +248,6 @@ // sActiveLODRequests mMutex rw.any.mMutex, ro.repo.none [1] // sMaxConcurrentRequests mMutex wo.main.none, ro.repo.none, ro.main.mMutex // mMeshHeader mHeaderMutex rw.repo.mHeaderMutex, ro.main.mHeaderMutex, ro.main.none [0] -// mMeshHeaderSize mHeaderMutex rw.repo.mHeaderMutex // mSkinRequests mMutex rw.repo.mMutex, ro.repo.none [5] // mSkinInfoQ mMutex rw.repo.mMutex, rw.main.mMutex [5] (was: [0]) // mDecompositionRequests mMutex rw.repo.mMutex, ro.repo.none [5] @@ -857,6 +858,12 @@ LLMeshRepoThread::~LLMeshRepoThread() mHttpRequestSet.clear(); mHttpHeaders.reset(); + while (!mSkinInfoQ.empty()) + { + delete mSkinInfoQ.front(); + mSkinInfoQ.pop_front(); + } + while (!mDecompositionQ.empty()) { delete mDecompositionQ.front(); @@ -946,7 +953,8 @@ void LLMeshRepoThread::run() else { // too many fails - mUnavailableQ.push(req); + LLMutexLock lock(mMutex); + mUnavailableQ.push_back(req); LL_WARNS() << "Failed to load " << req.mMeshParams << " , skip" << LL_ENDL; } } @@ -1022,37 +1030,42 @@ void LLMeshRepoThread::run() if (!mSkinRequests.empty()) { - std::set<UUIDBasedRequest> incomplete; - while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) - { - mMutex->lock(); - std::set<UUIDBasedRequest>::iterator iter = mSkinRequests.begin(); - UUIDBasedRequest req = *iter; - mSkinRequests.erase(iter); - mMutex->unlock(); - if (req.isDelayed()) - { - incomplete.insert(req); - } - else if (!fetchMeshSkinInfo(req.mId)) - { - if (req.canRetry()) - { - req.updateTime(); - incomplete.insert(req); - } - else - { - LL_DEBUGS() << "mSkinRequests failed: " << req.mId << LL_ENDL; - } - } - } + std::list<UUIDBasedRequest> incomplete; + while (!mSkinRequests.empty() && mHttpRequestSet.size() < sRequestHighWater) + { - if (!incomplete.empty()) - { - LLMutexLock locker(mMutex); - mSkinRequests.insert(incomplete.begin(), incomplete.end()); - } + mMutex->lock(); + auto req = mSkinRequests.front(); + mSkinRequests.pop_front(); + mMutex->unlock(); + if (req.isDelayed()) + { + incomplete.emplace_back(req); + } + else if (!fetchMeshSkinInfo(req.mId, req.canRetry())) + { + if (req.canRetry()) + { + req.updateTime(); + incomplete.emplace_back(req); + } + else + { + LLMutexLock locker(mMutex); + mSkinUnavailableQ.push_back(req); + LL_DEBUGS() << "mSkinReqQ failed: " << req.mId << LL_ENDL; + } + } + } + + if (!incomplete.empty()) + { + LLMutexLock locker(mMutex); + for (const auto& req : incomplete) + { + mSkinRequests.push_back(req); + } + } } // holding lock, try next list @@ -1151,7 +1164,7 @@ void LLMeshRepoThread::run() // Mutex: LLMeshRepoThread::mMutex must be held on entry void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) { - mSkinRequests.insert(UUIDBasedRequest(mesh_id)); + mSkinRequests.push_back(UUIDBasedRequest(mesh_id)); } // Mutex: LLMeshRepoThread::mMutex must be held on entry @@ -1177,10 +1190,13 @@ void LLMeshRepoThread::lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) { //could be called from any thread + const LLUUID& mesh_id = mesh_params.getSculptID(); LLMutexLock lock(mMutex); - mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); + LLMutexLock header_lock(mHeaderMutex); + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); if (iter != mMeshHeader.end()) { //if we have the header, request LOD byte range + LODRequest req(mesh_params, lod); { mLODReqQ.push(req); @@ -1190,8 +1206,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) else { HeaderRequest req(mesh_params); - - pending_lod_map::iterator pending = mPendingLOD.find(mesh_params); + pending_lod_map::iterator pending = mPendingLOD.find(mesh_id); if (pending != mPendingLOD.end()) { //append this lod request to existing header request @@ -1201,7 +1216,7 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) else { //if no header request is pending, fetch header mHeaderReqQ.push(req); - mPendingLOD[mesh_params].push_back(lod); + mPendingLOD[mesh_id].push_back(lod); } } } @@ -1304,7 +1319,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, } -bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) { if (!mHeaderMutex) @@ -1314,7 +1329,8 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) mHeaderMutex->lock(); - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + auto header_it = mMeshHeader.find(mesh_id); + if (header_it == mMeshHeader.end()) { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; @@ -1322,13 +1338,14 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) ++LLMeshRepository::sMeshRequestCount; bool ret = true; - U32 header_size = mMeshHeaderSize[mesh_id]; + U32 header_size = header_it->second.first; if (header_size > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["skin"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["skin"]["size"].asInteger(); + const LLSD& header = header_it->second.second; + S32 version = header["version"].asInteger(); + S32 offset = header_size + header["skin"]["offset"].asInteger(); + S32 size = header["skin"]["size"].asInteger(); mHeaderMutex->unlock(); @@ -1384,12 +1401,27 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) << LL_ENDL; ret = false; } - else + else if(can_retry) { handler->mHttpHandle = handle; mHttpRequestSet.insert(handler); } + else + { + LLMutexLock locker(mMutex); + mSkinUnavailableQ.emplace_back(mesh_id); + } } + else + { + LLMutexLock locker(mMutex); + mSkinUnavailableQ.emplace_back(mesh_id); + } + } + else + { + LLMutexLock locker(mMutex); + mSkinUnavailableQ.emplace_back(mesh_id); } } else @@ -1410,21 +1442,23 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) mHeaderMutex->lock(); - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + auto header_it = mMeshHeader.find(mesh_id); + if (header_it == mMeshHeader.end()) { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } ++LLMeshRepository::sMeshRequestCount; - U32 header_size = mMeshHeaderSize[mesh_id]; + U32 header_size = header_it->second.first; bool ret = true; if (header_size > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger(); + const auto& header = header_it->second.second; + S32 version = header["version"].asInteger(); + S32 offset = header_size + header["physics_convex"]["offset"].asInteger(); + S32 size = header["physics_convex"]["size"].asInteger(); mHeaderMutex->unlock(); @@ -1507,21 +1541,23 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) mHeaderMutex->lock(); - if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) + auto header_it = mMeshHeader.find(mesh_id); + if (header_it == mMeshHeader.end()) { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } ++LLMeshRepository::sMeshRequestCount; - U32 header_size = mMeshHeaderSize[mesh_id]; + U32 header_size = header_it->second.first; bool ret = true; if (header_size > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger(); + const auto& header = header_it->second.second; + S32 version = header["version"].asInteger(); + S32 offset = header_size + header["physics_mesh"]["offset"].asInteger(); + S32 size = header["physics_mesh"]["size"].asInteger(); mHeaderMutex->unlock(); @@ -1701,20 +1737,25 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, return false; } - mHeaderMutex->lock(); + const LLUUID& mesh_id = mesh_params.getSculptID(); + mHeaderMutex->lock(); + auto header_it = mMeshHeader.find(mesh_id); + if (header_it == mMeshHeader.end()) + { //we have no header info for this mesh, do nothing + mHeaderMutex->unlock(); + return false; + } ++LLMeshRepository::sMeshRequestCount; bool retval = true; - - LLUUID mesh_id = mesh_params.getSculptID(); - U32 header_size = mMeshHeaderSize[mesh_id]; - + U32 header_size = header_it->second.first; if (header_size > 0) { - S32 version = mMeshHeader[mesh_id]["version"].asInteger(); - S32 offset = header_size + mMeshHeader[mesh_id][header_lod[lod]]["offset"].asInteger(); - S32 size = mMeshHeader[mesh_id][header_lod[lod]]["size"].asInteger(); + const auto& header = header_it->second.second; + S32 version = header["version"].asInteger(); + S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger(); + S32 size = header[header_lod[lod]]["size"].asInteger(); mHeaderMutex->unlock(); if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) @@ -1789,17 +1830,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, } else { - mUnavailableQ.push(LODRequest(mesh_params, lod)); + LLMutexLock lock(mMutex); + mUnavailableQ.push_back(LODRequest(mesh_params, lod)); } } else { - mUnavailableQ.push(LODRequest(mesh_params, lod)); + LLMutexLock lock(mMutex); + mUnavailableQ.push_back(LODRequest(mesh_params, lod)); } } else { - mUnavailableQ.push(LODRequest(mesh_params, lod)); + LLMutexLock lock(mMutex); + mUnavailableQ.push_back(LODRequest(mesh_params, lod)); } } else @@ -1818,27 +1862,12 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes U32 header_size = 0; if (data_size > 0) { - std::istringstream stream; - try - { - std::string res_str((char*)data, data_size); + U32 dsize = data_size; + char* result_ptr = strip_deprecated_header((char*)data, dsize, &header_size); - std::string deprecated_header("<? LLSD/Binary ?>"); + data_size = dsize; - if (res_str.substr(0, deprecated_header.size()) == deprecated_header) - { - res_str = res_str.substr(deprecated_header.size() + 1, data_size); - header_size = deprecated_header.size() + 1; - } - data_size = res_str.size(); - - stream.str(res_str); - } - catch (std::bad_alloc&) - { - // out of memory, we won't be able to process this mesh - return MESH_OUT_OF_MEMORY; - } + boost::iostreams::stream<boost::iostreams::array_source> stream(result_ptr, data_size); if (!LLSDSerialize::fromBinary(header, stream, data_size)) { @@ -1875,8 +1904,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes { LLMutexLock lock(mHeaderMutex); - mMeshHeaderSize[mesh_id] = header_size; - mMeshHeader[mesh_id] = header; + mMeshHeader[mesh_id] = { header_size, header }; LLMeshRepository::sCacheBytesHeaders += header_size; } @@ -1884,7 +1912,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. //check for pending requests - pending_lod_map::iterator iter = mPendingLOD.find(mesh_params); + pending_lod_map::iterator iter = mPendingLOD.find(mesh_id); if (iter != mPendingLOD.end()) { for (U32 i = 0; i < iter->second.size(); ++i) @@ -1908,26 +1936,14 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p } LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); - std::istringstream stream; - try - { - std::string mesh_string((char*)data, data_size); - stream.str(mesh_string); - } - catch (std::bad_alloc&) - { - // out of memory, we won't be able to process this mesh - return MESH_OUT_OF_MEMORY; - } - - if (volume->unpackVolumeFaces(stream, data_size)) + if (volume->unpackVolumeFaces(data, data_size)) { if (volume->getNumFaces() > 0) { LoadedMesh mesh(volume, mesh_params, lod); { LLMutexLock lock(mMutex); - mLoadedQ.push(mesh); + mLoadedQ.push_back(mesh); // LLPointer is not thread safe, since we added this pointer into // threaded list, make sure counter gets decreased inside mutex lock // and won't affect mLoadedQ processing @@ -1950,10 +1966,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat { try { - std::string res_str((char*)data, data_size); - std::istringstream stream(res_str); - - U32 uzip_result = LLUZipHelper::unzip_llsd(skin, stream, data_size); + U32 uzip_result = LLUZipHelper::unzip_llsd(skin, data, data_size); if (uzip_result != LLUZipHelper::ZR_OK) { LL_WARNS(LOG_MESH) << "Mesh skin info parse error. Not a valid mesh asset! ID: " << mesh_id @@ -1970,8 +1983,16 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat } { - LLMeshSkinInfo info(skin); - info.mMeshID = mesh_id; + LLMeshSkinInfo* info = nullptr; + try + { + info = new LLMeshSkinInfo(mesh_id, skin); + } + catch (const std::bad_alloc& ex) + { + LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what() << LL_ENDL; + return false; + } // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL; { @@ -1991,10 +2012,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 { try { - std::string res_str((char*)data, data_size); - std::istringstream stream(res_str); - - U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, stream, data_size); + U32 uzip_result = LLUZipHelper::unzip_llsd(decomp, data, data_size); if (uzip_result != LLUZipHelper::ZR_OK) { LL_WARNS(LOG_MESH) << "Mesh decomposition parse error. Not a valid mesh asset! ID: " << mesh_id @@ -2003,7 +2021,7 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3 return false; } } - catch (std::bad_alloc&) + catch (const std::bad_alloc&) { LL_WARNS(LOG_MESH) << "Out of memory for mesh ID " << mesh_id << " of size: " << data_size << LL_ENDL; return false; @@ -2040,20 +2058,7 @@ EMeshProcessingResult LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_ volume_params.setSculptID(mesh_id, LL_SCULPT_TYPE_MESH); LLPointer<LLVolume> volume = new LLVolume(volume_params,0); - std::istringstream stream; - try - { - std::string mesh_string((char*)data, data_size); - stream.str(mesh_string); - } - catch (std::bad_alloc&) - { - // out of memory, we won't be able to process this mesh - delete d; - return MESH_OUT_OF_MEMORY; - } - - if (volume->unpackVolumeFaces(stream, data_size)) + if (volume->unpackVolumeFaces(data, data_size)) { d->mPhysicsShapeMesh.clear(); @@ -2864,58 +2869,72 @@ void LLMeshRepoThread::notifyLoadedMeshes() return; } - while (!mLoadedQ.empty()) + if (!mLoadedQ.empty()) { + std::deque<LoadedMesh> loaded_queue; + mMutex->lock(); - if (mLoadedQ.empty()) + if (!mLoadedQ.empty()) { + loaded_queue.swap(mLoadedQ); mMutex->unlock(); - break; - } - LoadedMesh mesh = mLoadedQ.front(); // make sure nothing else owns volume pointer by this point - mLoadedQ.pop(); - mMutex->unlock(); - - update_metrics = true; - if (mesh.mVolume->getNumVolumeFaces() > 0) - { - gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); - } - else - { - gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, - LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); + + update_metrics = true; + + // Process the elements free of the lock + for (const auto& mesh : loaded_queue) + { + if (mesh.mVolume->getNumVolumeFaces() > 0) + { + gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); + } + else + { + gMeshRepo.notifyMeshUnavailable(mesh.mMeshParams, + LLVolumeLODGroup::getVolumeDetailFromScale(mesh.mVolume->getDetail())); + } + } } } - while (!mUnavailableQ.empty()) + if (!mUnavailableQ.empty()) { + std::deque<LODRequest> unavil_queue; + mMutex->lock(); - if (mUnavailableQ.empty()) + if (!mUnavailableQ.empty()) { + unavil_queue.swap(mUnavailableQ); mMutex->unlock(); - break; - } - - LODRequest req = mUnavailableQ.front(); - mUnavailableQ.pop(); - mMutex->unlock(); - update_metrics = true; - gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); + update_metrics = true; + + // Process the elements free of the lock + for (const auto& req : unavil_queue) + { + gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD); + } + } } - if (! mSkinInfoQ.empty() || ! mDecompositionQ.empty()) + if (!mSkinInfoQ.empty() || !mSkinUnavailableQ.empty() || ! mDecompositionQ.empty()) { if (mMutex->trylock()) { - std::list<LLMeshSkinInfo> skin_info_q; + std::deque<LLMeshSkinInfo*> skin_info_q; + std::deque<UUIDBasedRequest> skin_info_unavail_q; std::list<LLModel::Decomposition*> decomp_q; if (! mSkinInfoQ.empty()) { skin_info_q.swap(mSkinInfoQ); } + + if (! mSkinUnavailableQ.empty()) + { + skin_info_unavail_q.swap(mSkinUnavailableQ); + } + if (! mDecompositionQ.empty()) { decomp_q.swap(mDecompositionQ); @@ -2929,6 +2948,11 @@ void LLMeshRepoThread::notifyLoadedMeshes() gMeshRepo.notifySkinInfoReceived(skin_info_q.front()); skin_info_q.pop_front(); } + while (! skin_info_unavail_q.empty()) + { + gMeshRepo.notifySkinInfoUnavailable(skin_info_unavail_q.front().mId); + skin_info_unavail_q.pop_front(); + } while (! decomp_q.empty()) { @@ -2953,7 +2977,7 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo if (iter != mMeshHeader.end()) { - LLSD& header = iter->second; + LLSD& header = iter->second.second; return LLMeshRepository::getActualMeshLOD(header, lod); } @@ -3156,7 +3180,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status) LLMutexLock lock(gMeshRepo.mThread->mMutex); for (int i(0); i < 4; ++i) { - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i)); } } @@ -3185,7 +3209,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b LLMutexLock lock(gMeshRepo.mThread->mMutex); for (int i(0); i < 4; ++i) { - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i)); } } else if (data && data_size > 0) @@ -3198,8 +3222,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id); if (iter != gMeshRepo.mThread->mMeshHeader.end()) { - header_bytes = (S32)gMeshRepo.mThread->mMeshHeaderSize[mesh_id]; - header = iter->second; + header_bytes = (S32)iter->second.first; + header = iter->second.second; } if (header_bytes > 0 @@ -3267,7 +3291,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b LLMutexLock lock(gMeshRepo.mThread->mMutex); for (int i(0); i < 4; ++i) { - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, i)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, i)); } } } @@ -3294,7 +3318,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status) << LL_ENDL; LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); } void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3331,7 +3355,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body << " Not retrying." << LL_ENDL; LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); } } else @@ -3342,7 +3366,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body << " Data size: " << data_size << LL_ENDL; LLMutexLock lock(gMeshRepo.mThread->mMutex); - gMeshRepo.mThread->mUnavailableQ.push(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); + gMeshRepo.mThread->mUnavailableQ.push_back(LLMeshRepoThread::LODRequest(mMeshParams, mLOD)); } } @@ -3360,9 +3384,8 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status) << ", Reason: " << status.toString() << " (" << status.toTerseString() << "). Not retrying." << LL_ENDL; - - // *TODO: Mark mesh unavailable on error. For now, simply leave - // request unfulfilled rather than retry forever. + LLMutexLock lock(gMeshRepo.mThread->mMutex); + gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID); } void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, @@ -3393,7 +3416,8 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* LL_WARNS(LOG_MESH) << "Error during mesh skin info processing. ID: " << mMeshID << ", Unknown reason. Not retrying." << LL_ENDL; - // *TODO: Mark mesh unavailable on error + LLMutexLock lock(gMeshRepo.mThread->mMutex); + gMeshRepo.mThread->mSkinUnavailableQ.emplace_back(mMeshID); } } @@ -3502,7 +3526,7 @@ LLMeshRepository::LLMeshRepository() mMeshThreadCount(0), mThread(NULL) { - + mSkinInfoCullTimer.resetWithExpiry(10.f); } void LLMeshRepository::init() @@ -3603,6 +3627,22 @@ S32 LLMeshRepository::update() return size ; } +void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) +{ + for (auto& lod : mLoadingMeshes) + { + for (auto& param : lod) + { + vector_replace_with_last(param.second, vobj); + } + } + + for (auto& skin_pair : mLoadingSkins) + { + vector_replace_with_last(skin_pair.second, vobj); + } +} + S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); @@ -3618,15 +3658,19 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_params); + const auto& mesh_id = mesh_params.getSculptID(); + mesh_load_map::iterator iter = mLoadingMeshes[detail].find(mesh_id); if (iter != mLoadingMeshes[detail].end()) { //request pending for this mesh, append volume id to list - iter->second.insert(vobj->getID()); + auto it = std::find(iter->second.begin(), iter->second.end(), vobj); + if (it == iter->second.end()) { + iter->second.push_back(vobj); + } } else { //first request for this mesh - mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); + mLoadingMeshes[detail][mesh_id].push_back(vobj); mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); LLMeshRepository::sLODPending++; } @@ -3783,6 +3827,28 @@ void LLMeshRepository::notifyLoadedMeshes() //call completed callbacks on finished decompositions mDecompThread->notifyCompleted(); + if (mSkinInfoCullTimer.checkExpirationAndReset(10.f)) + { + //// Clean up dead skin info + //U64Bytes skinbytes(0); + for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;) + { + auto copy_iter = iter++; + + //skinbytes += U64Bytes(sizeof(LLMeshSkinInfo)); + //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string)); + //skinbytes += U64Bytes(copy_iter->second->mJointNums.size() * sizeof(S32)); + //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4a)); + //skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(LLMatrix4)); + + if (copy_iter->second->getNumRefs() == 1) + { + mSkinMap.erase(copy_iter); + } + } + //LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL; + } + // For major operations, attempt to get the required locks // without blocking and punt if they're not available. The // longest run of holdoffs is kept in sMaxLockHoldoffs just @@ -3853,10 +3919,9 @@ void LLMeshRepository::notifyLoadedMeshes() for (mesh_load_map::iterator iter = mLoadingMeshes[i].begin(); iter != mLoadingMeshes[i].end(); ++iter) { F32 max_score = 0.f; - for (std::set<LLUUID>::iterator obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) + for (auto obj_iter = iter->second.begin(); obj_iter != iter->second.end(); ++obj_iter) { - LLViewerObject* object = gObjectList.findObject(*obj_iter); - + LLVOVolume* object = *obj_iter; if (object) { LLDrawable* drawable = object->mDrawable; @@ -3868,7 +3933,7 @@ void LLMeshRepository::notifyLoadedMeshes() } } - score_map[iter->first.getSculptID()] = max_score; + score_map[iter->first] = max_score; } } @@ -3920,24 +3985,39 @@ void LLMeshRepository::notifyLoadedMeshes() mThread->mSignal->signal(); } -void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info) +void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info) { - mSkinMap[info.mMeshID] = info; + mSkinMap[info->mMeshID] = info; // Cache into LLPointer // Alternative: We can get skin size from header - sCacheBytesSkins += info.sizeBytes(); + sCacheBytesSkins += info->sizeBytes(); - skin_load_map::iterator iter = mLoadingSkins.find(info.mMeshID); + skin_load_map::iterator iter = mLoadingSkins.find(info->mMeshID); if (iter != mLoadingSkins.end()) { - for (std::set<LLUUID>::iterator obj_id = iter->second.begin(); obj_id != iter->second.end(); ++obj_id) + for (LLVOVolume* vobj : iter->second) { - LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*obj_id); if (vobj) { - vobj->notifyMeshLoaded(); + vobj->notifySkinInfoLoaded(info); } } - mLoadingSkins.erase(info.mMeshID); + mLoadingSkins.erase(iter); + } +} + +void LLMeshRepository::notifySkinInfoUnavailable(const LLUUID& mesh_id) +{ + skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); + if (iter != mLoadingSkins.end()) + { + for (LLVOVolume* vobj : iter->second) + { + if (vobj) + { + vobj->notifySkinInfoUnavailable(); + } + } + mLoadingSkins.erase(iter); } } @@ -3966,14 +4046,15 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol S32 detail = LLVolumeLODGroup::getVolumeDetailFromScale(volume->getDetail()); //get list of objects waiting to be notified this mesh is loaded - mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_params); + const auto& mesh_id = mesh_params.getSculptID(); + mesh_load_map::iterator obj_iter = mLoadingMeshes[detail].find(mesh_id); if (volume && obj_iter != mLoadingMeshes[detail].end()) { //make sure target volume is still valid if (volume->getNumVolumeFaces() <= 0) { - LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_params.getSculptID() + LL_WARNS(LOG_MESH) << "Mesh loading returned empty volume. ID: " << mesh_id << LL_ENDL; } @@ -3987,37 +4068,35 @@ void LLMeshRepository::notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVol } else { - LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_params.getSculptID() + LL_WARNS(LOG_MESH) << "Couldn't find system volume for mesh " << mesh_id << LL_ENDL; } } //notify waiting LLVOVolume instances that their requested mesh is available - for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + for (LLVOVolume* vobj : obj_iter->second) { - LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); if (vobj) { vobj->notifyMeshLoaded(); } } - mLoadingMeshes[detail].erase(mesh_params); + mLoadingMeshes[detail].erase(obj_iter); } } void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod) { //called from main thread //get list of objects waiting to be notified this mesh is loaded - mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_params); - - F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); - + const auto& mesh_id = mesh_params.getSculptID(); + mesh_load_map::iterator obj_iter = mLoadingMeshes[lod].find(mesh_id); if (obj_iter != mLoadingMeshes[lod].end()) { - for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter) + F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod); + + for (LLVOVolume* vobj : obj_iter->second) { - LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter); if (vobj) { LLVolume* obj_volume = vobj->getVolume(); @@ -4031,7 +4110,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params, } } - mLoadingMeshes[lod].erase(mesh_params); + mLoadingMeshes[lod].erase(obj_iter); } } @@ -4040,7 +4119,7 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo return mThread->getActualMeshLOD(mesh_params, lod); } -const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj) +const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj) { LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (mesh_id.notNull()) @@ -4048,7 +4127,7 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const skin_map::iterator iter = mSkinMap.find(mesh_id); if (iter != mSkinMap.end()) { - return &(iter->second); + return iter->second; } //no skin info known about given mesh, try to fetch it @@ -4057,14 +4136,22 @@ const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); - if (iter == mLoadingSkins.end()) - { //no request pending for this skin info + if (iter != mLoadingSkins.end()) + { //request pending for this mesh, append volume id to list + auto it = std::find(iter->second.begin(), iter->second.end(), requesting_obj); + if (it == iter->second.end()) { + iter->second.push_back(requesting_obj); + } + } + else + { + //first request for this mesh + mLoadingSkins[mesh_id].push_back(requesting_obj); mPendingSkinRequests.push(mesh_id); } - mLoadingSkins[mesh_id].insert(requesting_obj->getID()); } } - return NULL; + return nullptr; } void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) @@ -4167,16 +4254,13 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id) bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id) { LLMutexLock lock(mHeaderMutex); - if (mMeshHeaderSize[mesh_id] > 0) + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); + if (iter != mMeshHeader.end() && iter->second.first > 0) { - mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); - if (iter != mMeshHeader.end()) + LLSD &mesh = iter->second.second; + if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) { - LLSD &mesh = iter->second; - if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) - { - return true; - } + return true; } } @@ -4201,9 +4285,9 @@ S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) { LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + if (iter != mThread->mMeshHeader.end() && iter->second.first > 0) { - LLSD& header = iter->second; + const LLSD& header = iter->second.second; if (header.has("404")) { @@ -4307,9 +4391,9 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by { LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + if (iter != mThread->mMeshHeader.end() && iter->second.first > 0) { - result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + result = getStreamingCostLegacy(iter->second.second, radius, bytes, bytes_visible, lod, unscaled_value); } } if (result > 0.f) @@ -4622,9 +4706,9 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) { LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + if (iter != mThread->mMeshHeader.end() && iter->second.first > 0) { - LLSD& header = iter->second; + LLSD& header = iter->second.second; bool header_invalid = (header.has("404") || !header.has("lowest_lod") |