From 5aecdff12e10ebd83f2e280e668a932272547806 Mon Sep 17 00:00:00 2001 From: Kevin Griffin Date: Wed, 22 Jul 2026 12:59:07 -0700 Subject: [PATCH] perf(mesh): skip per-vertex snap tables above 50k vertices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The subdivision MESH converter emitted one snap candidate and one key vertex per mesh vertex — ~56 B/vertex retained in every copy of the wire set. On NWD-scale imports (#358: tens of millions of vertices) that is GBs spent on snap targets far too dense to distinguish on screen. PolyfaceMesh and PolygonMesh already ship empty tables at any size. Above 50,000 vertices, ship none. Smaller meshes (including the #358 repro sample at 34.6k vertices per mesh) keep vertex snap unchanged. Measured (mem_probe_meshent, 1M-triangle MESH): 646 -> 589 B/face resident; wire content 210 -> 183 MB per 1M triangles. Co-Authored-By: Claude Fable 5 --- src/entities/mesh.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/entities/mesh.rs b/src/entities/mesh.rs index 9a1c74df4..28310501e 100644 --- a/src/entities/mesh.rs +++ b/src/entities/mesh.rs @@ -685,12 +685,23 @@ impl TruckConvertible for Mesh { } } - let snap_pts: Vec<(glam::DVec3, SnapHint)> = self - .vertices - .iter() - .map(|v| (glam::DVec3::new(v.x, v.y, v.z), SnapHint::Node)) - .collect(); - let key_vertices: Vec<[f64; 3]> = self.vertices.iter().map(|v| [v.x, v.y, v.z]).collect(); + // Per-vertex snap tables cost ~56 B/vertex and are retained in every + // copy of the wire set. On NWD-scale imports (#358: tens of millions + // of mesh vertices) that is GBs for snap targets far too dense to + // pick apart on screen — so past this size ship none, which is what + // PolyfaceMesh / PolygonMesh already do at any size. + const SNAP_TABLE_MAX_VERTICES: usize = 50_000; + let (snap_pts, key_vertices) = if self.vertices.len() > SNAP_TABLE_MAX_VERTICES { + (Vec::new(), Vec::new()) + } else { + ( + self.vertices + .iter() + .map(|v| (glam::DVec3::new(v.x, v.y, v.z), SnapHint::Node)) + .collect(), + self.vertices.iter().map(|v| [v.x, v.y, v.z]).collect(), + ) + }; Some(TruckEntity { pick_tris: Vec::new(),