From e356e4adf5dbdf59def7fcbd9cd34a6888d307d6 Mon Sep 17 00:00:00 2001 From: nazar-gavrylyk Date: Tue, 10 Nov 2026 15:58:42 +0100 Subject: [PATCH] Preview: a stall after playing at full rate still steps down a resolution The step-down was skipped while the achieved frame rate read as keeping up, and that rate comes from the frames shown in the last second they were shown: through a stall it kept the rate from before it, so a preview that played a cached stretch and then stalled never stepped down. A rate whose last frame is more than a second old no longer counts. --- crates/ui-egui/src/app/prefetch.rs | 3 ++- crates/ui-egui/tests/it/ui_preview_align.rs | 24 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/app/prefetch.rs b/crates/ui-egui/src/app/prefetch.rs index 7f6494d3f..a80ae98a9 100644 --- a/crates/ui-egui/src/app/prefetch.rs +++ b/crates/ui-egui/src/app/prefetch.rs @@ -553,7 +553,8 @@ impl EffectcraftApp { || pb.res.is_some() || !self.viewer_res().is_auto() || now - since < 2.0 - || pb.achieved_fps().is_some_and(|f| f * step >= pb.fps * 0.8) + // (a rate from before a stall: nothing shown for a second isn't keeping up) + || (pb.shown_at.back().is_some_and(|t| now - t <= 1.0) && pb.achieved_fps().is_some_and(|f| f * step >= pb.fps * 0.8)) || lower < self.session.prefs.adaptive_limit() - 1e-9 { return; diff --git a/crates/ui-egui/tests/it/ui_preview_align.rs b/crates/ui-egui/tests/it/ui_preview_align.rs index 9d3119b21..a9622d458 100644 --- a/crates/ui-egui/tests/it/ui_preview_align.rs +++ b/crates/ui-egui/tests/it/ui_preview_align.rs @@ -320,6 +320,30 @@ fn cache_frames_when_idle_survives_an_inverted_work_area() { assert!(!h.state().playback.playing); } +/// A preview that played at full rate and then stalls on frames that aren't cached still steps +/// down: the rate from before the stall doesn't count once nothing was shown for a second. (The +/// last second shown kept reading as full rate through the stall, and it never stepped down.) +#[test] +fn playback_that_stalls_after_keeping_up_steps_down() { + let mut h = harness(); + h.state_mut().session.prefs.previews.adaptive_playback = true; + h.state().frames.set_budget(0); + h.state_mut().use_manual_clock(); + invoke(&mut h, "playback.toggle", json!({})); + h.step(); + assert!(h.state().playback.playing); + // A second shown at the comp's rate, just before the stall. + let t0 = h.state().now(); + for i in 0..30 { + h.state_mut().playback.frame_shown(t0 - 1.0 + f64::from(i) / 30.0); + } + for _ in 0..25 { + h.state_mut().clock_mut().advance(0.1); + h.step(); + } + assert_eq!(h.state().viewer_scale(1.0, 1.0), 0.5); +} + /// Settings ▸ Previews ▸ Lower Resolution When Playback Can't Keep Up: a preview at Auto that /// stalls for two seconds steps down to half its scale, two more to a quarter; an explicit Resolution and /// the pref turned off (its default) keep the scale, and stopping goes back to the viewer's.