summaryrefslogtreecommitdiff
path: root/indra/newview/llmeshrepository.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llmeshrepository.cpp')
-rw-r--r--indra/newview/llmeshrepository.cpp143
1 files changed, 118 insertions, 25 deletions
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 26e2d8f319..a8585c7f23 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -77,6 +77,8 @@
#include "llinventorypanel.h"
#include "lluploaddialog.h"
#include "llfloaterreg.h"
+#include "llvoavatarself.h"
+#include "llskinningutil.h"
#include "boost/iostreams/device/array.hpp"
#include "boost/iostreams/stream.hpp"
@@ -757,7 +759,7 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,
<< " (" << status.toTerseString() << ")" << LL_ENDL;
std::ostringstream details;
- typedef std::set<std::string> mav_errors_set_t;
+ typedef std::unordered_set<std::string> mav_errors_set_t;
mav_errors_set_t mav_errors;
if (content.has("error"))
@@ -828,7 +830,8 @@ LLMeshRepoThread::LLMeshRepoThread()
mHttpLargeOptions(),
mHttpHeaders(),
mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
- mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID)
+ mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID),
+ mWorkQueue("MeshRepoThread", 1024*1024)
{
LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp());
@@ -911,6 +914,10 @@ void LLMeshRepoThread::run()
break;
}
+ // run mWorkQueue for up to 8ms
+ static std::chrono::nanoseconds WorkTimeNanoSec{std::chrono::nanoseconds::rep(8 * 1000000) };
+ mWorkQueue.runFor(WorkTimeNanoSec);
+
if (! mHttpRequestSet.empty())
{
// Dispatch all HttpHandler notifications
@@ -1322,7 +1329,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url,
bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
{
-
+ LL_PROFILE_ZONE_SCOPED;
if (!mHeaderMutex)
{
return false;
@@ -1447,6 +1454,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry)
bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
{
+ LL_PROFILE_ZONE_SCOPED;
if (!mHeaderMutex)
{
return false;
@@ -1554,6 +1562,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
{
+ LL_PROFILE_ZONE_SCOPED;
if (!mHeaderMutex)
{
return false;
@@ -1693,6 +1702,7 @@ void LLMeshRepoThread::decActiveHeaderRequests()
//return false if failed to get header
bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry)
{
+ LL_PROFILE_ZONE_SCOPED;
++LLMeshRepository::sMeshRequestCount;
{
@@ -1756,6 +1766,7 @@ 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)
{
+ LL_PROFILE_ZONE_SCOPED;
if (!mHeaderMutex)
{
return false;
@@ -1940,6 +1951,18 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes
LLMeshRepository::sCacheBytesHeaders += (U32)header_size;
}
+ // immediately request SkinInfo since we'll need it before we can render any LoD if it is present
+ {
+ LLMutexLock lock(gMeshRepo.mMeshMutex);
+
+ if (gMeshRepo.mLoadingSkins.find(mesh_id) == gMeshRepo.mLoadingSkins.end())
+ {
+ gMeshRepo.mLoadingSkins[mesh_id] = {}; // add an empty vector to indicate to main thread that we are loading skin info
+ }
+ }
+
+ fetchMeshSkinInfo(mesh_id);
+
LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time.
//check for pending requests
@@ -1971,6 +1994,18 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p
{
if (volume->getNumFaces() > 0)
{
+ // if we have a valid SkinInfo, cache per-joint bounding boxes for this LOD
+ LLMeshSkinInfo* skin_info = mSkinMap[mesh_params.getSculptID()];
+ if (skin_info && isAgentAvatarValid())
+ {
+ for (S32 i = 0; i < volume->getNumFaces(); ++i)
+ {
+ // NOTE: no need to lock gAgentAvatarp as the state being checked is not changed after initialization
+ LLVolumeFace& face = volume->getVolumeFace(i);
+ LLSkinningUtil::updateRiggingInfo(skin_info, gAgentAvatarp, face);
+ }
+ }
+
LoadedMesh mesh(volume, mesh_params, lod);
{
LLMutexLock lock(mMutex);
@@ -2014,18 +2049,19 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
}
{
- 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;
+ LLPointer<LLMeshSkinInfo> info = nullptr;
+ info = new LLMeshSkinInfo(mesh_id, skin);
+
+ if (isAgentAvatarValid())
+ { // joint numbers are consistent inside LLVOAvatar and animations, but inconsistent inside meshes,
+ // generate a map of mesh joint numbers to LLVOAvatar joint numbers
+ LLSkinningUtil::initJointNums(info, gAgentAvatarp);
}
- // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL;
+ // remember the skin info in the background thread so we can use it
+ // to calculate per-joint bounding boxes when volumes are loaded
+ mSkinMap[mesh_id] = info;
+
{
LLMutexLock lock(mMutex);
mSkinInfoQ.push_back(info);
@@ -2265,10 +2301,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
S32 mesh_num = 0;
S32 texture_num = 0;
- std::set<LLViewerTexture* > textures;
- std::map<LLViewerTexture*,S32> texture_index;
+ std::unordered_set<LLViewerTexture* > textures;
+ std::unordered_map<LLViewerTexture*,S32> texture_index;
- std::map<LLModel*,S32> mesh_index;
+ std::unordered_map<LLModel*,S32> mesh_index;
std::string model_name;
S32 instance_num = 0;
@@ -2957,7 +2993,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()
{
if (mMutex->trylock())
{
- std::deque<LLMeshSkinInfo*> skin_info_q;
+ std::deque<LLPointer<LLMeshSkinInfo>> skin_info_q;
std::deque<UUIDBasedRequest> skin_info_unavail_q;
std::list<LLModel::Decomposition*> decomp_q;
@@ -3080,6 +3116,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLMeshHeader& header, S32 lod)
// are cases far off the norm.
void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)
{
+ LL_PROFILE_ZONE_SCOPED;
mProcessed = true;
unsigned int retries(0U);
@@ -3356,6 +3393,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)
void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
U8 * data, S32 data_size)
{
+ LL_PROFILE_ZONE_SCOPED;
if ((!MESH_LOD_PROCESS_FAILED)
&& ((data != NULL) == (data_size > 0))) // if we have data but no size or have size but no data, something is wrong
{
@@ -3421,6 +3459,7 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status)
void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
U8 * data, S32 data_size)
{
+ LL_PROFILE_ZONE_SCOPED;
if ((!MESH_SKIN_INFO_PROCESS_FAILED)
&& ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong
&& gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))
@@ -3470,6 +3509,7 @@ void LLMeshDecompositionHandler::processFailure(LLCore::HttpStatus status)
void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
U8 * data, S32 data_size)
{
+ LL_PROFILE_ZONE_SCOPED;
if ((!MESH_DECOMP_PROCESS_FAILED)
&& ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong
&& gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size))
@@ -3517,6 +3557,7 @@ void LLMeshPhysicsShapeHandler::processFailure(LLCore::HttpStatus status)
void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */,
U8 * data, S32 data_size)
{
+ LL_PROFILE_ZONE_SCOPED;
if ((!MESH_PHYS_SHAPE_PROCESS_FAILED)
&& ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong
&& gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size) == MESH_OK)
@@ -3651,20 +3692,63 @@ S32 LLMeshRepository::update()
return static_cast<S32>(size);
}
-void LLMeshRepository::unregisterMesh(LLVOVolume* vobj)
+void LLMeshRepository::unregisterMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail)
{
- for (auto& lod : mLoadingMeshes)
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
+ llassert((mesh_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
+ llassert(mesh_params.getSculptID().notNull());
+ auto& lod = mLoadingMeshes[detail];
+ auto param_iter = lod.find(mesh_params.getSculptID());
+ if (param_iter != lod.end())
+ {
+ vector_replace_with_last(param_iter->second, vobj);
+ llassert(!vector_replace_with_last(param_iter->second, vobj));
+ if (param_iter->second.empty())
+ {
+ lod.erase(param_iter);
+ }
+ }
+}
+
+void LLMeshRepository::unregisterSkinInfo(const LLUUID& mesh_id, LLVOVolume* vobj)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+
+ llassert(mesh_id.notNull());
+ auto skin_pair_iter = mLoadingSkins.find(mesh_id);
+ if (skin_pair_iter != mLoadingSkins.end())
{
- for (auto& param : lod)
+ vector_replace_with_last(skin_pair_iter->second, vobj);
+ llassert(!vector_replace_with_last(skin_pair_iter->second, vobj));
+ if (skin_pair_iter->second.empty())
{
- vector_replace_with_last(param.second, vobj);
+ mLoadingSkins.erase(skin_pair_iter);
}
}
+}
+
+// Lots of dead objects make expensive calls to
+// LLMeshRepository::unregisterMesh which may delay shutdown. Avoid this by
+// preemptively unregistering all meshes.
+// We can also do this safely if all objects are confirmed dead for some other
+// reason.
+void LLMeshRepository::unregisterAllMeshes()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
- for (auto& skin_pair : mLoadingSkins)
+ // The size of mLoadingMeshes and mLoadingSkins may be large and thus
+ // expensive to iterate over in LLVOVolume::~LLVOVolume.
+ // This is unnecessary during shutdown, so we ignore the referenced objects in the
+ // least expensive way which is still safe: by clearing these containers.
+ // Clear now and not in LLMeshRepository::shutdown because
+ // LLMeshRepository::notifyLoadedMeshes could (depending on invocation
+ // order) reference a pointer to an object after it has been deleted.
+ for (auto& lod : mLoadingMeshes)
{
- vector_replace_with_last(skin_pair.second, vobj);
+ lod.clear();
}
+ mLoadingSkins.clear();
}
S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod)
@@ -3859,6 +3943,7 @@ void LLMeshRepository::notifyLoadedMeshes()
for (auto iter = mSkinMap.begin(), ender = mSkinMap.end(); iter != ender;)
{
auto copy_iter = iter++;
+ LLUUID id = copy_iter->first;
//skinbytes += U64Bytes(sizeof(LLMeshSkinInfo));
//skinbytes += U64Bytes(copy_iter->second->mJointNames.size() * sizeof(std::string));
@@ -3870,6 +3955,12 @@ void LLMeshRepository::notifyLoadedMeshes()
{
mSkinMap.erase(copy_iter);
}
+
+ // erase from background thread
+ mThread->mWorkQueue.post([=]()
+ {
+ mThread->mSkinMap.erase(id);
+ });
}
//LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL;
}
@@ -4206,7 +4297,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
{
LLMutexLock lock(mMeshMutex);
//add volume to list of loading meshes
- std::set<LLUUID>::iterator iter = mLoadingPhysicsShapes.find(mesh_id);
+ std::unordered_set<LLUUID>::iterator iter = mLoadingPhysicsShapes.find(mesh_id);
if (iter == mLoadingPhysicsShapes.end())
{ //no request pending for this skin info
// *FIXME: Nothing ever deletes entries, can't be right
@@ -4236,7 +4327,7 @@ LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id
{
LLMutexLock lock(mMeshMutex);
//add volume to list of loading meshes
- std::set<LLUUID>::iterator iter = mLoadingDecompositions.find(mesh_id);
+ std::unordered_set<LLUUID>::iterator iter = mLoadingDecompositions.find(mesh_id);
if (iter == mLoadingDecompositions.end())
{ //no request pending for this skin info
mLoadingDecompositions.insert(mesh_id);
@@ -4287,6 +4378,8 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
bool LLMeshRepository::hasSkinInfo(const LLUUID& mesh_id)
{
+ LL_PROFILE_ZONE_SCOPED;
+
if (mesh_id.isNull())
{
return false;