From d769320d454bff35e742316a67d40fbc2a150b9c Mon Sep 17 00:00:00 2001 From: tylerjenningsw Date: Thu, 15 Oct 2026 10:04:09 -0400 Subject: [PATCH] test(canvas): grow the slow zoom-preview scene until it crosses the threshold (M8) The browser-worker test assumed a fixed 2400x2400 glass scene renders in at least 12 ms; a faster machine or renderer (the glass speedups) would make it quick and the test fail. The scene now gets more and more blurred rectangles until renders from scratch of the views the test uses take three times the threshold. Refs #295 --- crates/ui-egui/src/render_worker.rs | 2 +- crates/ui-egui/src/zoom_preview_tests.rs | 43 ++++++++++++++++++++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/crates/ui-egui/src/render_worker.rs b/crates/ui-egui/src/render_worker.rs index 3ad9c54c..e2fb9a20 100644 --- a/crates/ui-egui/src/render_worker.rs +++ b/crates/ui-egui/src/render_worker.rs @@ -20,7 +20,7 @@ use web_time::Instant; /// A preview has this many times fewer pixels each way than the view it stands in for. pub const PREVIEW_FACTOR: f64 = 4.0; /// Full renders quicker than this (about a frame) show without a preview first. -const PREVIEW_AFTER_MS: f64 = 12.0; +pub const PREVIEW_AFTER_MS: f64 = 12.0; #[derive(Clone)] pub struct Job { diff --git a/crates/ui-egui/src/zoom_preview_tests.rs b/crates/ui-egui/src/zoom_preview_tests.rs index 68704571..0fcd9a29 100644 --- a/crates/ui-egui/src/zoom_preview_tests.rs +++ b/crates/ui-egui/src/zoom_preview_tests.rs @@ -13,7 +13,7 @@ use figcraft_render::{View, Work}; use serde_json::json; use super::{CanvasState, shows}; -use crate::render_worker::{Done, Inline, Job, PREVIEW_FACTOR, Renders, coarse_view, render_now}; +use crate::render_worker::{Done, Inline, Job, PREVIEW_AFTER_MS, PREVIEW_FACTOR, Renders, coarse_view, render_now}; /// A page of ellipses with a rectangle on top; the session and the rectangle. fn document() -> (Session, NodeId) { @@ -27,6 +27,35 @@ fn document() -> (Session, NodeId) { (s, rect) } +/// A page whose renders from scratch of each of `views` take at least `ms`: the rectangle with glass +/// and a background blur, and more and more blurred rectangles over the views until they do (a +/// fixed scene would turn quick on a faster machine or renderer). +fn slow_scene(views: &[View], ms: f64) -> Session { + let (mut s, rect) = document(); + s.execute("effect.add", &json!({"ids": [rect], "type": "GLASS"})).unwrap(); + s.execute("effect.add", &json!({"ids": [rect], "type": "BACKGROUND_BLUR"})).unwrap(); + let area = views.iter().map(View::page_rect).reduce(|a, b| a.union(b)).unwrap(); + let mut more = 8; + for _ in 0..12 { + let ds = s.ds().unwrap(); + let quickest = views.iter().map(|v| render_now(&job(&ds.doc, ds.page, ds.uid, v.clone())).unwrap().ms).fold(f64::INFINITY, f64::min); + if quickest >= ms { + return s; + } + let (w, h) = (area.width() / 4.0, area.height() / 4.0); + let ids: Vec = (0..more) + .map(|k| { + let (fx, fy) = (f64::from(k * 37 % 101) / 101.0, f64::from(k * 59 % 103) / 103.0); + let p = json!({"x": area.x0 + fx * (area.width() - w), "y": area.y0 + fy * (area.height() - h), "width": w, "height": h}); + id_of(&s.execute("shape.rectangle", &p).unwrap()["id"]).unwrap() + }) + .collect(); + s.execute("effect.add", &json!({"ids": ids, "type": "BACKGROUND_BLUR"})).unwrap(); + more *= 2; + } + panic!("no scene renders slower than {ms} ms"); +} + /// A `w` × `h` device-pixel view at `scale` centred on page point `c`. fn view_at(c: (f64, f64), scale: f64, w: u32, h: u32) -> View { View { origin: (c.0 - f64::from(w) / scale / 2.0, c.1 - f64::from(h) / scale / 2.0), scale, width: w, height: h } @@ -254,18 +283,18 @@ fn a_preview_replaces_a_refined_image_of_the_same_zoom_elsewhere_on_the_page() { #[test] fn the_browser_worker_previews_by_measured_render_time_then_refines_the_next_frame() { - // Big enough that a render from scratch takes well over a frame: blurs and glass on 2400². - let (mut s, rect) = document(); - s.execute("effect.add", &json!({"ids": [rect], "type": "GLASS"})).unwrap(); - s.execute("effect.add", &json!({"ids": [rect], "type": "BACKGROUND_BLUR"})).unwrap(); + // Renders from scratch at 200% and 100% (whose times decide the previews below) well over the + // threshold, wherever this runs. + let view = |scale| view_at((300.0, 200.0), scale, 1200, 1200); + let s = slow_scene(&[view(2.0), view(1.0)], 3.0 * PREVIEW_AFTER_MS); let ds = s.ds().unwrap(); - let at = |scale| job(&ds.doc, ds.page, ds.uid, view_at((300.0, 200.0), scale, 2400, 2400)); + let at = |scale| job(&ds.doc, ds.page, ds.uid, view(scale)); // The production threshold, as the browser has it. let mut w = Inline::new(egui::Context::default()); w.submit(at(2.0)); let first = w.poll().expect("the first image"); assert!(!first.coarse && !w.in_flight(), "the first render has no measure to preview by"); - assert!(first.ms >= 12.0, "renders are timed in the browser worker too (and this one is slow): {} ms", first.ms); + assert!(first.ms >= PREVIEW_AFTER_MS, "renders are timed in the browser worker too (and this one is slow): {} ms", first.ms); // A new zoom: the preview this frame, the refined image the next. w.submit(at(1.0)); let p = w.poll().expect("a preview");