gtauri: distance-from-viewport drop policy for ALL jobs

The backlog must never delay on-screen work. Urgent jobs (real
Chromium requests) are now stale-dropped too, not just prefetch:
a fast fling queues urgent work for every band it crosses, and all
of it except the final band is dead — it filled the queue cap and
made fresh on-screen requests wait for the JS retry timer.

Safe because the anchor now settles at the final scroll position
(trailing send), and on-screen cells have idx >= VPORT so they can
never be dropped. A pure LIFO would not fix this: stale jobs sit
at the stack bottom, never popped, still blocking the cap.

Emulator fling test: 309 stale urgent jobs purged, queue peak 28,
all 850 decodable images loaded.
This commit is contained in:
Greg Pomerantz 2026-11-01 15:38:22 -05:00
parent 02d1f097ac
commit d990627200

View File

@ -228,11 +228,13 @@ fn set_prefetch_window(lo: usize, hi: usize) {
VPORT.store(lo as u32, Ordering::Relaxed);
let mut q = Q.lock().unwrap();
let mut inq = INFLIGHT.lock().unwrap();
// Stale PREFETCH work (far behind the new viewport) is worthless — drop
// it. URGENT jobs (real pending requests) are never dropped here.
// The anchor just moved to `lo`: everything more than STALE_ROWS
// behind it is dead work (urgent included — a fling leaves urgent
// jobs for every band it crossed). Drop it instantly so it can never
// delay the new viewport or eat queue capacity.
let kept = q.len();
q.retain(|j| {
if j.urgent || j.idx + STALE_ROWS >= lo as u32 {
if j.idx + STALE_ROWS >= lo as u32 {
return true;
}
inq.remove(&j.id);
@ -269,14 +271,21 @@ fn pop_next() -> Job {
g = Q_CV.wait(g).unwrap();
continue;
}
// Only PREFETCH work is droppable. URGENT jobs are real pending
// requests (JS/Chromium is waiting on them) — even if the viewport
// anchor went stale, they must run.
// Distance-from-viewport policy: any job more than STALE_ROWS
// behind the viewport is dead work — the user flung past it, and
// decoding it would only delay what is actually on screen. This
// applies to URGENT jobs too (a fling queues urgent work for every
// band it crosses; all of it except the final band is stale). Safe
// because the anchor now always settles at the final scroll
// position (trailing send), and on-screen cells have idx >= VPORT
// so they can never be dropped. (A pure LIFO would not solve this:
// the stale pile sits at the stack bottom, never popped, still
// blocking the queue cap.)
if let Some(j) = g.front() {
if !j.urgent && j.idx + STALE_ROWS < VPORT.load(Ordering::Relaxed) {
if j.idx + STALE_ROWS < VPORT.load(Ordering::Relaxed) {
let j = g.pop_front().unwrap();
INFLIGHT.lock().unwrap().remove(&j.id);
tr(&format!("drop stale id={} idx={}", j.id, j.idx));
tr(&format!("drop stale id={} idx={} urgent={}", j.id, j.idx, j.urgent));
continue;
}
}