perf: don't resolve viewport cameras for a grid nobody draws

`grid-detail` came back `views=1095.2ms params=0.0ms bg=0.0ms n=0`. Zero
grid views — every millisecond of it thrown away.

`grid_views` asked `active_viewports` for every viewport, which resolves a
camera for each, and `camera_for_viewport` reaches `model_space_extents`,
which outside the Model layout tessellates the whole drawing. Only then
did it filter on `grid_on`, which removed all of them. The parallel walk
from the previous commit had already cut this from 7826.9 ms; it was
7.8 seconds of work for an empty vector.

`grid_views` now asks first. `any_viewport_grid_on` reads the same fields
`active_viewports` copies into `ViewportInstance::grid_on`, and skips the
visibility filters that function also applies: answering "maybe" costs
only the work that would have happened anyway, while answering "no"
wrongly would drop a grid the user asked for.

Also reports the tessellation memo's guard and the inputs that can move
it. Two consecutive identical resident builds each missed all 186 455
entries — `memo_hit=0` twice in a row — which a stable guard cannot
explain, so something is clearing the memo between them and reading the
code has not said what. `guard=`, `guard_stale=`, `avp=`, `anno=`,
`anno_h=`, `all_vis=` and `sdf_gen=` will.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-05 18:53:02 +03:00
1 parent 0b4551b6ec
commit d9a1d55f2e
2 files changed
+46 -2

No files matched your search

+17 -2
View File
@@ -9080,6 +9080,11 @@ impl Scene {
let mut materialize_ms = 0.0f64;
let mut memo_hits = 0usize;
let memo_misses;
// Two consecutive identical resident builds both missed every entry,
// which a stable guard cannot explain — the memo is being cleared
// between them. Report the guard and the inputs that can move it.
let mut guard_dbg = 0u64;
let mut guard_was_stale = false;
let t_build = perf.then(iced::time::Instant::now);
let mut wires: Vec<WireModel> = if memo_active {
// Guard hash of everything tessellate_entity output depends on
@@ -9114,7 +9119,9 @@ impl Scene {
} else {
(&self.tess_memo, &self.tess_memo_guard)
};
if guard_cell.get() != guard {
guard_dbg = guard;
guard_was_stale = guard_cell.get() != guard;
if guard_was_stale {
memo_cell.borrow_mut().clear();
guard_cell.set(guard);
}
@@ -9228,7 +9235,8 @@ impl Scene {
crate::perf_record!(
"[perf] wires-build total={:.1}ms sort_cache={:.1} visible={:.1} blk_cache={:.1} \
build={:.1} [classify={:.1} hits={:.1} tess={:.1} materialize={:.1}] sort={:.1}({}) \
entities={} memo_hit={} memo_miss={} wires={} memo={} visible_path={} candidates={}",
entities={} memo_hit={} memo_miss={} wires={} memo={} visible_path={} candidates={} \
guard={:016x} guard_stale={} avp={} anno={:.4} anno_h={} all_vis={} sdf_gen={}",
crate::perf::elapsed_ms(t_fn),
sort_cache_ms,
visible_ms,
@@ -9247,6 +9255,13 @@ entities={} memo_hit={} memo_miss={} wires={} memo={} visible_path={} candidates
if memo_active { "on" } else { "off" },
visible_path,
visible_candidates,
guard_dbg,
guard_was_stale,
avp.map(|h| h.value()).unwrap_or(0),
anno,
annotation_scale_handle.map(|h| h.value()).unwrap_or(0),
all_visible,
crate::scene::text::sdf_atlas::generation(),
);
}
wires
+29
View File
@@ -69,7 +69,36 @@ impl Scene {
(layout_block, sheet, content)
}
/// Could any viewport in this layout draw a grid?
///
/// Read from the same fields `active_viewports` copies into
/// `ViewportInstance::grid_on`, and deliberately without the visibility
/// filters that function also applies: answering "maybe" only costs the
/// work that would have happened anyway, while answering "no" wrongly
/// would drop a grid the user asked for.
fn any_viewport_grid_on(&self) -> bool {
if self.current_layout == "Model" {
return self.model_tiles.borrow().iter().any(|tile| tile.grid_on);
}
let (_, sheet, content) = self.paper_viewport_handles();
let grid_on = |handle: Handle| {
matches!(
self.document.get_entity(handle),
Some(EntityType::Viewport(vp)) if vp.status.grid_on
)
};
grid_on(sheet) || content.iter().copied().any(grid_on)
}
pub fn grid_views(&self, vw: f32, vh: f32) -> Vec<(iced::Rectangle, Camera, Handle)> {
// `active_viewports` resolves a camera for every viewport, and
// `camera_for_viewport` reaches `model_space_extents`, which outside the
// Model layout tessellates the whole drawing. Filtering on `grid_on`
// afterwards threw all of that away: on the reproducer the first paper
// frame spent 7.8 s here to produce `n=0` views. Ask first.
if !self.any_viewport_grid_on() {
return Vec::new();
}
self.active_viewports(vw, vh, acadrust::entities::ViewportRenderMode::Wireframe2D)
.into_iter()
.filter(|inst| inst.grid_on)