forked from 1b-agent/opencadstudio-upstream
perf(scene): delta journal so edits touch only changed entities (phase 0-1)
Every geometry mutation previously bumped a monotonic geometry_epoch and each derived cache compared its stamp and, on a miss, re-walked the whole document — so drawing or moving one line rebuilt every hatch / image / mesh / wipeout model even though none of them changed. Add a per-mutation delta journal: bump_entities(&[(Handle, ChangeKind)]) records exactly which handles changed (Added / Removed / Modified), folding the memo drop and the epoch bump into one call a site cannot forget. A bounded ring keeps the recent deltas; replay_since(last_epoch) coalesces the changes past a consumer or returns None (full rebuild) when a spanned delta is `full` or the consumer fell off the ring. bump_geometry / bump_geometry_no_blocks push a `full` delta so the journal is never missing a step. Route the common single-entity ops through it: add (Added), update (Modified), erase (Removed), move/rotate/scale/mirror (Modified), copy (Added). Gate the four per-category model caches on category relevance — an edit whose handles are not in a category leaves that category cache warm; a removal is treated conservatively (the erased handle can no longer be classified), and the mesh cache also invalidates on any INSERT edit since it carries the instanced block meshes. Net: a plain-entity edit no longer rebuilds the hatch/image/mesh/wipeout model sets. The resident wire clone-all and the GPU re-upload are still whole-set — the journal is the groundwork for making those per-entity next. Adds 6 journal unit tests (replay, coalescing, full-fallback, ring overflow, category gate). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
4bcf5063e9
commit
57401f6f32
4 files changed
+365
-32
No files matched your search
@@ -329,6 +329,7 @@ impl Scene {
|
||||
// ── Erase ─────────────────────────────────────────────────────────────
|
||||
|
||||
pub fn erase_entities(&mut self, handles: &[Handle]) {
|
||||
let mut erased: Vec<(Handle, ChangeKind)> = Vec::new();
|
||||
for &h in handles {
|
||||
// Objects on a locked layer can't be erased.
|
||||
if self.is_layer_locked(h) {
|
||||
@@ -339,7 +340,7 @@ impl Scene {
|
||||
self.hatches.remove(&h);
|
||||
self.meshes.remove(&h);
|
||||
self.solid_models.remove(&h);
|
||||
self.mark_entity_dirty(h);
|
||||
erased.push((h, ChangeKind::Removed));
|
||||
}
|
||||
// Remove erased handles from all groups; delete groups that become empty.
|
||||
let group_dict_handle = self.document.header.acad_group_dict_handle;
|
||||
@@ -367,8 +368,10 @@ impl Scene {
|
||||
}
|
||||
self.document.objects.remove(gh);
|
||||
}
|
||||
// Deleting top-level entities/inserts leaves block definitions intact;
|
||||
// the erased handles were already dropped from the memo above.
|
||||
self.bump_geometry_no_blocks();
|
||||
// Deleting top-level entities/inserts leaves block definitions intact.
|
||||
// Report the exact erased handles so derived caches drop just those and
|
||||
// the resident set removes only their wires (bump_entities drops them
|
||||
// from the tessellation memos too).
|
||||
self.bump_entities(&erased);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user