forked from 1b-agent/opencadstudio-upstream
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
0b4551b6ec
commit
d9a1d55f2e
2 files changed
+46
-2
No files matched your search
+17
-2
@@ -9080,6 +9080,11 @@ impl Scene {
|
|||||||
let mut materialize_ms = 0.0f64;
|
let mut materialize_ms = 0.0f64;
|
||||||
let mut memo_hits = 0usize;
|
let mut memo_hits = 0usize;
|
||||||
let memo_misses;
|
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 t_build = perf.then(iced::time::Instant::now);
|
||||||
let mut wires: Vec<WireModel> = if memo_active {
|
let mut wires: Vec<WireModel> = if memo_active {
|
||||||
// Guard hash of everything tessellate_entity output depends on
|
// Guard hash of everything tessellate_entity output depends on
|
||||||
@@ -9114,7 +9119,9 @@ impl Scene {
|
|||||||
} else {
|
} else {
|
||||||
(&self.tess_memo, &self.tess_memo_guard)
|
(&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();
|
memo_cell.borrow_mut().clear();
|
||||||
guard_cell.set(guard);
|
guard_cell.set(guard);
|
||||||
}
|
}
|
||||||
@@ -9228,7 +9235,8 @@ impl Scene {
|
|||||||
crate::perf_record!(
|
crate::perf_record!(
|
||||||
"[perf] wires-build total={:.1}ms sort_cache={:.1} visible={:.1} blk_cache={:.1} \
|
"[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}({}) \
|
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),
|
crate::perf::elapsed_ms(t_fn),
|
||||||
sort_cache_ms,
|
sort_cache_ms,
|
||||||
visible_ms,
|
visible_ms,
|
||||||
@@ -9247,6 +9255,13 @@ entities={} memo_hit={} memo_miss={} wires={} memo={} visible_path={} candidates
|
|||||||
if memo_active { "on" } else { "off" },
|
if memo_active { "on" } else { "off" },
|
||||||
visible_path,
|
visible_path,
|
||||||
visible_candidates,
|
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
|
wires
|
||||||
|
|||||||
@@ -69,7 +69,36 @@ impl Scene {
|
|||||||
(layout_block, sheet, content)
|
(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)> {
|
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)
|
self.active_viewports(vw, vh, acadrust::entities::ViewportRenderMode::Wireframe2D)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|inst| inst.grid_on)
|
.filter(|inst| inst.grid_on)
|
||||||
|
|||||||
Reference in new issue
Block a user