perf(render): reuse static wire set for model-space pick/snap

Every pan/rotate on a large drawing jerked once at the start of the
gesture. Instrumentation traced it to `paper_sheet_wires_arc` re-running a
full ~300 ms tessellation of the whole model block on the first hit-test
after each camera move.

`entity_wires_arc` (the pick/snap source in Model layout) delegated to the
camera_generation-keyed, view-culled `paper_sheet_wires_arc`. A camera
move bumps `camera_generation`, so the next hit-test cold-missed that cache
and re-tessellated every visible entity — O(visible), which is why the
jump grew with on-screen object count and shrank when zoomed in. The GPU
render was unaffected (it holds the separate camera-independent
`model_static_wires`), so only that one CPU frame stalled and the
accumulated mouse motion applied at once, reading as a jump.

Point the Model pick path at the same resident static set the render holds
(keyed on geometry_epoch only). Pick wants every entity, not a view-culled
subset, so this is also more correct — off-screen entities stay pickable —
and it never re-tessellates on a camera move.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-05 03:26:07 +03:00
1 parent 845194e05b
commit 626031de00
1 file changed
+11 -5
+11 -5
View File
@@ -2117,12 +2117,18 @@ impl Scene {
}
}
let layout_block = self.current_layout_block_handle();
// Model space: paper_sheet_wires_arc IS the full entity wire set — share the Arc,
// no Vec clone needed.
// Model space: reuse the resident, camera-independent static wire set the
// render already holds (keyed on geometry_epoch only). This is the FULL
// entity set — pick / snap want every entity, not a view-culled subset —
// and it does NOT re-tessellate on a camera move. The old path went
// through the camera_generation-keyed, view-culled paper_sheet set, so
// every pan/rotate cold-missed it and paid a full O(visible) re-tess
// (~300 ms on large drawings) the first time hit-testing ran after the
// move — the "jump" at the start of each gesture. The tile args are
// unused by `model_tile_wires_arc`.
if self.current_layout == "Model" {
let arc = self.paper_sheet_wires_arc();
*self.wire_cache.borrow_mut() = Some((key, Arc::clone(&arc)));
return arc;
let cam = self.camera.borrow().clone();
return self.model_tile_wires_arc(0, &cam, 1.0, 1.0);
}
// Paper space: extend sheet wires with projected viewport content.
let mut wires = (*self.paper_sheet_wires_arc()).clone();