gltfpack: Record the fact that mesh geometry might be duplicate

Instead of computing a hash after mesh processing for every mesh, we now
only do this when the mesh has been tagged as possibly-duplicate. This
reduces the cost of hash update to cases when we are likely to benefit
from them, and makes it easier to disable deduplication entirely for
testing.

While it is possible that two meshes did not have duplicate geometry
before processing and are processed to have it (eg two identical meshes
with a redundant vertex stream on one but not the other that gets
removed), this is fairly unlikely in practice.
This commit is contained in:
Arseny Kapoulkine
2024-10-05 10:12:27 -07:00
parent e6d41aeab0
commit 95d5779d4c
3 changed files with 28 additions and 9 deletions
+21 -9
View File
@@ -411,14 +411,18 @@ static void process(cgltf_data* data, const char* input_path, const char* output
#endif
for (size_t i = 0; i < meshes.size(); ++i)
processMesh(meshes[i], settings);
{
Mesh& mesh = meshes[i];
processMesh(mesh, settings);
if (mesh.geometry_duplicate)
hashMesh(mesh);
}
#ifndef NDEBUG
meshes.insert(meshes.end(), debug_meshes.begin(), debug_meshes.end());
#endif
for (size_t i = 0; i < meshes.size(); ++i)
hashMesh(meshes[i]);
filterEmptyMeshes(meshes); // some meshes may become empty after processing
@@ -585,19 +589,27 @@ static void process(cgltf_data* data, const char* input_path, const char* output
const QuantizationTexture& qt = qt_meshes[pi] == size_t(-1) ? qt_dummy : qt_materials[qt_meshes[pi]];
std::pair<size_t, size_t>& primitive_json = primitive_cache[std::make_pair(prim.geometry_hash[0], prim.geometry_hash[1])];
comma(json_meshes);
if (primitive_json.second > 0)
if (prim.geometry_duplicate)
{
json_meshes.append(json_meshes, primitive_json.first, primitive_json.second);
std::pair<size_t, size_t>& primitive_json = primitive_cache[std::make_pair(prim.geometry_hash[0], prim.geometry_hash[1])];
if (primitive_json.second)
{
// reuse previously written accessors
json_meshes.append(json_meshes, primitive_json.first, primitive_json.second);
}
else
{
primitive_json.first = json_meshes.size();
writeMeshGeometry(json_meshes, views, json_accessors, accr_offset, prim, qp, qt, settings);
primitive_json.second = json_meshes.size() - primitive_json.first;
}
}
else
{
primitive_json.first = json_meshes.size();
writeMeshGeometry(json_meshes, views, json_accessors, accr_offset, prim, qp, qt, settings);
primitive_json.second = json_meshes.size() - primitive_json.first;
}
if (prim.material)
+2
View File
@@ -56,6 +56,8 @@ struct Mesh
std::vector<Stream> streams;
std::vector<unsigned int> indices;
bool geometry_duplicate;
uint64_t geometry_hash[2];
size_t targets;
+5
View File
@@ -376,7 +376,12 @@ void dedupMeshes(std::vector<Mesh>& meshes)
continue;
if (mesh.scene != target.scene || mesh.material != target.material || mesh.skin != target.skin)
{
// mark both meshes as having duplicate geometry; we don't use this in dedupMeshes but it's useful later in the pipeline
target.geometry_duplicate = true;
mesh.geometry_duplicate = true;
continue;
}
// basic sanity test; these should be included in geometry hash
assert(mesh.streams.size() == target.streams.size());