diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-11-24 12:16:59 +0200 |
---|---|---|
committer | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2022-11-24 20:58:05 +0200 |
commit | 32984b56ea8fa4f4357379a40627b5e9267d7543 (patch) | |
tree | c332e615cc6b609f6eb924198500a0d61e6f980b | |
parent | dfa76a56e32b8577131542f5c412b48797f8d3d3 (diff) |
SL-18701 llsd is not thread safe, parse it before using
-rw-r--r-- | indra/newview/llgltfmateriallist.cpp | 161 | ||||
-rw-r--r-- | indra/newview/llgltfmateriallist.h | 6 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.h | 2 | ||||
-rw-r--r-- | indra/newview/llpanelface.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llviewermenu.cpp | 4 | ||||
-rwxr-xr-x | indra/newview/llviewerregion.cpp | 18 | ||||
-rw-r--r-- | indra/newview/llviewerregion.h | 4 | ||||
-rw-r--r-- | indra/newview/llvocache.cpp | 73 | ||||
-rw-r--r-- | indra/newview/llvocache.h | 19 |
10 files changed, 183 insertions, 110 deletions
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index a604930715..45de0b71ae 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -42,6 +42,7 @@ #include "llviewerstats.h" #include "llcorehttputil.h" #include "llagent.h" +#include "llvocache.h" #include "llworld.h" #include "tinygltf/tiny_gltf.h" @@ -159,14 +160,14 @@ public: LLSD message; sparam_t::const_iterator it = strings.begin(); - if (it != strings.end()) { + if (it != strings.end()) + { const std::string& llsdRaw = *it++; std::istringstream llsdData(llsdRaw); if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) { LL_WARNS() << "LLGLTFMaterialOverrideDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; } - LLGLTFMaterialList::writeCacheOverrides(message, llsdRaw); } else { @@ -175,99 +176,118 @@ public: return false; } - if (!message.has("object_id")) + LLGLTFOverrideCacheEntry object_override; + if (!object_override.fromLLSD(message)) { // malformed message, nothing we can do to handle it LL_DEBUGS("GLTF") << "Message without id:" << message << LL_ENDL; return false; } + // Cache the data + { + LL_DEBUGS("GLTF") << "material overrides cache" << LL_ENDL; + + // default to main region if message doesn't specify + LLViewerRegion * region = gAgent.getRegion();; + + if (object_override.mHasRegionHandle) + { + // TODO start requiring this once server sends this for all messages + region = LLWorld::instance().getRegionFromHandle(object_override.mRegionHandle); + } + + if (region) + { + region->cacheFullUpdateGLTFOverride(object_override); + } + else + { + LL_WARNS("GLTF") << "could not access region for material overrides message cache, region_handle: " << LL_ENDL; + } + } + applyData(object_override); + return true; + } + + static void applyData(const LLGLTFOverrideCacheEntry &object_override) + { + // Parse the data + LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop"); LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General"); struct ReturnData { public: - std::vector<LLPointer<LLGLTFMaterial> > mMaterialVector; - std::vector<bool> mResults; + LLPointer<LLGLTFMaterial> mMaterial; + S32 mSide; + bool mSuccess; }; // fromJson() is performance heavy offload to a thread. main_queue->postTo( general_queue, - [message]() // Work done on general queue + [object_override]() // Work done on general queue { - ReturnData result; + std::vector<ReturnData> results; - if (message.has("sides") && message.has("gltf_json")) + if (!object_override.mSides.empty()) { - LLSD const& sides = message.get("sides"); - LLSD const& gltf_json = message.get("gltf_json"); - - if (sides.isArray() && gltf_json.isArray() && - sides.size() != 0 && - sides.size() == gltf_json.size()) + results.reserve(object_override.mSides.size()); + // parse json + std::map<S32, std::string>::const_iterator iter = object_override.mSides.begin(); + std::map<S32, std::string>::const_iterator end = object_override.mSides.end(); + while (iter != end) { - // message should be interpreted thusly: - /// sides is a list of face indices - // gltf_json is a list of corresponding json - // any side not represented in "sides" has no override - result.mResults.resize(sides.size()); - result.mMaterialVector.resize(sides.size()); - - // parse json - for (int i = 0; i < sides.size(); ++i) - { - LLPointer<LLGLTFMaterial> override_data = new LLGLTFMaterial(); - - std::string gltf_json_str = gltf_json[i].asString(); + LLPointer<LLGLTFMaterial> override_data = new LLGLTFMaterial(); + std::string warn_msg, error_msg; - std::string warn_msg, error_msg; + bool success = override_data->fromJSON(iter->second, warn_msg, error_msg); - bool success = override_data->fromJSON(gltf_json_str, warn_msg, error_msg); + ReturnData result; + result.mSuccess = success; + result.mSide = iter->first; - result.mResults[i] = success; - - if (success) - { - result.mMaterialVector[i] = override_data; - } - else - { - LL_WARNS("GLTF") << "failed to parse GLTF override data. errors: " << error_msg << " | warnings: " << warn_msg << LL_ENDL; - } + if (success) + { + result.mMaterial = override_data; } + else + { + LL_WARNS("GLTF") << "failed to parse GLTF override data. errors: " << error_msg << " | warnings: " << warn_msg << LL_ENDL; + } + + results.push_back(result); + iter++; } } - return result; + return results; }, - [message](ReturnData result) // Callback to main thread + [object_override](std::vector<ReturnData> results) // Callback to main thread { - LLUUID object_id = message.get("object_id").asUUID(); - LLViewerObject * obj = gObjectList.findObject(object_id); + LLViewerObject * obj = gObjectList.findObject(object_override.mObjectId); - if (result.mResults.size() > 0 ) + if (results.size() > 0 ) { - LLSD const& sides = message.get("sides"); std::unordered_set<S32> side_set; - for (int i = 0; i < result.mResults.size(); ++i) + for (int i = 0; i < results.size(); ++i) { - if (result.mResults[i]) + if (results[i].mSuccess) { - S32 side = sides[i].asInteger(); // flag this side to not be nulled out later - side_set.insert(sides[i]); + side_set.insert(results[i].mSide); - if (!obj || !obj->setTEGLTFMaterialOverride(side, result.mMaterialVector[i])) + if (!obj || !obj->setTEGLTFMaterialOverride(results[i].mSide, results[i].mMaterial)) { // object not ready to receive override data, queue for later - gGLTFMaterialList.queueOverrideUpdate(object_id, side, result.mMaterialVector[i]); + gGLTFMaterialList.queueOverrideUpdate(object_override.mObjectId, results[i].mSide, results[i].mMaterial); } else if (obj && obj->isAnySelected()) { - LLMaterialEditor::updateLive(object_id, side); + LLMaterialEditor::updateLive(object_override.mObjectId, results[i].mSide); } } else @@ -275,7 +295,7 @@ public: // unblock material editor if (obj && obj->isAnySelected()) { - LLMaterialEditor::updateLive(object_id, sides[i].asInteger()); + LLMaterialEditor::updateLive(object_override.mObjectId, results[i].mSide); } } } @@ -290,7 +310,7 @@ public: obj->setTEGLTFMaterialOverride(i, nullptr); if (object_has_selection) { - LLMaterialEditor::updateLive(object_id, i); + LLMaterialEditor::updateLive(object_override.mObjectId, i); } } } @@ -309,8 +329,6 @@ public: } } }); - - return true; } }; @@ -439,8 +457,6 @@ void LLGLTFMaterialList::flushUpdates(void(*done_callback)(bool)) sUpdates = LLSD::emptyArray(); } - - } class AssetLoadUserData @@ -695,32 +711,7 @@ void LLGLTFMaterialList::modifyMaterialCoro(std::string cap_url, LLSD overrides, } } -void LLGLTFMaterialList::writeCacheOverrides(LLSD const & message, std::string const & llsdRaw) +void LLGLTFMaterialList::loadCacheOverrides(const LLGLTFOverrideCacheEntry& override) { - LL_DEBUGS("GLTF") << "material overrides cache" << LL_ENDL; - - // default to main region if message doesn't specify - LLViewerRegion * region = gAgent.getRegion();; - - if (message.has("region_handle_low") && message.has("region_handle_high")) - { - // TODO start requiring this once server sends this for all messages - U64 region_handle_low = message["region_handle_low"].asInteger(); - U64 region_handle_high = message["region_handle_high"].asInteger(); - U64 region_handle = (region_handle_low & 0x00000000ffffffffUL) || (region_handle_high << 32); - region = LLWorld::instance().getRegionFromHandle(region_handle); - } - - if (region) { - region->cacheFullUpdateExtras(message, llsdRaw); - } else { - LL_WARNS("GLTF") << "could not access region for material overrides message cache, region_handle: " << LL_ENDL; - } -} - -void LLGLTFMaterialList::loadCacheOverrides(std::string const & message) -{ - std::vector<std::string> strings(1, message); - - handle_gltf_override_message(nullptr, "", LLUUID::null, strings); + LLGLTFMaterialOverrideDispatchHandler::applyData(override); } diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index 805b477248..0f0edf7414 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -35,6 +35,7 @@ #include <unordered_map> class LLFetchedGLTFMaterial; +class LLGLTFOverrideCacheEntry; class LLGLTFMaterialList { @@ -89,10 +90,7 @@ public: // any override data that arrived before the object was ready to receive it void applyQueuedOverrides(LLViewerObject* obj); - // takes both the parsed message and its raw text to avoid unnecessary re serialization - static void writeCacheOverrides(LLSD const & message, std::string const & llsdRaw); - - static void loadCacheOverrides(std::string const & message_raw); + static void loadCacheOverrides(const LLGLTFOverrideCacheEntry& override); private: friend class LLGLTFMaterialOverrideDispatchHandler; diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index d5948b297c..d5339777c4 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -1008,7 +1008,7 @@ static U32 write_texture(const LLUUID& id, tinygltf::Model& model) void LLMaterialEditor::onClickSave() { - if (!capabilitiesAvalaible()) + if (!capabilitiesAvailable()) { LLNotificationsUtil::add("MissingMaterialCaps"); return; @@ -3067,7 +3067,7 @@ void LLMaterialEditor::loadDefaults() setFromGltfModel(model_in, 0, true); } -bool LLMaterialEditor::capabilitiesAvalaible() +bool LLMaterialEditor::capabilitiesAvailable() { const LLViewerRegion* region = gAgent.getRegion(); if (!region) diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 3520709a31..23d5434ff7 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -229,7 +229,7 @@ public: U32 getUnsavedChangesFlags() { return mUnsavedChanges; } U32 getRevertedChangesFlags() { return mRevertedChanges; } - static bool capabilitiesAvalaible(); + static bool capabilitiesAvailable(); private: static bool updateInventoryItem(const std::string &buffer, const LLUUID &item_id, const LLUUID &task_id); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 98f7adabd9..84b1ff63f4 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -1774,7 +1774,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, has_pbr_material = false; BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced(); - bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvalaible(); + bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); // pbr material LLTextureCtrl* pbr_ctrl = findChild<LLTextureCtrl>("pbr_control"); diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 76a5cf8f5e..c67d76100a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2807,7 +2807,7 @@ struct LLSelectedTEGetmatIdAndPermissions : public LLSelectedTEFunctor bool enable_object_edit_gltf_material() { - if (!LLMaterialEditor::capabilitiesAvalaible()) + if (!LLMaterialEditor::capabilitiesAvailable()) { return false; } @@ -2819,7 +2819,7 @@ bool enable_object_edit_gltf_material() bool enable_object_save_gltf_material() { - if (!LLMaterialEditor::capabilitiesAvalaible()) + if (!LLMaterialEditor::capabilitiesAvailable()) { return false; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 5ecc081782..e3ac1767fb 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -215,7 +215,7 @@ public: LLVOCacheEntry::vocache_entry_set_t mVisibleEntries; //must-be-created visible entries wait for objects creation. LLVOCacheEntry::vocache_entry_priority_list_t mWaitingList; //transient list storing sorted visible entries waiting for object creation. std::set<U32> mNonCacheableCreatedList; //list of local ids of all non-cacheable objects - LLVOCacheEntry::vocache_extras_entry_map_t mCacheExtraJson; // for materials + LLVOCacheEntry::vocache_gltf_overrides_map_t mGLTFOverridesJson; // for materials // time? // LRU info? @@ -786,7 +786,7 @@ void LLViewerRegion::loadObjectCache() { LLVOCache & vocache = LLVOCache::instance(); vocache.readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; - vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheExtraJson); + vocache.readGenericExtrasFromCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesJson); if (mImpl->mCacheMap.empty()) { @@ -815,7 +815,7 @@ void LLViewerRegion::saveObjectCache() LLVOCache & instance = LLVOCache::instance(); instance.writeToCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap, mCacheDirty, removal_enabled) ; - instance.writeGenericExtrasToCache(mHandle, mImpl->mCacheID, mImpl->mCacheExtraJson, mCacheDirty, removal_enabled); + instance.writeGenericExtrasToCache(mHandle, mImpl->mCacheID, mImpl->mGLTFOverridesJson, mCacheDirty, removal_enabled); mCacheDirty = FALSE; } @@ -2640,15 +2640,15 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec return result; } -void LLViewerRegion::cacheFullUpdateExtras(LLSD const & extras, std::string const & extras_raw) +void LLViewerRegion::cacheFullUpdateGLTFOverride(const LLGLTFOverrideCacheEntry &override_data) { - LLUUID object_id = extras["object_id"].asUUID(); + LLUUID object_id = override_data.mObjectId; LLViewerObject * obj = gObjectList.findObject(object_id); if (obj != nullptr) { U32 local_id = obj->getLocalID(); - mImpl->mCacheExtraJson[local_id] = LLVOCacheEntry::ExtrasEntry{extras, extras_raw}; + mImpl->mGLTFOverridesJson[local_id] = override_data; } else { @@ -3542,9 +3542,9 @@ std::string LLViewerRegion::getSimHostName() void LLViewerRegion::loadCacheMiscExtras(U32 local_id, LLVOCacheEntry * entry, U32 crc) { - auto iter = mImpl->mCacheExtraJson.find(local_id); - if (iter != mImpl->mCacheExtraJson.end()) + auto iter = mImpl->mGLTFOverridesJson.find(local_id); + if (iter != mImpl->mGLTFOverridesJson.end()) { - LLGLTFMaterialList::loadCacheOverrides(iter->second.extras_raw); + LLGLTFMaterialList::loadCacheOverrides(iter->second); } } diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 85f5b48b48..ec507fb982 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -68,6 +68,7 @@ class LLHost; class LLBBox; class LLSpatialGroup; class LLDrawable; +class LLGLTFOverrideCacheEntry; class LLViewerRegionImpl; class LLViewerOctreeGroup; class LLVOCachePartition; @@ -349,7 +350,8 @@ public: // handle a full update message eCacheUpdateResult cacheFullUpdate(LLDataPackerBinaryBuffer &dp, U32 flags); eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp, U32 flags); - void cacheFullUpdateExtras(LLSD const & extras, std::string const & extras_raw); + + void cacheFullUpdateGLTFOverride(const LLGLTFOverrideCacheEntry &override_data); LLVOCacheEntry* getCacheEntryForOctree(U32 local_id); LLVOCacheEntry* getCacheEntry(U32 local_id, bool valid = true); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 2b93460d25..cb75426cce 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -57,6 +57,75 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) return apr_file->write(src, n_bytes) == n_bytes ; } +bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data) +{ + if (!data.has("object_id")) + { + mObjectId.setNull(); + return false; + } + + if (data.has("region_handle_low") && data.has("region_handle_high")) + { + // TODO start requiring this once server sends this for all messages + U64 region_handle_low = data["region_handle_low"].asInteger(); + U64 region_handle_high = data["region_handle_high"].asInteger(); + mRegionHandle = (region_handle_low & 0x00000000ffffffffUL) || (region_handle_high << 32); + mHasRegionHandle = true; + } + else + { + mHasRegionHandle = false; + } + + mObjectId = data["object_id"]; + + // message should be interpreted thusly: + /// sides is a list of face indices + // gltf_json is a list of corresponding json + // any side not represented in "sides" has no override + if (data.has("sides") && data.has("gltf_json")) + { + LLSD const& sides = data.get("sides"); + LLSD const& gltf_json = data.get("gltf_json"); + + if (sides.isArray() && gltf_json.isArray() && + sides.size() != 0 && + sides.size() == gltf_json.size()) + { + for (int i = 0; i < sides.size(); ++i) + { + S32 side_idx = sides[i].asInteger(); + mSides[side_idx] = gltf_json[i].asString(); + } + } + } + return true; +} + +LLSD LLGLTFOverrideCacheEntry::toLLSD() +{ + llassert(false); // "Function not tested!!! + + LLSD data; + if (mHasRegionHandle) + { + data["region_handle_low"] = LLSD::Integer(mRegionHandle & 0x00000000ffffffffUL); + data["region_handle_high"] = LLSD::Integer(mRegionHandle >> 32); + } + + data["object_id"] = mObjectId; + + std::map<S32, std::string>::const_iterator iter = mSides.begin(); + std::map<S32, std::string>::const_iterator end = mSides.end(); + while (iter != end) + { + data["sides"].append(LLSD::Integer(iter->first)); + data["sides"].append(iter->second); + } + + return data; +} //--------------------------------------------------------------------------- // LLVOCacheEntry @@ -1436,7 +1505,7 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca return ; } -void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map) +void LLVOCache::readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map) { LL_DEBUGS() << "TODO" << LL_ENDL; } @@ -1578,6 +1647,6 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry: return ; } -void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled) +void LLVOCache::writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled) { } diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 33c1dfef8d..f41e9301ca 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -39,6 +39,18 @@ // Cache entries class LLCamera; +class LLGLTFOverrideCacheEntry +{ +public: + bool fromLLSD(const LLSD& data); + LLSD toLLSD(); + + LLUUID mObjectId; + std::map<S32, std::string> mSides; //json per side + U64 mRegionHandle; + bool mHasRegionHandle; +}; + class LLVOCacheEntry : public LLViewerOctreeEntryData { @@ -152,7 +164,8 @@ public: typedef std::map<U32, LLPointer<LLVOCacheEntry> > vocache_entry_map_t; typedef std::set<LLVOCacheEntry*> vocache_entry_set_t; typedef std::set<LLVOCacheEntry*, CompareVOCacheEntry> vocache_entry_priority_list_t; - typedef std::unordered_map<U32, ExtrasEntry> vocache_extras_entry_map_t; + + typedef std::unordered_map<U32, LLGLTFOverrideCacheEntry> vocache_gltf_overrides_map_t; S32 mLastCameraUpdated; protected: @@ -275,10 +288,10 @@ public: void removeCache(ELLPath location, bool started = false) ; void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; - void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map); + void readGenericExtrasFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map); void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache, bool removal_enabled); - void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_extras_entry_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled); + void writeGenericExtrasToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_gltf_overrides_map_t& cache_extras_entry_map, BOOL dirty_cache, bool removal_enabled); void removeEntry(U64 handle) ; U32 getCacheEntries() { return mNumEntries; } |