From cd28b6f7c1ce375f64b67273bea90e85573315a3 Mon Sep 17 00:00:00 2001 From: sLuCHa <142535358+sLuCHaa@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:57:11 +0200 Subject: [PATCH] perf(clipboard): cap the ghost preview by wire count, box beyond it on_preview_wires clones and re-uploads the whole ghost on every cursor move, so its cost scales with the wire count, not just the point count. A whole-drawing paste flooded the event loop and locked up placement. Gate on the wire count as well as the point count, and fall back to a single bounding-box outline above the budget. The budget still shows the full-geometry ghost for typical pastes (up to ~20k wires); only a whole-drawing paste rubber-bands a box. --- src/modules/draw/clipboard/paste.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/modules/draw/clipboard/paste.rs b/src/modules/draw/clipboard/paste.rs index 0bc8a6b58..01dc3c368 100644 --- a/src/modules/draw/clipboard/paste.rs +++ b/src/modules/draw/clipboard/paste.rs @@ -38,15 +38,18 @@ pub struct PasteCommand { } impl PasteCommand { - /// Per-frame preview cost is proportional to the total point count across - /// the ghost wires. Above this, switch to the bounding-box outline so - /// placement stays smooth. ~50k points is well under a frame budget yet - /// still shows the full ghost for typical multi-object pastes. - const MAX_PREVIEW_POINTS: usize = 50_000; + /// `on_preview_wires` clones and re-uploads the whole ghost every cursor + /// move, so its cost scales with the wire count and the total point count. + /// Past either budget the per-move work floods the event loop, so switch to + /// a bounding-box outline; below them the full ghost still shows. + const MAX_PREVIEW_WIRES: usize = 20_000; + const MAX_PREVIEW_POINTS: usize = 300_000; pub fn new(wires: Vec, centroid: Vec3) -> Self { let total_points: usize = wires.iter().map(|w| w.points.len()).sum(); - if total_points > Self::MAX_PREVIEW_POINTS { + let too_heavy = + wires.len() > Self::MAX_PREVIEW_WIRES || total_points > Self::MAX_PREVIEW_POINTS; + if too_heavy { if let Some(bbox_wire) = Self::bbox_outline(&wires) { // Drop the full wires — the box is all the ghost needs now. return Self { wires: Vec::new(), bbox_wire: Some(bbox_wire), centroid };