perf(grips): cap total selection grips at 4096

GRIPOBJLIMIT gates object count, but one dense polyline emits ~2
grips/vertex past it (~200K grips through the per-frame project + draw
path, ms-scale, no cache). Enforce a vertex budget once in
refresh_selected_grips: stable vertex-first priority, entity order
restored, handles truncated in lockstep. Below the cap selections are
byte-identical.

Tests:
- refresh_selected_grips_caps_total_grip_count: cap + handles lockstep
- refresh_selected_grips_prefers_vertex_grips_over_midpoints: vertices survive
- grip_budget_boundary_lengths: empty/cap/cap+1 edge cases

Bench (cargo bench grip, 200K-grip fixture): per-frame 6.8ms -> 0.13ms
(45-52x); select-time build 2.36ms full. A/B reference deleted.
This commit is contained in:
Karim Jerbi committed 2026-09-21 22:52:41 +01:00
1 parent dcc05f310d
commit 2d49204c50
5 files changed
+327 -2

No files matched your search

+9
View File
@@ -329,6 +329,15 @@ pub fn format_snap_angle(deg: f32) -> String {
/// GRIPOBJLIMIT default: past this many selected objects, no grips are drawn.
pub const DEFAULT_GRIP_OBJECT_LIMIT: i32 = 100;
/// GRIPVERTLIMIT default: cap on TOTAL selection grips across all selected
/// objects. `grip_object_limit` gates object count, but one dense polyline
/// can emit ~2 grips/vertex past it — this caps the vertex blowup. Mid-segment
/// grips are dropped first; vertex grips are kept.
///
/// `pub` so the `cargo bench` harness (external crate) measures the real
/// constant alongside [`crate::app::apply_grip_budget`] as `ui_grip_budget`.
pub const MAX_SELECTED_GRIPS: usize = 4096;
/// The "settings" section of the consolidated config ([`crate::app::config`]).
/// Field defaults mirror the app's in-code defaults so a missing key restores
/// the value the app boots with.