Fix progressive render budget when timestamp is stale (#11094)

Pass performance.now from finalize/debounce and re-anchor the WASM
budget if the stamp is 0 or already past max_blocking_time, so HQ
tiles are not yielded after a few nodes with almost no real work.
This commit is contained in:
Alejandro Alonso 2026-08-06 09:00:45 +02:00 committed by GitHub
parent 649f4bebef
commit 8b64b0f84f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 2 deletions

View File

@ -1406,7 +1406,7 @@
;; this implicitly (`zoom_changed`); this extends it to pan/resize-triggered
;; ends (e.g. selecting a shape opens the options panel and resizes the
;; viewport), which previously blanked.
(internal-render 0 RENDER-FLAG-SYNC-TILES)
(internal-render (js/performance.now) RENDER-FLAG-SYNC-TILES)
;; The direct render above bypasses the rAF `render` loop, so repaint the
;; editor overlay explicitly. Only when this was a full frame: a progressive
;; render keeps painting through the rAF loop and its partial frames must not
@ -1421,7 +1421,7 @@
(if (view-gesture-active?)
;; Pan/zoom pause: render without ending the interaction.
(do
(internal-render 0 RENDER-FLAG-SYNC-TILES)
(internal-render (js/performance.now) RENDER-FLAG-SYNC-TILES)
(render-text-editor-overlay-after-frame!))
(finalize-view-interaction!))))]
(fns/debounce do-render DEBOUNCE_DELAY_MS)))

View File

@ -2357,6 +2357,7 @@ impl RenderState {
allow_stop: bool,
) -> Result<FrameType> {
performance::begin_measure!("continue_render_loop");
let timestamp = self.render_budget_start(timestamp);
let frame_type =
self.render_shape_tree_partial(base_object, tree, timestamp, allow_stop)?;
@ -2404,6 +2405,7 @@ impl RenderState {
tree: ShapesPoolRef,
timestamp: i32,
) -> Result<FrameType> {
let timestamp = self.render_budget_start(timestamp);
self.render_shape_tree_partial(base_object, tree, timestamp, false)?;
// Same composition as `continue_render_loop` for full frames: snapshot only the
@ -2538,6 +2540,24 @@ impl RenderState {
Ok((data.as_bytes().to_vec(), width, height))
}
/// Anchor the progressive render budget to wall-clock now when the
/// caller-provided timestamp is unusable:
/// - Frontend sometimes passes `0` (finalize-view / debounced zoom-end).
/// - rAF may hand a timestamp that is already older than the budget when
/// the handler runs late. Using that stamp made `should_stop_rendering`
/// yield after a few nodes with ~0ms of real work.
#[inline]
fn render_budget_start(&self, timestamp: i32) -> i32 {
let now = performance::get_time();
if timestamp <= 0 {
return now;
}
if now - timestamp > self.options.max_blocking_time_ms {
return now;
}
timestamp
}
#[inline]
pub fn should_stop_rendering(&self, iteration: i32, timestamp: i32) -> bool {
if iteration % self.options.node_batch_threshold != 0 {