From a83a4811b51472b5f760861b6a8acde5fc3bd43b Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Wed, 9 Nov 2022 22:45:20 +0200
Subject: SL-18518 Move json to material work to background thread

---
 indra/newview/llgltfmateriallist.cpp | 164 ++++++++++++++++++++++-------------
 indra/newview/llgltfmateriallist.h   |  11 +++
 2 files changed, 113 insertions(+), 62 deletions(-)

(limited to 'indra')

diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 8e184c719d..c18988ef15 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -271,92 +271,132 @@ void LLGLTFMaterialList::flushModifyMaterialQueue(void(*done_callback)(bool))
     sModifyQueue.clear();
 }
 
-LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
+class AssetLoadUserData
 {
-    LL_PROFILE_ZONE_SCOPED;
-    uuid_mat_map_t::iterator iter = mList.find(id);
-    if (iter == mList.end())
+public:
+    AssetLoadUserData() {}
+    tinygltf::Model mModelIn;
+    LLPointer<LLFetchedGLTFMaterial> mMaterial;
+};
+
+void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status)
+{
+    LL_PROFILE_ZONE_NAMED("gltf asset callback");
+    AssetLoadUserData* asset_data = (AssetLoadUserData*)user_data;
+
+    if (status != LL_ERR_NOERR)
+    {
+        LL_WARNS() << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL;
+        asset_data->mMaterial->mFetching = false;
+        delete asset_data;
+    }
+    else
     {
-        LL_PROFILE_ZONE_NAMED("gltf fetch")
-        LLFetchedGLTFMaterial* mat = new LLFetchedGLTFMaterial();
-        mList[id] = mat;
 
-        if (!mat->mFetching)
-        {
-            // if we do multiple getAssetData calls,
-            // some will get distched, messing ref counter
-            // Todo: get rid of mat->ref()
-            mat->mFetching = true;
-            mat->ref();
+        LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
+        LL::WorkQueue::ptr_t general_queue = LL::WorkQueue::getInstance("General");
 
-            gAssetStorage->getAssetData(id, LLAssetType::AT_MATERIAL,
-                [=](const LLUUID& id, LLAssetType::EType asset_type, void* user_data, S32 status, LLExtStat ext_status)
+        typedef std::pair<U32, tinygltf::Model> return_data_t;
+
+        main_queue->postTo(
+            general_queue,
+            [id, asset_type, asset_data]() // Work done on general queue
+        {
+            std::vector<char> buffer;
             {
-                LL_PROFILE_ZONE_NAMED("gltf asset callback");
-                if (status)
+                LL_PROFILE_ZONE_NAMED("gltf read asset");
+                LLFileSystem file(id, asset_type, LLFileSystem::READ);
+                auto size = file.getSize();
+                if (!size)
                 {
-                    LL_WARNS() << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL;
+                    return false;
                 }
 
-                std::vector<char> buffer;
+                buffer.resize(size);
+                file.read((U8*)&buffer[0], buffer.size());
+            }
 
-                {
-                    LL_PROFILE_ZONE_NAMED("gltf read asset");
-                    LLFileSystem file(id, asset_type, LLFileSystem::READ);
-                    auto size = file.getSize();
-                    if (!size)
-                    {
-                        LL_DEBUGS() << "Zero size material." << LL_ENDL;
-                        mat->mFetching = false;
-                        mat->unref();
-                        return;
-                    }
+            {
+                LL_PROFILE_ZONE_NAMED("gltf deserialize asset");
 
+                LLSD asset;
 
+                // read file into buffer
+                std::istrstream str(&buffer[0], buffer.size());
 
-                    buffer.resize(size);
-                    file.read((U8*)&buffer[0], buffer.size());
-                }
-
+                if (LLSDSerialize::deserialize(asset, str, buffer.size()))
                 {
-                    LL_PROFILE_ZONE_NAMED("gltf deserialize asset");
-
-                    LLSD asset;
-
-                    // read file into buffer
-                    std::istrstream str(&buffer[0], buffer.size());
-
-                    if (LLSDSerialize::deserialize(asset, str, buffer.size()))
+                    if (asset.has("version") && asset["version"] == "1.0")
                     {
-                        if (asset.has("version") && asset["version"] == "1.0")
+                        if (asset.has("type") && asset["type"].asString() == "GLTF 2.0")
                         {
-                            if (asset.has("type") && asset["type"].asString() == "GLTF 2.0")
+                            if (asset.has("data") && asset["data"].isString())
                             {
-                                if (asset.has("data") && asset["data"].isString())
-                                {
-                                    std::string data = asset["data"];
+                                std::string data = asset["data"];
+
+                                std::string warn_msg, error_msg;
 
-                                    std::string warn_msg, error_msg;
+                                LL_PROFILE_ZONE_SCOPED;
+                                tinygltf::TinyGLTF gltf;
 
-                                    if (!mat->fromJSON(data, warn_msg, error_msg))
-                                    {
-                                        LL_WARNS() << "Failed to decode material asset: " << LL_ENDL;
-                                        LL_WARNS() << warn_msg << LL_ENDL;
-                                        LL_WARNS() << error_msg << LL_ENDL;
-                                    }
+                                if (!gltf.LoadASCIIFromString(&asset_data->mModelIn, &error_msg, &warn_msg, data.c_str(), data.length(), ""))
+                                {
+                                    LL_WARNS() << "Failed to decode material asset: "
+                                        << LL_NEWLINE
+                                        << warn_msg
+                                        << LL_NEWLINE
+                                        << error_msg
+                                        << LL_ENDL;
+                                    return false;
                                 }
+                                return true;
                             }
                         }
                     }
-                    else
-                    {
-                        LL_WARNS() << "Failed to deserialize material LLSD" << LL_ENDL;
-                    }
                 }
+                else
+                {
+                    LL_WARNS() << "Failed to deserialize material LLSD" << LL_ENDL;
+                }
+            }
+
+            return false;
+        },
+            [id, asset_data](bool result) // Callback to main thread
+            mutable {
+
+            if (result)
+            {
+                asset_data->mMaterial->setFromModel(asset_data->mModelIn, 0/*only one index*/);
+            }
+            else
+            {
+                LL_DEBUGS() << "Failed to get material " << id << LL_ENDL;
+            }
+            asset_data->mMaterial->mFetching = false;
+            delete asset_data;
+        });
+    }
+}
+
+LLGLTFMaterial* LLGLTFMaterialList::getMaterial(const LLUUID& id)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    uuid_mat_map_t::iterator iter = mList.find(id);
+    if (iter == mList.end())
+    {
+        LL_PROFILE_ZONE_NAMED("gltf fetch")
+        LLFetchedGLTFMaterial* mat = new LLFetchedGLTFMaterial();
+        mList[id] = mat;
+
+        if (!mat->mFetching)
+        {
+            mat->mFetching = true;
+
+            AssetLoadUserData *user_data = new AssetLoadUserData();
+            user_data->mMaterial = mat;
 
-                mat->mFetching = false;
-                mat->unref();
-            }, nullptr);
+            gAssetStorage->getAssetData(id, LLAssetType::AT_MATERIAL, onAssetLoadComplete, (void*)user_data);
         }
         
         return mat;
diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h
index e035d2108d..2dae11d2ca 100644
--- a/indra/newview/llgltfmateriallist.h
+++ b/indra/newview/llgltfmateriallist.h
@@ -26,6 +26,8 @@
 
 #pragma once
 
+#include "llassettype.h"
+#include "llextendedstatus.h"
 #include "llfetchedgltfmaterial.h"
 #include "llgltfmaterial.h"
 #include "llpointer.h"
@@ -69,6 +71,15 @@ public:
     void queueOverrideUpdate(const LLUUID& id, S32 side, LLGLTFMaterial* override_data);
 
     void applyQueuedOverrides(LLViewerObject* obj);
+
+protected:
+    static void onAssetLoadComplete(
+        const LLUUID& asset_uuid,
+        LLAssetType::EType type,
+        void* user_data,
+        S32 status,
+        LLExtStat ext_status);
+
 private:
     typedef std::unordered_map<LLUUID, LLPointer<LLFetchedGLTFMaterial > > uuid_mat_map_t;
     uuid_mat_map_t mList;
-- 
cgit v1.2.3