forked from 1b-agent/opencadstudio-upstream
perf(glyphs): memoize constraint-glyph placements behind constraints_epoch
Placements (entity lookups, intersections, String labels, projections) recomputed per view() and per mouse-move hit-test, with overlay re-clones and 2-3x offset recomputes. New constraints_epoch bumped on every set mutation/visibility/undo/DWG-load (plus new set_constraint_enabled API); single-slot Arc<[GlyphEntry]> memo on an 11-field key (hover/selection excluded); overlay de-cloned/de-duped to the single geometry source; hit paths reuse the cache. Tests: - cached_glyph_placements_hit_returns_same_arc: same-key Arc identity - cached_glyph_placements_invalidated_by_metadata_edit: edit + selection change yield new Arc - glyph_hit_test_entries_matches_precomputed_boxes: shared hit-test helper Bench (cargo bench glyph, 60 constraints): 8.18us -> 0.05-0.15us (~55x). A/B reference deleted.
This commit is contained in:
1 parent
2d49204c50
commit
4432f633e7
12 files changed
+767
-239
No files matched your search
@@ -2321,6 +2321,25 @@ pub struct Scene {
|
||||
parametric_constraints::ParametricScope,
|
||||
parametric_constraints::ConstraintId,
|
||||
)>,
|
||||
/// Bumped on every parametric-constraint-set mutation (add / remove /
|
||||
/// metadata edit / visibility override / whole-set restore). The
|
||||
/// constraint-glyph memoization keys on this so a stale cache can never
|
||||
/// outlive the edit that invalidated it — a missed bump is a
|
||||
/// correctness bug (stale glyphs), not just a perf miss.
|
||||
constraints_epoch: u64,
|
||||
/// Memoised constraint-glyph placements for the latest [`GlyphKey`](parametric_constraints::GlyphKey)
|
||||
/// (Task 3; overlay/hit consumers adopt it in Task 4). Single-slot memo:
|
||||
/// within one frame view + hit-test + dwell + click share the key (hits),
|
||||
/// camera motion misses once per frame by design, and edits just miss on
|
||||
/// the stale entry — no leak possible. `RefCell` + `Arc` shape mirrors
|
||||
/// `layout_names_cache`; a missed constraint bump serves stale glyphs, so
|
||||
/// every set mutation must bump `constraints_epoch`.
|
||||
glyph_cache: RefCell<
|
||||
Option<(
|
||||
parametric_constraints::GlyphKey,
|
||||
Arc<[parametric_constraints::GlyphEntry]>,
|
||||
)>,
|
||||
>,
|
||||
/// Document-wide named-parameter and expression table decoded from
|
||||
/// standard associative variables.
|
||||
pub(crate) named_parameters: named_parameters::ParameterTable,
|
||||
@@ -2656,6 +2675,8 @@ impl Scene {
|
||||
dynamic_dimension_camera_gen: None,
|
||||
hidden_parametric_constraints: HashSet::default(),
|
||||
shown_parametric_constraints: HashSet::default(),
|
||||
constraints_epoch: 0,
|
||||
glyph_cache: RefCell::new(None),
|
||||
named_parameters: named_parameters::ParameterTable::new(),
|
||||
has_associative_centers: std::cell::Cell::new(None),
|
||||
block_defn_cache: RefCell::new(HashMap::default()),
|
||||
@@ -5703,6 +5724,9 @@ impl Scene {
|
||||
.collect();
|
||||
self.object_isolation.hidden.extend(hide);
|
||||
self.object_isolation.keep = Some(keep);
|
||||
// Isolation hides entities the memoised glyph placements read
|
||||
// (`entity_temporarily_hidden`), so invalidate them too.
|
||||
self.bump_constraints_epoch();
|
||||
if !changes.is_empty() {
|
||||
self.bump_entities(&changes);
|
||||
}
|
||||
@@ -5726,6 +5750,9 @@ impl Scene {
|
||||
self.selected.clear();
|
||||
self.selected_order.clear();
|
||||
self.bump_selection_set();
|
||||
// Newly hidden entities change `entity_temporarily_hidden`, which the
|
||||
// memoised glyph placements read — invalidate them too.
|
||||
self.bump_constraints_epoch();
|
||||
self.bump_entities(&changes);
|
||||
}
|
||||
|
||||
@@ -5742,6 +5769,12 @@ impl Scene {
|
||||
.map(|handle| (handle, ChangeKind::Modified))
|
||||
.collect();
|
||||
self.object_isolation = ObjectIsolationState::default();
|
||||
// Restoring isolated entities changes `entity_temporarily_hidden`,
|
||||
// which the memoised glyph placements read — invalidate them too.
|
||||
// (`reset_transient_visibility` needs no bump: it only runs on
|
||||
// doc-replace, where `load_parametric_constraints_from_document`
|
||||
// already bumps the epoch for the whole-set replace.)
|
||||
self.bump_constraints_epoch();
|
||||
if !changes.is_empty() {
|
||||
self.bump_entities(&changes);
|
||||
}
|
||||
@@ -6027,6 +6060,20 @@ impl Scene {
|
||||
self.scale_epoch += 1;
|
||||
}
|
||||
|
||||
/// Current parametric-constraint-set epoch (cache key input for the
|
||||
/// memoised `cached_glyph_placements` accessor).
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn constraints_epoch(&self) -> u64 {
|
||||
self.constraints_epoch
|
||||
}
|
||||
|
||||
/// Invalidate constraint-glyph consumers. Call on EVERY mutation of the
|
||||
/// constraint set or its visibility overrides — a missed bump serves
|
||||
/// stale glyphs.
|
||||
pub(crate) fn bump_constraints_epoch(&mut self) {
|
||||
self.constraints_epoch += 1;
|
||||
}
|
||||
|
||||
pub fn cached_scale_picker_list(&self) -> std::sync::Arc<Vec<(String, f32, f64)>> {
|
||||
let factor = self.annotation_scale_unit_factor();
|
||||
let imperial = self.prefers_imperial_scales();
|
||||
|
||||
Reference in new issue
Block a user