From 45bcefd981e268b158d11d59f2ba9063293986a6 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Tue, 14 Jun 2022 16:39:46 +0300
Subject: [PATCH] SL-17475 fix remap causing an assert

---
 indra/llmath/llvolume.cpp                 |  4 +-
 indra/llmeshoptimizer/llmeshoptimizer.cpp | 59 ++++++++++++++++++++++-
 indra/llmeshoptimizer/llmeshoptimizer.h   | 13 ++++-
 indra/newview/llmodelpreview.cpp          |  2 +-
 4 files changed, 72 insertions(+), 6 deletions(-)

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 23f372f6e36..9efdcd4e8c1 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -4957,8 +4957,8 @@ void LLVolumeFace::remap()
 {
     // generate a remap buffer
     std::vector<unsigned int> remap(mNumIndices);
-    S32 remap_vertices_count = LLMeshOptimizer::generateRemapMulti(&remap[0],
-        NULL,
+    S32 remap_vertices_count = LLMeshOptimizer::generateRemapMultiU16(&remap[0],
+        mIndices,
         mNumIndices,
         mPositions,
         mNormals,
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp
index 8570887dddd..cb9716a9070 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.cpp
+++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp
@@ -152,7 +152,7 @@ void LLMeshOptimizer::optimizeVertexCacheU16(U16 * destination, const U16 * indi
     meshopt_optimizeVertexCache<unsigned short>(destination, indices, index_count, vertex_count);
 }
 
-size_t LLMeshOptimizer::generateRemapMulti(
+size_t LLMeshOptimizer::generateRemapMultiU32(
     unsigned int* remap,
     const U32 * indices,
     U64 index_count,
@@ -167,7 +167,62 @@ size_t LLMeshOptimizer::generateRemapMulti(
        {(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
     };
 
-    return meshopt_generateVertexRemapMulti(&remap[0], indices, index_count, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
+    // Remap can function without indices,
+    // but providing indices helps with removing unused vertices
+    U64 indeces_cmp = indices ? index_count : vertex_count;
+
+    // meshopt_generateVertexRemapMulti will throw an assert if (indices[i] >= vertex_count)
+    return meshopt_generateVertexRemapMulti(&remap[0], indices, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
+}
+
+size_t LLMeshOptimizer::generateRemapMultiU16(
+    unsigned int* remap,
+    const U16 * indices,
+    U64 index_count,
+    const LLVector4a * vertex_positions,
+    const LLVector4a * normals,
+    const LLVector2 * text_coords,
+    U64 vertex_count)
+{
+    meshopt_Stream streams[] = {
+       {(const float*)vertex_positions, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)normals, sizeof(F32) * 3, sizeof(F32) * 4},
+       {(const float*)text_coords, sizeof(F32) * 2, sizeof(F32) * 2},
+    };
+
+    S32 out_of_range_count = 0;
+    U32* indices_u32 = NULL;
+    if (indices)
+    {
+        indices_u32 = (U32*)ll_aligned_malloc_32(index_count * sizeof(U32));
+        for (U64 i = 0; i < index_count; i++)
+        {
+            if (indices[i] < vertex_count)
+            {
+                indices_u32[i] = indices[i];
+            }
+            else
+            {
+                out_of_range_count++;
+                indices_u32[i] = 0;
+            }
+        }
+    }
+
+    if (out_of_range_count)
+    {
+        LL_WARNS() << out_of_range_count << " indexes are out of range." << LL_ENDL;
+    }
+
+    // Remap can function without indices,
+    // but providing indices helps with removing unused vertices
+    U64 indeces_cmp = indices_u32 ? index_count : vertex_count;
+
+    size_t unique =  meshopt_generateVertexRemapMulti(&remap[0], indices_u32, indeces_cmp, vertex_count, streams, sizeof(streams) / sizeof(streams[0]));
+
+    ll_aligned_free_32(indices_u32);
+
+    return unique;
 }
 
 void LLMeshOptimizer::remapIndexBufferU32(U32 * destination_indices,
diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h
index c76f8a5a898..ea965d6b47c 100644
--- a/indra/llmeshoptimizer/llmeshoptimizer.h
+++ b/indra/llmeshoptimizer/llmeshoptimizer.h
@@ -68,8 +68,10 @@ class LLMeshOptimizer
         U64 vertex_count);
 
     // Remap functions
+    // Welds indentical vertexes together.
+    // Removes unused vertices if indices were provided.
 
-    static size_t generateRemapMulti(
+    static size_t generateRemapMultiU32(
         unsigned int* remap,
         const U32 * indices,
         U64 index_count,
@@ -78,6 +80,15 @@ class LLMeshOptimizer
         const LLVector2 * text_coords,
         U64 vertex_count);
 
+    static size_t generateRemapMultiU16(
+        unsigned int* remap,
+        const U16 * indices,
+        U64 index_count,
+        const LLVector4a * vertex_positions,
+        const LLVector4a * normals,
+        const LLVector2 * text_coords,
+        U64 vertex_count);
+
     static void remapIndexBufferU32(U32 * destination_indices,
         const U32 * indices,
         U64 index_count,
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index 707a8b970f5..ef791fd80de 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1284,7 +1284,7 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
 
     // II. Remap.
     std::vector<unsigned int> remap(size_indices);
-    S32 size_remap_vertices = LLMeshOptimizer::generateRemapMulti(&remap[0],
+    S32 size_remap_vertices = LLMeshOptimizer::generateRemapMultiU32(&remap[0],
         combined_indices,
         size_indices,
         combined_positions,
-- 
GitLab