perf(text): cache SDF text vertices across frames
The SDF text collector re-laid out every glyph of every text entity on each frame (pan/zoom included). Cache the vertex list on the Scene keyed by (geometry_epoch, annotation-scale bits) — it only changes when geometry or the scale changes — so pan/zoom reuses it. Glyph baking happens on the cache-miss path only; the atlas is a persistent global and the texture upload is already gated on the geometry epoch, so cache hits skip both the layout and any re-upload. No behaviour change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
75ddab6da7
commit
fd0b8fc1d4
2 changed files with 32 additions and 3 deletions
|
|
@ -710,6 +710,11 @@ pub struct Scene {
|
||||||
pub(crate) model_tiles: RefCell<Vec<ModelTile>>,
|
pub(crate) model_tiles: RefCell<Vec<ModelTile>>,
|
||||||
/// Index of the active model tile (camera input + overlays target it).
|
/// Index of the active model tile (camera input + overlays target it).
|
||||||
pub(crate) active_model_tile: std::cell::Cell<usize>,
|
pub(crate) active_model_tile: std::cell::Cell<usize>,
|
||||||
|
/// Cache of the SDF text vertex list, keyed on `(geometry_epoch,
|
||||||
|
/// anno_scale.to_bits())`, so the per-frame collector is not re-laid-out on
|
||||||
|
/// pan / zoom. See [`Scene::sdf_text_vertices`].
|
||||||
|
sdf_text_cache:
|
||||||
|
RefCell<Option<(u64, u32, std::sync::Arc<Vec<crate::scene::pipeline::text_gpu::TextVertex>>)>>,
|
||||||
/// pane_grid layout tree for the Model tab — the source of truth for the
|
/// pane_grid layout tree for the Model tab — the source of truth for the
|
||||||
/// tile split layout, resize and focus. `model_tiles` (the renderer's
|
/// tile split layout, resize and focus. `model_tiles` (the renderer's
|
||||||
/// per-pane data: camera / render-mode / grid) is kept in lock-step with
|
/// per-pane data: camera / render-mode / grid) is kept in lock-step with
|
||||||
|
|
@ -959,6 +964,7 @@ impl Scene {
|
||||||
snap_on: false,
|
snap_on: false,
|
||||||
}]),
|
}]),
|
||||||
active_model_tile: std::cell::Cell::new(0),
|
active_model_tile: std::cell::Cell::new(0),
|
||||||
|
sdf_text_cache: RefCell::new(None),
|
||||||
// One pane mapped to tile 0 — matches the single default tile above.
|
// One pane mapped to tile 0 — matches the single default tile above.
|
||||||
model_panes: iced::widget::pane_grid::State::new(0).0,
|
model_panes: iced::widget::pane_grid::State::new(0).0,
|
||||||
selection: Rc::new(RefCell::new(SelectionState::default())),
|
selection: Rc::new(RefCell::new(SelectionState::default())),
|
||||||
|
|
|
||||||
|
|
@ -783,8 +783,31 @@ impl Scene {
|
||||||
#[allow(dead_code)] // consumed by the text render pass in the GPU integration step
|
#[allow(dead_code)] // consumed by the text render pass in the GPU integration step
|
||||||
pub(in crate::scene) fn sdf_text_vertices(
|
pub(in crate::scene) fn sdf_text_vertices(
|
||||||
&self,
|
&self,
|
||||||
) -> Vec<crate::scene::pipeline::text_gpu::TextVertex> {
|
) -> std::sync::Arc<Vec<crate::scene::pipeline::text_gpu::TextVertex>> {
|
||||||
self.sdf_text_vertices_enabled(crate::scene::text::sdf_atlas::sdf_text_enabled())
|
use std::sync::Arc;
|
||||||
|
if !crate::scene::text::sdf_atlas::sdf_text_enabled() {
|
||||||
|
return Arc::new(Vec::new());
|
||||||
|
}
|
||||||
|
// Cache keyed on (geometry_epoch, annotation scale): the run layout only
|
||||||
|
// changes when geometry or the scale changes, so pan / zoom reuses it
|
||||||
|
// instead of re-laying-out every glyph each frame.
|
||||||
|
let anno = if self.current_layout == "Model" {
|
||||||
|
self.annotation_scale
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
};
|
||||||
|
let key = (self.geometry_epoch, anno.to_bits());
|
||||||
|
{
|
||||||
|
let cache = self.sdf_text_cache.borrow();
|
||||||
|
if let Some((epoch, anno_bits, verts)) = cache.as_ref() {
|
||||||
|
if *epoch == key.0 && *anno_bits == key.1 {
|
||||||
|
return verts.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let verts = Arc::new(self.sdf_text_vertices_enabled(true));
|
||||||
|
*self.sdf_text_cache.borrow_mut() = Some((key.0, key.1, verts.clone()));
|
||||||
|
verts
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -1152,7 +1175,7 @@ impl Scene {
|
||||||
let text_verts = if inst.paper_sheet {
|
let text_verts = if inst.paper_sheet {
|
||||||
Arc::new(Vec::new())
|
Arc::new(Vec::new())
|
||||||
} else {
|
} else {
|
||||||
Arc::new(self.sdf_text_vertices())
|
self.sdf_text_vertices()
|
||||||
};
|
};
|
||||||
Some(ViewportData {
|
Some(ViewportData {
|
||||||
wires: all_wires,
|
wires: all_wires,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue