From 7c831d115b55b96129806353a51a01dcf2bcebba Mon Sep 17 00:00:00 2001
From: RunitaiLinden <davep@lindenlab.com>
Date: Mon, 3 Apr 2023 17:22:40 -0500
Subject: [PATCH] SL-18458 Make LLVOCache the one source of truth on most
 recently received overrides. (#147)

---
 indra/llprimitive/lltextureentry.cpp    | 11 ++++--
 indra/llprimitive/lltextureentry.h      |  2 +-
 indra/newview/llappviewer.cpp           |  2 +-
 indra/newview/llfetchedgltfmaterial.cpp |  2 +-
 indra/newview/llgltfmateriallist.cpp    | 45 +++++++++++------------
 indra/newview/llspatialpartition.cpp    |  5 +--
 indra/newview/llviewerobject.cpp        | 23 ++++++------
 indra/newview/llviewerregion.cpp        | 35 ++++++++++--------
 indra/newview/llviewerregion.h          |  2 ++
 indra/newview/llvocache.cpp             | 47 ++++++++++++++++++-------
 indra/newview/llvocache.h               |  8 +++--
 11 files changed, 112 insertions(+), 70 deletions(-)

diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index a665db378b3..17b1f4cf5cb 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -559,10 +559,17 @@ void LLTextureEntry::setGLTFMaterial(LLGLTFMaterial* material, bool local_origin
     }
 }
 
-void LLTextureEntry::setGLTFMaterialOverride(LLGLTFMaterial* mat)
+S32 LLTextureEntry::setGLTFMaterialOverride(LLGLTFMaterial* mat)
 { 
     llassert(mat == nullptr || getGLTFMaterial() != nullptr); // if override is not null, base material must not be null
-    mGLTFMaterialOverrides = mat; 
+    if (mat == mGLTFMaterialOverrides)
+    {
+        return TEM_CHANGE_NONE;
+    }
+
+    mGLTFMaterialOverrides = mat;
+
+    return TEM_CHANGE_TEXTURE;
 }
 
 S32 LLTextureEntry::setBaseMaterial()
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index 9a81181f3a5..f5f2c0172d8 100644
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -200,7 +200,7 @@ class LLTextureEntry
 
     // GLTF override
     LLGLTFMaterial* getGLTFMaterialOverride() const { return mGLTFMaterialOverrides; }
-    void setGLTFMaterialOverride(LLGLTFMaterial* mat);
+    S32 setGLTFMaterialOverride(LLGLTFMaterial* mat);
     // Clear most overrides so the render material better matches the material
     // ID (preserve transforms). If the overrides become passthrough, set the
     // overrides to nullptr.
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 12ed123805d..b17c78abac2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -4281,7 +4281,7 @@ U32 LLAppViewer::getObjectCacheVersion()
 {
 	// Viewer object cache version, change if object update
 	// format changes. JC
-	const U32 INDRA_OBJECT_CACHE_VERSION = 15;
+	const U32 INDRA_OBJECT_CACHE_VERSION = 16;
 
 	return INDRA_OBJECT_CACHE_VERSION;
 }
diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp
index 2e71b4fa87b..4efe1ad189c 100644
--- a/indra/newview/llfetchedgltfmaterial.cpp
+++ b/indra/newview/llfetchedgltfmaterial.cpp
@@ -89,7 +89,7 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)
 
     if (!LLPipeline::sShadowRender)
     {
-        if (mNormalTexture.notNull())
+        if (mNormalTexture.notNull() && mNormalTexture->getDiscardLevel() <= 4)
         {
             shader->bindTexture(LLShaderMgr::BUMP_MAP, mNormalTexture);
         }
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 57a67f52f62..08ce43434f0 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -192,14 +192,7 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
         {
             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);
-            }
+            LLViewerRegion * region = LLWorld::instance().getRegionFromHandle(object_override.mRegionHandle);
 
             if (region)
             {
@@ -248,8 +241,8 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
             {
                 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();
+                std::unordered_map<S32, std::string>::const_iterator iter = object_override.mSides.begin();
+                std::unordered_map<S32, std::string>::const_iterator end = object_override.mSides.end();
                 while (iter != end)
                 {
                     LLPointer<LLGLTFMaterial> override_data = new LLGLTFMaterial();
@@ -278,7 +271,6 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
         },
             [object_override, this](std::vector<ReturnData> results) // Callback to main thread
             {
-
             LLViewerObject * obj = gObjectList.findObject(object_override.mObjectId);
 
             if (results.size() > 0 )
@@ -292,23 +284,16 @@ class LLGLTFMaterialOverrideDispatchHandler : public LLDispatchHandler
                         // flag this side to not be nulled out later
                         side_set.insert(results[i].mSide);
 
-                        if (!obj || !obj->setTEGLTFMaterialOverride(results[i].mSide, results[i].mMaterial))
+                        if (obj)
                         {
-                            // object not ready to receive override data, queue for later
-                            gGLTFMaterialList.queueOverrideUpdate(object_override.mObjectId, results[i].mSide, results[i].mMaterial);
-                        }
-                        else if (obj && obj->getTE(results[i].mSide) && obj->getTE(results[i].mSide)->isSelected())
-                        {
-                            doSelectionCallbacks(object_override.mObjectId, results[i].mSide);
+                            obj->setTEGLTFMaterialOverride(results[i].mSide, results[i].mMaterial);
                         }
                     }
-                    else
+                    
+                    // unblock material editor
+                    if (obj && obj->getTE(results[i].mSide) && obj->getTE(results[i].mSide)->isSelected())
                     {
-                        // unblock material editor
-                        if (obj && obj->getTE(results[i].mSide) && obj->getTE(results[i].mSide)->isSelected())
-                        {
-                            doSelectionCallbacks(object_override.mObjectId, results[i].mSide);
-                        }
+                        doSelectionCallbacks(object_override.mObjectId, results[i].mSide);
                     }
                 }
 
@@ -353,6 +338,7 @@ namespace
 
 void LLGLTFMaterialList::queueOverrideUpdate(const LLUUID& id, S32 side, LLGLTFMaterial* override_data)
 {
+#if 0
     override_list_t& overrides = mQueuedOverrides[id];
     
     if (overrides.size() < side + 1)
@@ -361,6 +347,7 @@ void LLGLTFMaterialList::queueOverrideUpdate(const LLUUID& id, S32 side, LLGLTFM
     }
 
     overrides[side] = override_data;
+#endif
 }
 
 void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj)
@@ -368,6 +355,8 @@ void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj)
     LL_PROFILE_ZONE_SCOPED;
 
     llassert(obj);
+
+#if 0
     const LLUUID& id = obj->getID();
     auto iter = mQueuedOverrides.find(id);
 
@@ -410,6 +399,14 @@ void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj)
 
         mQueuedOverrides.erase(iter);
     }
+#else
+    // the override cache is the authoritarian source of the most recent override data
+    LLViewerRegion* regionp = obj->getRegion();
+    if (regionp)
+    {
+        regionp->applyCacheMiscExtras(obj);
+    }
+#endif
 }
 
 void LLGLTFMaterialList::queueModify(const LLViewerObject* obj, S32 side, const LLGLTFMaterial* mat)
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index fc9b3093e81..4d99ee13864 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1375,7 +1375,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
 		selecter.traverse(mOctree);
 	
 	return 0;
-	}
+}
 
 extern BOOL gCubeSnapshot;
 
@@ -1540,6 +1540,7 @@ void pushVertsColorCoded(LLSpatialGroup* group)
 //  - a linked rigged drawable face has the wrong draw order index
 bool check_rigged_group(LLDrawable* drawable)
 {
+#if 0
     if (drawable->isState(LLDrawable::RIGGED))
     {
         LLSpatialGroup* group = drawable->getSpatialGroup();
@@ -1587,7 +1588,7 @@ bool check_rigged_group(LLDrawable* drawable)
             }
         }
     }
-
+#endif
     return true;
 }
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 1c53bddb620..e641ac4215a 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5399,19 +5399,22 @@ S32 LLViewerObject::setTEGLTFMaterialOverride(U8 te, LLGLTFMaterial* override_ma
         return retval;
     }
 
-    tep->setGLTFMaterialOverride(override_mat);
+    retval = tep->setGLTFMaterialOverride(override_mat);
 
-    if (override_mat)
+    if (retval)
     {
-        LLFetchedGLTFMaterial* render_mat = new LLFetchedGLTFMaterial(*src_mat);
-        render_mat->applyOverride(*override_mat);
-        tep->setGLTFRenderMaterial(render_mat);
-        retval = TEM_CHANGE_TEXTURE;
+        if (override_mat)
+        {
+            LLFetchedGLTFMaterial* render_mat = new LLFetchedGLTFMaterial(*src_mat);
+            render_mat->applyOverride(*override_mat);
+            tep->setGLTFRenderMaterial(render_mat);
+            retval = TEM_CHANGE_TEXTURE;
 
-    }
-    else if (tep->setGLTFRenderMaterial(nullptr))
-    {
-        retval = TEM_CHANGE_TEXTURE;
+        }
+        else if (tep->setGLTFRenderMaterial(nullptr))
+        {
+            retval = TEM_CHANGE_TEXTURE;
+        }
     }
 
     return retval;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 192a96a4089..b159cc27504 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2651,20 +2651,8 @@ LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObjec
 
 void LLViewerRegion::cacheFullUpdateGLTFOverride(const LLGLTFOverrideCacheEntry &override_data)
 {
-    LLUUID object_id = override_data.mObjectId;
-    LLViewerObject * obj = gObjectList.findObject(object_id);
-    if (obj != nullptr)
-    {
-        llassert(obj->getRegion() == this);
-
-        U32 local_id = obj->getLocalID();
-
-        mImpl->mGLTFOverridesJson[local_id] = override_data;
-    }
-    else
-    {
-        LL_WARNS("GLTF") << "got material override for unknown object_id, cannot cache it" << LL_ENDL;
-    }
+    U32 object_id = override_data.mLocalId;
+    mImpl->mGLTFOverridesJson[object_id] = override_data;
 }
 
 LLVOCacheEntry* LLViewerRegion::getCacheEntryForOctree(U32 local_id)
@@ -3560,3 +3548,22 @@ void LLViewerRegion::loadCacheMiscExtras(U32 local_id)
         LLGLTFMaterialList::loadCacheOverrides(iter->second);
     }
 }
+
+void LLViewerRegion::applyCacheMiscExtras(LLViewerObject* obj)
+{
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+    llassert(obj);
+
+    U32 local_id = obj->getLocalID();
+    auto iter = mImpl->mGLTFOverridesJson.find(local_id);
+    if (iter != mImpl->mGLTFOverridesJson.end())
+    {
+        llassert(iter->second.mGLTFMaterial.size() == iter->second.mSides.size());
+
+        for (auto& side : iter->second.mGLTFMaterial)
+        {
+            obj->setTEGLTFMaterialOverride(side.first, side.second);
+        }
+    }
+}
+
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index b132a3a5f36..fe0fdfb9306 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -426,6 +426,8 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 public:
 	void loadCacheMiscExtras(U32 local_id);
 
+    void applyCacheMiscExtras(LLViewerObject* obj);
+
 	struct CompareDistance
 	{
 		bool operator()(const LLViewerRegion* const& lhs, const LLViewerRegion* const& rhs)
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 0fbcf9c6243..7081ecaa4b5 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -57,9 +57,14 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)
 
 bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
 {
-    if (!data.has("object_id"))
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
+    
+    llassert(data.has("local_id"));
+    llassert(data.has("object_id"));
+    llassert(data.has("region_handle_x") && data.has("region_handle_y"));
+
+    if (!data.has("local_id"))
     {
-        mObjectId.setNull();
         return false;
     }
 
@@ -69,13 +74,13 @@ bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
         U32 region_handle_y = data["region_handle_y"].asInteger();
         U32 region_handle_x = data["region_handle_x"].asInteger();
         mRegionHandle = to_region_handle(region_handle_x, region_handle_y);
-        mHasRegionHandle = true;
     }
     else
     {
-        mHasRegionHandle = false;
+        return false;
     }
 
+    mLocalId = data["local_id"].asInteger();
     mObjectId = data["object_id"];
 
     // message should be interpreted thusly:
@@ -94,7 +99,26 @@ bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
             for (int i = 0; i < sides.size(); ++i)
             {
                 S32 side_idx = sides[i].asInteger();
-                mSides[side_idx] = gltf_json[i].asString();
+                std::string gltf_json_str = gltf_json[i].asString();
+                mSides[side_idx] = gltf_json_str;
+                LLGLTFMaterial* override_mat = new LLGLTFMaterial();
+                std::string error, warn;
+                if (override_mat->fromJSON(gltf_json_str, warn, error))
+                {
+                    mGLTFMaterial[i] = override_mat;
+                }
+                else
+                {
+                    LL_WARNS() << "Invalid GLTF string: \n" << gltf_json_str << LL_ENDL;
+                    if (!error.empty())
+                    {
+                        LL_WARNS() << "Error: " << error << LL_ENDL;
+                    }
+                    if (!warn.empty())
+                    {
+                        LL_WARNS() << "Warning: " << warn << LL_ENDL;
+                    }
+                }
             }
         }
         else
@@ -107,16 +131,15 @@ bool LLGLTFOverrideCacheEntry::fromLLSD(const LLSD& data)
 
 LLSD LLGLTFOverrideCacheEntry::toLLSD() const
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK;
     LLSD data;
-    if (mHasRegionHandle)
-    {
-        U32 region_handle_x, region_handle_y;
-        from_region_handle(mRegionHandle, &region_handle_x, &region_handle_y);
-        data["region_handle_y"] = LLSD::Integer(region_handle_y);
-        data["region_handle_x"] = LLSD::Integer(region_handle_x);
-    }
+    U32 region_handle_x, region_handle_y;
+    from_region_handle(mRegionHandle, &region_handle_x, &region_handle_y);
+    data["region_handle_y"] = LLSD::Integer(region_handle_y);
+    data["region_handle_x"] = LLSD::Integer(region_handle_x);
 
     data["object_id"] = mObjectId;
+    data["local_id"] = (LLSD::Integer) mLocalId;
 
     for (auto const & side : mSides)
     {
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index dcc8d37c5c3..ec0df318285 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -32,6 +32,7 @@
 #include "lldir.h"
 #include "llvieweroctree.h"
 #include "llapr.h"
+#include "llgltfmaterial.h"
 
 #include <unordered_map>
 
@@ -46,9 +47,10 @@ class LLGLTFOverrideCacheEntry
     LLSD toLLSD() const;
 
     LLUUID mObjectId;
-    std::map<S32, std::string> mSides; //json per side
-    U64 mRegionHandle;
-    bool mHasRegionHandle;
+    U32    mLocalId = 0;
+    std::unordered_map<S32, std::string> mSides; //json per side
+    std::unordered_map<S32, LLPointer<LLGLTFMaterial> > mGLTFMaterial; //GLTF material per side
+    U64 mRegionHandle = 0;
 };
 
 class LLVOCacheEntry 
-- 
GitLab