perf(layers): toggle layer visibility without re-tessellating

Turning a 141k-entity layer off/on took 1.5-5 s; it now takes ~0.6-0.9 s.

- Off/freeze toggles go through invalidate_layer_visibility: entities on
  the layer keep their tessellation memo (visibility gates them before
  tessellation); only block users re-expand. No mesh recolor.
- The resident patch reuses a surviving memo entry instead of
  re-tessellating, guarded by the same display-context hash as the full
  build.
- The patch looked up `layout.order` linearly per re-shown entity, which
  made turning a big layer back on quadratic.
- recolor_meshes_for_handles resolved materials for handles with no mesh.
- Wire arena: a hidden slab keeps its instances and sets a `hidden` flag
  in its consts (collapsed in the vertex shader); an unchanged re-show only
  clears the flag. Const writes are batched into merged spans.
- The `layer_visible` automation action indexed the document's layer
  table instead of the sortable panel rows the Layer* messages use.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 5.5 committed 2026-10-05 15:53:27 +03:00
1 parent c35b902f3a
commit de6e27304d
7 files changed
+228 -64

No files matched your search

+6 -6
View File
@@ -33,7 +33,7 @@ impl OpenCADStudio {
dl.turn_off();
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
@@ -70,7 +70,7 @@ impl OpenCADStudio {
dl.freeze();
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
@@ -440,7 +440,7 @@ impl OpenCADStudio {
dl.turn_on();
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
@@ -461,7 +461,7 @@ impl OpenCADStudio {
dl.thaw();
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
@@ -530,7 +530,7 @@ impl OpenCADStudio {
}
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
@@ -620,7 +620,7 @@ impl OpenCADStudio {
dl.turn_on();
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&names);
self.tabs[i].scene.invalidate_layer_visibility(&names);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.refresh_layer_panel();
+2 -2
View File
@@ -1227,9 +1227,9 @@ impl OpenCADStudio {
"redo" => Message::Redo,
"layer_visible" | "layer_locked" | "layer_frozen" | "layer_current" => {
let layer = string(req, "layer")?;
// The Layer* messages index the panel's (sortable) row list.
let index = self.tabs[self.active_tab]
.scene
.document
.layers
.layers
.iter()
.position(|l| l.name == layer)
+2 -2
View File
@@ -3338,7 +3338,7 @@ impl OpenCADStudio {
pl.visible = on;
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&targets);
self.tabs[i].scene.invalidate_layer_visibility(&targets);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.command_line.push_output(
@@ -3426,7 +3426,7 @@ impl OpenCADStudio {
pl.frozen = frozen;
}
}
self.tabs[i].scene.invalidate_layer_dependencies(&targets);
self.tabs[i].scene.invalidate_layer_visibility(&targets);
self.tabs[i].dirty = true;
self.commit_layer_undo(i, undo);
self.command_line.push_output(