From 7f411bc02d4fbb29557ede5749bd789de3bb3391 Mon Sep 17 00:00:00 2001 From: Hakan Seven Date: Thu, 15 Oct 2026 01:17:39 +0300 Subject: [PATCH] layouts: keep every content viewport's wires cached (#1769) The resident wire sets were capped at 16 and cleared once more were held. A layout with more content viewports than that (24 in the report) cleared them all on each redraw and re-tessellated the model for every viewport, so the layout stayed sluggish even when nothing changed. The cap now covers the shown layout's viewports: idle redraws build no wires, and a frame of that layout draws in ~14 ms instead of ~30 ms plus ~100 ms of rebuilds. The automation bridge gains a `layout_switch` action, as clicking a layout tab does, which is how this was measured. Co-Authored-By: Claude Opus 5.5 --- src/app/control/actions.rs | 2 ++ src/scene/mod.rs | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/app/control/actions.rs b/src/app/control/actions.rs index 923f1d775..c169d5f4a 100644 --- a/src/app/control/actions.rs +++ b/src/app/control/actions.rs @@ -1166,6 +1166,8 @@ impl OpenCADStudio { let name = string(req, "name")?; let msg = match name { "close_modal" => Message::CloseModal, + // Show a layout (or "Model"), as clicking its tab does. + "layout_switch" => Message::LayoutSwitch(string(req, "value")?.into()), // The "changed outside" modal's suggested actions (D6): reload // the disk copy, keep the in-memory one and overwrite, save as, // or dismiss. Native only — the web build has no such dialog. diff --git a/src/scene/mod.rs b/src/scene/mod.rs index f2d821ccf..fa56c3c69 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -7223,12 +7223,20 @@ impl Scene { if block == self.model_space_block_handle() { *self.model_wire_gpu_patch.borrow_mut() = None; } + // Every content viewport of the shown layout holds a set of its own; + // a cap below their count cleared them all each frame and rebuilt + // every viewport's wires on every redraw (#1769). + let shown = if self.current_layout == "Model" { + 0 + } else { + self.paper_viewport_handles().2.len() + }; let mut sets = self.resident_wire_sets.borrow_mut(); // Evict stale entries (older epochs / abandoned keys) so switching // spaces or re-scaling a viewport can't accumulate dead full sets. let cur_epoch = self.geometry_epoch; sets.retain(|_, set| set.epoch == cur_epoch); - if sets.len() > 16 { + if sets.len() > 16.max(shown + 2) { sets.clear(); } sets.insert(