From 740d34d9e70ef1b7ba5acc05fcdd8e0b2d66efc3 Mon Sep 17 00:00:00 2001 From: Rye Mutt <rye@alchemyviewer.org> Date: Tue, 20 Dec 2022 20:45:52 -0500 Subject: [PATCH] Clean up and crash fixes to mesh repo --- indra/newview/llcontrolavatar.cpp | 2 +- indra/newview/llmeshrepository.cpp | 497 ++++++++++------------------- indra/newview/llmeshrepository.h | 17 +- indra/newview/llspatialpartition.h | 2 +- indra/newview/llvovolume.cpp | 38 ++- indra/newview/llvovolume.h | 12 +- 6 files changed, 219 insertions(+), 349 deletions(-) diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index f04b487d120..5523ca494d6 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -235,7 +235,7 @@ void LLControlAvatar::matchVolumeTransform() #define MATCH_BIND_SHAPE #ifdef MATCH_BIND_SHAPE // MAINT-8671 - based on a patch from Beq Janus - const LLMeshSkinInfo* skin_info = mRootVolp->getSkinInfo(); + LLConstPointer<LLMeshSkinInfo> skin_info = mRootVolp->getSkinInfo(); if (skin_info) { #ifdef SHOW_DEBUG diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a8a61170bd6..1a88cdd720b 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1170,8 +1170,9 @@ 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 header_lock(mHeaderMutex); - mesh_header_map::iterator iter = mMeshHeader.find(mesh_params.getSculptID()); + mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); if (iter != mMeshHeader.end()) { //if we have the header, request LOD byte range header_lock.unlock(); @@ -1186,11 +1187,8 @@ void LLMeshRepoThread::loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod) else { header_lock.unlock(); - HeaderRequest req(mesh_params); - const LLUUID& mesh_id = mesh_params.getSculptID(); - LLMutexLock lock(mMutex); pending_lod_map::iterator pending = mPendingLOD.find(mesh_id); @@ -1325,101 +1323,104 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, int l return handle; } - -bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) -{ - +bool LLMeshRepoThread::getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info) +{ //protected by mMutex if (!mHeaderMutex) { return false; } - mHeaderMutex->lock(); + LLMutexLock lock(mHeaderMutex); + + ++LLMeshRepository::sMeshRequestCount; 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 ret = true; - U32 header_size = header_it->second.first; - - if (header_size > 0) + if ((info.mHeaderSize = header_it->second.first) > 0) { - const auto& header = header_it->second.second; - S32 version = header["version"].asInteger(); - S32 offset = header_size + header["skin"]["offset"].asInteger(); - S32 size = header["skin"]["size"].asInteger(); + const LLSD& header = header_it->second.second; + const LLSD& block = header[block_name]; + info.mVersion = header["version"].asInteger(); + info.mOffset = info.mHeaderSize + block["offset"].asInteger(); + info.mSize = block["size"].asInteger(); + } + return true; +} - mHeaderMutex->unlock(); +bool LLMeshRepoThread::loadInfoFromFilesystem(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn) +{ + //check cache for mesh skin info + LLFileSystem file(mesh_id, LLAssetType::AT_MESH); + if (file.getSize() >= info.mOffset + info.mSize) + { + auto buffer = std::make_unique<U8[]>(info.mSize); + if (!buffer) + { + LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh data load, size: " << info.mSize << LL_ENDL; + return false; + } + LLMeshRepository::sCacheBytesRead += info.mSize; + ++LLMeshRepository::sCacheReads; + file.seek(info.mOffset); + file.read(buffer.get(), info.mSize); - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) + //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) + bool zero = true; + for (S32 i = 0; i < llmin(info.mSize, S32(1024)) && zero; ++i) { - //check cache for mesh skin info - LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ); - if (file.open() && file.getSize() >= offset+size) - { - U8* buffer = new(std::nothrow) U8[size]; - if (!buffer) - { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for skin info, size: " << size << LL_ENDL; - return false; - } - LLMeshRepository::sCacheBytesRead += size; - ++LLMeshRepository::sCacheReads; - file.seek(offset); - file.read(buffer, size); - file.close(); + zero = buffer[i] > 0 ? false : true; + } - //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } + if (!zero) + { //attempt to parse + if (fn(mesh_id, buffer.get(), info.mSize)) + { + return true; + } + } + } + return false; +} - if (!zero) - { //attempt to parse - if (skinInfoReceived(mesh_id, buffer, size)) - { - delete[] buffer; - return true; - } - } +bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) +{ + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "skin", info)) + { + return false; + } - delete[] buffer; - } + if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) + { + //check cache for mesh skin info + if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::skinInfoReceived, this, _1, _2, _3))) + return true; - //reading from cache failed for whatever reason, fetch from sim - std::string http_url; - int legacy_cap_version(0); - constructUrl(mesh_id, &http_url, &legacy_cap_version); + //reading from cache failed for whatever reason, fetch from sim + std::string http_url; + int legacy_cap_version(0); + constructUrl(mesh_id, &http_url, &legacy_cap_version); - if (!http_url.empty()) + if (!http_url.empty()) + { + auto handler = std::make_shared<LLMeshSkinInfoHandler>(mesh_id, info.mOffset, info.mSize); + LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) { - auto handler = std::make_shared<LLMeshSkinInfoHandler>(mesh_id, offset, size); - LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler); - if (LLCORE_HTTP_HANDLE_INVALID == handle) - { - LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID - << ". Reason: " << mHttpStatus.toString() - << " (" << mHttpStatus.toTerseString() << ")" - << LL_ENDL; - ret = false; - } - else if(can_retry) - { - handler->mHttpHandle = handle; - mHttpRequestSet.emplace(std::move(handler)); - } - else - { - LLMutexLock locker(mMutex); - mSkinUnavailableQ.emplace_back(mesh_id); - } + LL_WARNS(LOG_MESH) << "HTTP GET request failed for skin info on mesh " << mID + << ". Reason: " << mHttpStatus.toString() + << " (" << mHttpStatus.toTerseString() << ")" + << LL_ENDL; + return false; + } + else if (can_retry) + { + handler->mHttpHandle = handle; + mHttpRequestSet.emplace(std::move(handler)); } else { @@ -1434,180 +1435,72 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) } } else - { - mHeaderMutex->unlock(); + { + LLMutexLock locker(mMutex); + mSkinUnavailableQ.emplace_back(mesh_id); } //early out was not hit, effectively fetched - return ret; + return true; } bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { - if (!mHeaderMutex) + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "physics_convex", info)) { return false; } - 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; - U32 header_size = header_it->second.first; - bool ret = true; - - if (header_size > 0) + if (info.mHeaderSize > 0 && info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - 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(); + //check cache for mesh physics info + if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::decompositionReceived, this, _1, _2, _3))) + return true; - mHeaderMutex->unlock(); + //reading from cache failed for whatever reason, fetch from sim + std::string http_url; + int legacy_cap_version(0); + constructUrl(mesh_id, &http_url, &legacy_cap_version); - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) + if (!http_url.empty()) { - //check cache for mesh skin info - LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ); - if (file.open() && file.getSize() >= offset+size) + auto handler = std::make_shared<LLMeshDecompositionHandler>(mesh_id, info.mOffset, info.mSize); + LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler); + if (LLCORE_HTTP_HANDLE_INVALID == handle) { - U8* buffer = new(std::nothrow) U8[size]; - if (!buffer) - { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for mesh decomposition, size: " << size << LL_ENDL; - return false; - } - LLMeshRepository::sCacheBytesRead += size; - ++LLMeshRepository::sCacheReads; - - file.seek(offset); - file.read(buffer, size); - file.close(); - - //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (decompositionReceived(mesh_id, buffer, size)) - { - delete[] buffer; - return true; - } - } - - delete[] buffer; + LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID + << ". Reason: " << mHttpStatus.toString() + << " (" << mHttpStatus.toTerseString() << ")" + << LL_ENDL; + return false; } - - //reading from cache failed for whatever reason, fetch from sim - std::string http_url; - int legacy_cap_version(0); - constructUrl(mesh_id, &http_url, &legacy_cap_version); - - if (!http_url.empty()) + else { - auto handler = std::make_shared<LLMeshDecompositionHandler>(mesh_id, offset, size); - LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler); - if (LLCORE_HTTP_HANDLE_INVALID == handle) - { - LL_WARNS(LOG_MESH) << "HTTP GET request failed for decomposition mesh " << mID - << ". Reason: " << mHttpStatus.toString() - << " (" << mHttpStatus.toTerseString() << ")" - << LL_ENDL; - ret = false; - } - else - { - handler->mHttpHandle = handle; - mHttpRequestSet.insert(handler); - } + handler->mHttpHandle = handle; + mHttpRequestSet.insert(handler); } } } - else - { - mHeaderMutex->unlock(); - } //early out was not hit, effectively fetched - return ret; + return true; } bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { - if (!mHeaderMutex) + MeshHeaderInfo info; + if (!getMeshHeaderInfo(mesh_id, "physics_mesh", info)) { return false; } - 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; - U32 header_size = header_it->second.first; - bool ret = true; - - if (header_size > 0) + if (info.mHeaderSize > 0) { - 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(); - - if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) + if (info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - //check cache for mesh physics shape info - LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ); - if (file.open() && file.getSize() >= offset+size) - { - LLMeshRepository::sCacheBytesRead += size; - ++LLMeshRepository::sCacheReads; - file.seek(offset); - U8* buffer = new(std::nothrow) U8[size]; - if (!buffer) - { - LL_WARNS_ONCE(LOG_MESH) << "Failed to allocate memory for physics shape, size: " << size << LL_ENDL; - return false; - } - file.read(buffer, size); - file.close(); - - //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (physicsShapeReceived(mesh_id, buffer, size) == MESH_OK) - { - delete[] buffer; - return true; - } - } - - delete[] buffer; - } + if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::physicsShapeReceived, this, _1, _2, _3))) + return true; //reading from cache failed for whatever reason, fetch from sim std::string http_url; @@ -1616,15 +1509,15 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (!http_url.empty()) { - auto handler = std::make_shared<LLMeshPhysicsShapeHandler>(mesh_id, offset, size); - LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler); + auto handler = std::make_shared<LLMeshPhysicsShapeHandler>(mesh_id, info.mOffset, info.mSize); + LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for physics shape on mesh " << mID << ". Reason: " << mHttpStatus.toString() << " (" << mHttpStatus.toTerseString() << ")" << LL_ENDL; - ret = false; + return false; } else { @@ -1638,13 +1531,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) physicsShapeReceived(mesh_id, NULL, 0); } } - else - { - mHeaderMutex->unlock(); - } //early out was not hit, effectively fetched - return ret; + return true; } //static @@ -1697,6 +1586,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c file.close(); if (headerReceived(mesh_params, buffer, bytes) == MESH_OK) { +#ifdef SHOW_DEBUG + std::string mid; + mesh_params.getSculptID().toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the cache." << LL_ENDL; +#endif // Found mesh in cache return true; } @@ -1711,6 +1605,12 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c if (!http_url.empty()) { +#ifdef SHOW_DEBUG + std::string mid; + mesh_params.getSculptID().toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh header for ID " << mid << " - was retrieved from the simulator." << LL_ENDL; +#endif + //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB //NOTE -- this will break of headers ever exceed 4KB @@ -1738,71 +1638,20 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c //return false if failed to get mesh lod. bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry) { - if (!mHeaderMutex) - { - return false; - } - - const LLUUID& mesh_id = mesh_params.getSculptID(); + LLUUID mesh_id = mesh_params.getSculptID(); + MeshHeaderInfo info; - 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(); + if (!getMeshHeaderInfo(mesh_id, header_lod[lod].c_str(), info)) + { return false; } - ++LLMeshRepository::sMeshRequestCount; - bool retval = true; - - U32 header_size = header_it->second.first; - if (header_size > 0) + + if (info.mHeaderSize > 0) { - 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) + if(info.mVersion <= MAX_MESH_VERSION && info.mOffset >= 0 && info.mSize > 0) { - - //check cache for mesh asset - LLFileSystem file(mesh_id, LLAssetType::AT_MESH, LLFileSystem::READ); - if (file.open() && file.getSize() >= offset+size) - { - U8* buffer = new(std::nothrow) U8[size]; - if (!buffer) - { - LL_WARNS_ONCE(LOG_MESH) << "Can't allocate memory for mesh " << mesh_id << " LOD " << lod << ", size: " << size << LL_ENDL; - // todo: for now it will result in indefinite constant retries, should result in timeout - // or in retry-count and disabling mesh. (but usually viewer is beyond saving at this point) - return false; - } - LLMeshRepository::sCacheBytesRead += size; - ++LLMeshRepository::sCacheReads; - file.seek(offset); - file.read(buffer, size); - file.close(); - - //make sure buffer isn't all 0's by checking the first 1KB (reserved block but not written) - bool zero = true; - for (S32 i = 0; i < llmin(size, 1024) && zero; ++i) - { - zero = buffer[i] > 0 ? false : true; - } - - if (!zero) - { //attempt to parse - if (lodReceived(mesh_params, lod, buffer, size) == MESH_OK) - { - delete[] buffer; - return true; - } - } - - delete[] buffer; - } + if (loadInfoFromFilesystem(mesh_id, info, boost::bind(&LLMeshRepoThread::lodReceived, this, mesh_params, lod, _2, _3 ))) + return true; //reading from cache failed for whatever reason, fetch from sim std::string http_url; @@ -1811,15 +1660,20 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, if (!http_url.empty()) { - auto handler = std::make_shared<LLMeshLODHandler>(mesh_params, lod, offset, size); - LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, offset, size, handler); +#if SHOW_DEBUG + std::string mid; + mesh_id.toString(mid); + LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mid << " - was retrieved from the simulator." << LL_ENDL; +#endif + auto handler = std::make_shared<LLMeshLODHandler>(mesh_params, lod, info.mOffset, info.mSize); + LLCore::HttpHandle handle = getByteRange(http_url, legacy_cap_version, info.mOffset, info.mSize, handler); if (LLCORE_HTTP_HANDLE_INVALID == handle) { LL_WARNS(LOG_MESH) << "HTTP GET request failed for LOD on mesh " << mID << ". Reason: " << mHttpStatus.toString() << " (" << mHttpStatus.toTerseString() << ")" << LL_ENDL; - retval = false; + return false; } else if (can_retry) { @@ -1850,7 +1704,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, mHeaderMutex->unlock(); } - return retval; + return true; } EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) @@ -1907,7 +1761,6 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes LLMeshRepository::sCacheBytesHeaders += header_size; } - LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. //check for pending requests @@ -1935,7 +1788,6 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p } LLPointer<LLVolume> volume = new LLVolume(mesh_params, LLVolumeLODGroup::getVolumeScaleFromDetail(lod)); - if (volume->unpackVolumeFaces(data, data_size)) { if (volume->getNumFaces() > 0) @@ -2887,7 +2739,7 @@ void LLMeshRepoThread::notifyLoadedMeshes() // Process the elements free of the lock for (const auto& mesh : loaded_queue) { - if (mesh.mVolume->getNumVolumeFaces() > 0) + if (mesh.mVolume && mesh.mVolume->getNumVolumeFaces() > 0) { gMeshRepo.notifyMeshLoaded(mesh.mMeshParams, mesh.mVolume); } @@ -3640,13 +3492,13 @@ void LLMeshRepository::unregisterMesh(LLVOVolume* vobj) { for (auto& param : lod) { - vector_replace_with_last(param.second, vobj); + param.second.erase(vobj); } } for (auto& skin_pair : mLoadingSkins) { - vector_replace_with_last(skin_pair.second, vobj); + skin_pair.second.erase(vobj); } } @@ -3665,18 +3517,20 @@ 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.getSculptID()); + 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 - auto it = std::find(iter->second.begin(), iter->second.end(), vobj); - if (it == iter->second.end()) { - iter->second.push_back(vobj); + auto& obj_set = iter->second; + auto it = obj_set.find(vobj); + if (it == obj_set.end()) { + obj_set.insert(vobj); } } else { //first request for this mesh - mLoadingMeshes[detail][mesh_params.getSculptID()].push_back(vobj); + mLoadingMeshes[detail][mesh_id].insert(vobj); mPendingRequests.emplace_back(mesh_params, detail); LLMeshRepository::sLODPending++; } @@ -4011,7 +3865,7 @@ void LLMeshRepository::notifyLoadedMeshes() void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info) { - auto pair = mSkinMap.emplace(info->mMeshID, info); // Cache into LLPointer + mSkinMap[info->mMeshID] = info; // Cache into LLPointer // Alternative: We can get skin size from header sCacheBytesSkins += info->sizeBytes(); @@ -4022,7 +3876,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo* info) { if (vobj) { - vobj->notifySkinInfoLoaded(((*pair.first).second)); + vobj->notifySkinInfoLoaded(info); } } mLoadingSkins.erase(iter); @@ -4148,32 +4002,33 @@ LLPointer<LLMeshSkinInfo> LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, L if (mesh_id.notNull()) { skin_map::iterator iter = mSkinMap.find(mesh_id); - if (iter != mSkinMap.end()) - { - return iter->second; - } - - //no skin info known about given mesh, try to fetch it - { - LLMutexLock lock(mMeshMutex); - //add volume to list of loading meshes - skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); + if (iter != mSkinMap.end()) + { + return iter->second; + } + + //no skin info known about given mesh, try to fetch it + if (requesting_obj != nullptr) + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); 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); + auto& obj_set = iter->second; + auto it = obj_set.find(requesting_obj); + if (it == obj_set.end()) { + obj_set.insert(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); + mPendingSkinRequests.push(mesh_id); + } + } + } return nullptr; } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index f48797b9190..64896942e84 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -283,6 +283,16 @@ class LLMeshRepoThread final : public LLThread }; + struct MeshHeaderInfo + { + MeshHeaderInfo() + : mHeaderSize(0), mVersion(0), mOffset(-1), mSize(0) {} + U32 mHeaderSize; + U32 mVersion; + S32 mOffset; + S32 mSize; + }; + ///////// // In flight queues ///////// @@ -363,6 +373,9 @@ class LLMeshRepoThread final : public LLThread EMeshProcessingResult physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32 data_size); bool hasPhysicsShapeInHeader(const LLUUID& mesh_id); + bool getMeshHeaderInfo(const LLUUID& mesh_id, const char* block_name, MeshHeaderInfo& info); + bool loadInfoFromFilesystem(const LLUUID& mesh_id, MeshHeaderInfo& info, boost::function<bool(const LLUUID&, U8*, S32)> fn); + void notifyLoadedMeshes(); // Only call from main thread. S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); @@ -633,7 +646,7 @@ class LLMeshRepository static void metricsProgress(unsigned int count); static void metricsUpdate(); - typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > mesh_load_map; + typedef boost::unordered_map<LLUUID, boost::unordered_set<LLVOVolume*> > mesh_load_map; mesh_load_map mLoadingMeshes[4]; typedef boost::unordered_flat_map<LLUUID, LLPointer<LLMeshSkinInfo>> skin_map; @@ -647,7 +660,7 @@ class LLMeshRepository std::vector<LLMeshRepoThread::LODRequest> mPendingRequests; //list of mesh ids awaiting skin info - typedef boost::unordered_map<LLUUID, std::vector<LLVOVolume*> > skin_load_map; + typedef boost::unordered_map<LLUUID, boost::unordered_set<LLVOVolume*> > skin_load_map; skin_load_map mLoadingSkins; //list of mesh ids that need to send skin info fetch requests diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index a5db551dd84..6c50893d7ea 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -118,7 +118,7 @@ class LLDrawInfo : public LLRefCount U8 mDiffuseAlphaMode; bool mSelected; LLPointer<LLVOAvatar> mAvatar = nullptr; - LLMeshSkinInfo* mSkinInfo = nullptr; + LLPointer<LLMeshSkinInfo> mSkinInfo = nullptr; struct CompareTexture diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 926c787e841..6cc435420a5 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -234,10 +234,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mColorChanged = FALSE; mSpotLightPriority = 0.f; - mSkinInfoFailed = false; mSkinInfo = NULL; - mSkinRenderMatrixJointCount = 0; - mSkinLastRenderFrame = 0; mMediaImplList.resize(getNumTEs()); mLastFetchedMediaVersion = -1; @@ -257,7 +254,10 @@ LLVOVolume::~LLVOVolume() mSkinInfo = nullptr; - gMeshRepo.unregisterMesh(this); + //if(mMeshDataInFlight || mSkinInfoInFlight) + { + gMeshRepo.unregisterMesh(this); + } if(!mMediaImplList.empty()) { @@ -1117,7 +1117,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo if (mSkinInfo && mSkinInfo->mMeshID != volume_params.getSculptID()) { mSkinInfo = NULL; - mSkinInfoFailed = false; } if (!getVolume()->isMeshAssetLoaded()) @@ -1130,12 +1129,12 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bo } } - if (!mSkinInfo && !hasSkinInfoFailed()) + if (!mSkinInfo) { - mSkinInfo = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this); - if (mSkinInfo) + const LLMeshSkinInfo* skin_info = gMeshRepo.getSkinInfo(volume_params.getSculptID(), this); + if (skin_info) { - notifySkinInfoLoaded(mSkinInfo); + notifySkinInfoLoaded(skin_info); } } } @@ -1171,7 +1170,6 @@ void LLVOVolume::updateSculptTexture() mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); } - mSkinInfoFailed = false; mSkinInfo = NULL; } else @@ -1227,17 +1225,29 @@ void LLVOVolume::notifyMeshLoaded() updateVisualComplexity(); } -void LLVOVolume::notifySkinInfoLoaded(LLMeshSkinInfo* skin) +void LLVOVolume::notifySkinInfoLoaded(const LLMeshSkinInfo* skin) { - mSkinInfoFailed = false; mSkinInfo = skin; + mSculptChanged = TRUE; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - notifyMeshLoaded(); + LLVOAvatar *av = getAvatar(); + if (av && !isAnimatedObject()) + { + av->addAttachmentOverridesForObject(this); + av->notifyAttachmentMeshLoaded(); + } + LLControlAvatar *cav = getControlAvatar(); + if (cav && isAnimatedObject()) + { + cav->addAttachmentOverridesForObject(this); + cav->notifyAttachmentMeshLoaded(); + } + updateVisualComplexity(); } void LLVOVolume::notifySkinInfoUnavailable() { - mSkinInfoFailed = true; mSkinInfo = nullptr; } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 764d398df53..30c9e4d4bc6 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -357,7 +357,7 @@ class LLVOVolume final : public LLViewerObject void updateVisualComplexity(); void notifyMeshLoaded(); - void notifySkinInfoLoaded(LLMeshSkinInfo* skin); + void notifySkinInfoLoaded(const LLMeshSkinInfo* skin); void notifySkinInfoUnavailable(); // Returns 'true' iff the media data for this object is in flight @@ -442,15 +442,7 @@ class LLVOVolume final : public LLViewerObject bool mResetDebugText; LLPointer<LLRiggedVolume> mRiggedVolume; - - bool hasSkinInfoFailed() const { return mSkinInfoFailed; } - - bool mSkinInfoFailed; - LLPointer<LLMeshSkinInfo> mSkinInfo; - std::unique_ptr <LLMatrix4a[]> mSkinMatrixCache; - std::unique_ptr <F32[]> mSkinRenderMatrixCache; - U32 mSkinRenderMatrixJointCount; - U32 mSkinLastRenderFrame; + LLConstPointer<LLMeshSkinInfo> mSkinInfo; // statics public: -- GitLab