M5.6: with a GPU, a slider drag's preview is drawn in the frame of the drag tick

A drag tick requested the loupe's draft and the frame ended; the draft,
done in 1.5-3 ms on the GPU, was picked up at the start of the next frame,
a frame after the slider moved. Now, in a drag, the loupe waits up to 40 %
of a frame for its draft when the last loupe render took well under that
(not with a render offload, nor zoomed in, where what changes on screen is
the window's draft). A CPU render, which would only make the frame late, is
not waited for.

JobPool::wait waits for the next finished job, which try_recv then hands
out; Renderer::poll's collection of finished jobs is split out so the wait
can turn the draft into the texture.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
dev-null-undefined
2026-10-13 03:40:23 +02:00
co-authored by Claude
parent 701f78ea2e
commit c8f676252f
5 changed files with 95 additions and 8 deletions
+13 -2
View File
@@ -56,6 +56,8 @@ pub struct JobPool<S, R> {
shared: Arc<Shared<S, R>>,
tx: Sender<Done<S, R>>,
rx: Receiver<Done<S, R>>,
/// A finished job [`Self::wait`] took off the channel, handed out first by [`Self::try_recv`].
early: Option<Done<S, R>>,
#[cfg_attr(target_arch = "wasm32", allow(dead_code))]
threads: usize,
started: bool,
@@ -82,6 +84,7 @@ impl<S: Copy + Eq + Hash + Send + 'static, R: Send + 'static> JobPool<S, R> {
}),
tx,
rx,
early: None,
threads,
started: false,
seq: 0,
@@ -210,8 +213,16 @@ impl<S: Copy + Eq + Hash + Send + 'static, R: Send + 'static> JobPool<S, R> {
}
/// A finished job, if any.
pub fn try_recv(&self) -> Option<Done<S, R>> {
self.rx.try_recv().ok()
pub fn try_recv(&mut self) -> Option<Done<S, R>> {
self.early.take().or_else(|| self.rx.try_recv().ok())
}
/// Wait up to `timeout` for a job to finish; whether one has (it is the next [`Self::try_recv`]).
pub fn wait(&mut self, timeout: Duration) -> bool {
if self.early.is_none() {
self.early = self.rx.recv_timeout(timeout).ok();
}
self.early.is_some()
}
/// Run up to `n` jobs on the calling thread (wasm, tests). Returns how many ran.
+13
View File
@@ -351,3 +351,16 @@ fn disk_cache_never_touches_foreign_files() {
assert!(!disk::is_cache_file("01", "0123456789abcdef0123456789abcdef.jpg.bak"));
let _ = std::fs::remove_dir_all(&dir);
}
/// [`JobPool::wait`] returns once a job finishes, which [`JobPool::try_recv`] then hands out, or
/// after the timeout.
#[test]
fn pool_wait_keeps_the_finished_job_for_try_recv() {
let mut p: JobPool<u8, u8> = JobPool::new(1);
assert!(!p.wait(std::time::Duration::from_millis(10)), "nothing runs");
p.submit(1, 0, 1, Box::new(|| 7));
assert!(p.wait(std::time::Duration::from_secs(10)));
assert!(p.wait(std::time::Duration::ZERO), "kept until taken");
assert_eq!(p.try_recv().map(|d| d.result), Some(7));
assert!(p.try_recv().is_none());
}