perf(canvas): skip idle indicator snapshots
This commit is contained in:
parent
7a30644bb0
commit
83f488fd0a
|
|
@ -217,7 +217,7 @@ pub fn end_if_epoch(epoch: u64) {
|
|||
/// uses this to keep requesting redraws so the breathing animates.
|
||||
pub fn is_active() -> bool {
|
||||
let r = REGISTRY.lock().unwrap();
|
||||
!r.nodes.is_empty() || !r.frames.is_empty() || !r.reveals.is_empty()
|
||||
has_active_indicators(&r)
|
||||
}
|
||||
|
||||
/// A clone of the current indicators for the paint pass to read.
|
||||
|
|
@ -229,12 +229,21 @@ pub fn snapshot() -> AgentIndicators {
|
|||
/// `now_ms` pruned. The paint pass calls this every frame so completed
|
||||
/// reveal animations stop requesting redraws.
|
||||
pub fn snapshot_at(now_ms: u64) -> AgentIndicators {
|
||||
snapshot_at_if_active(now_ms).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// A clone of the current indicators after reveal maintenance, or
|
||||
/// `None` when there is nothing active for paint to consume.
|
||||
pub fn snapshot_at_if_active(now_ms: u64) -> Option<AgentIndicators> {
|
||||
let mut r = REGISTRY.lock().unwrap();
|
||||
if !has_active_indicators(&r) {
|
||||
return None;
|
||||
}
|
||||
rebase_external_clock_reveals(&mut r, now_ms);
|
||||
r.reveals
|
||||
.retain(|_, started| now_ms.saturating_sub(*started) <= REVEAL_DURATION_MS);
|
||||
smooth_overdue_reveal_burst(&mut r, now_ms);
|
||||
r.clone()
|
||||
has_active_indicators(&r).then(|| r.clone())
|
||||
}
|
||||
|
||||
/// Next host-clock millisecond needed for generated-node reveal animation.
|
||||
|
|
@ -333,6 +342,10 @@ fn smooth_overdue_reveal_burst(r: &mut AgentIndicators, now_ms: u64) {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_active_indicators(r: &AgentIndicators) -> bool {
|
||||
!r.nodes.is_empty() || !r.frames.is_empty() || !r.reveals.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -435,6 +448,32 @@ mod tests {
|
|||
clear();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_at_if_active_avoids_idle_snapshot_clone() {
|
||||
let _guard = TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
clear();
|
||||
assert!(
|
||||
snapshot_at_if_active(1_000).is_none(),
|
||||
"idle paint should skip cloning an empty indicator snapshot"
|
||||
);
|
||||
|
||||
let epoch = begin();
|
||||
add_frame(epoch, "frame", "#4ECDC4", "Mochi");
|
||||
assert!(
|
||||
snapshot_at_if_active(1_000).is_some_and(|snap| snap.frames.contains_key("frame")),
|
||||
"active frame indicators still produce a paint snapshot"
|
||||
);
|
||||
|
||||
clear();
|
||||
let epoch = begin();
|
||||
add_reveal(epoch, "expired", 1_000);
|
||||
assert!(
|
||||
snapshot_at_if_active(3_000).is_none(),
|
||||
"an expired reveal should prune and leave no idle snapshot"
|
||||
);
|
||||
end_if_epoch(epoch);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_rebases_external_clock_reveals_to_paint_clock() {
|
||||
let _guard = TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ impl<'a> Widget for CanvasViewport<'a> {
|
|||
// 2. Dotted grid — canvas-local, scales with pan/zoom.
|
||||
let viewport = &self.viewport;
|
||||
super::canvas_viewport_grid::paint_grid(cx, rect, viewport, &self.theme);
|
||||
let indicators = op_editor_core::agent_indicators::snapshot_at(self.now_ms);
|
||||
let indicators = op_editor_core::agent_indicators::snapshot_at_if_active(self.now_ms);
|
||||
|
||||
// 3. Walk the active page; clip enforces widget bounds.
|
||||
if let Some(page) = self.scene.active_page() {
|
||||
|
|
@ -481,7 +481,9 @@ impl<'a> Widget for CanvasViewport<'a> {
|
|||
rect.size.y + CULL_MARGIN * 2.0,
|
||||
),
|
||||
};
|
||||
let reveal_schedule = reveal_schedule_for_paint(&indicators.reveals, self.now_ms);
|
||||
let reveal_schedule = indicators
|
||||
.as_ref()
|
||||
.and_then(|indicators| reveal_schedule_for_paint(&indicators.reveals, self.now_ms));
|
||||
for child in page.children.iter().rev() {
|
||||
if let Some(reveals) = reveal_schedule {
|
||||
super::canvas_viewport_paint::paint_node_with_reveals(
|
||||
|
|
@ -504,14 +506,16 @@ impl<'a> Widget for CanvasViewport<'a> {
|
|||
);
|
||||
}
|
||||
}
|
||||
super::canvas_agent_overlay::paint_agent_frame_indicators_with_snapshot(
|
||||
cx,
|
||||
&page.children,
|
||||
viewport_origin,
|
||||
viewport.zoom,
|
||||
self.now_ms,
|
||||
&indicators,
|
||||
);
|
||||
if let Some(indicators) = indicators.as_ref() {
|
||||
super::canvas_agent_overlay::paint_agent_frame_indicators_with_snapshot(
|
||||
cx,
|
||||
&page.children,
|
||||
viewport_origin,
|
||||
viewport.zoom,
|
||||
self.now_ms,
|
||||
indicators,
|
||||
);
|
||||
}
|
||||
if let Some(hovered) = self.hovered.as_ref() {
|
||||
if let Some(node) = page.find(hovered) {
|
||||
const HOVER: Color = Color {
|
||||
|
|
@ -595,10 +599,12 @@ impl<'a> Widget for CanvasViewport<'a> {
|
|||
continue;
|
||||
};
|
||||
if node.hidden
|
||||
|| indicators
|
||||
.reveals
|
||||
.get(&node.id)
|
||||
.is_some_and(|started_at| self.now_ms < *started_at)
|
||||
|| indicators.as_ref().is_some_and(|indicators| {
|
||||
indicators
|
||||
.reveals
|
||||
.get(&node.id)
|
||||
.is_some_and(|started_at| self.now_ms < *started_at)
|
||||
})
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue