gallery/vendor
Greg Pomerantz 7c2d0f354e 120Hz: early waker thread + render freshness guard (vsync-edge pacing)
The Choreographer vsync callback reaches the UI thread only 2.5-6 ms
AFTER the vsync edge (measured on the phone). With a 2.5-5 ms Skia
render plus present, that left no phase margin inside the 8.3 ms slot:
51% of frames landed one slot late (judder) and ~4% two slots late
(hitches), on every build tested so far.

Attempted fixes, all measured and retired (see commit history):
- render-ahead hold (present previous frame at next render start):
  the held present lands after the NEXT wake's 3.2-6 ms Choreographer
  latency -> 52% one-slot late.
- present-at-end + present GATE (sleep on the UI thread to quantize
  the present to the vsync grid): the gate sleep (2.5-4 ms) added to
  the slot budget (wake 5.3 + core 3 + gate 3 + present 1 = 12.3 ms >
  8.3 ms) -> cadence collapsed to 60 Hz.

Working fix (this commit):
- vsync.rs: an 'early waker' thread learns the vsync grid from the
  callback's frame_time_nanos (vkprobe::note_vsync_edge) and wakes the
  main looper ~0.8 ms BEFORE each edge while animating. Render start
  moves from edge+2.5..6 to edge-0.8..+0.5, so the present lands at a
  natural ~edge+3..5 ms phase with no UI-thread sleep.
- lib.rs: a render freshness guard (min gap = period - 1.5 ms) makes
  the FIRST wake of each slot (early or the late Choreographer
  fallback) render and rejects the second (double render = 60 Hz
  collapse). Threshold sits between late-after-early (5.8 ms, reject)
  and early-after-late (7.5 ms, accept).
- lib.rs: locked renders no longer consume pending_redraw (it carried
  the motion invalidations; consuming it starved the follow-up
  unlocked iteration -> 60 Hz collapse).
- stg.rs: IT lines now log the render decision (locked/saw_wake/
  pr_before/do_render); vkprobe logs gate sleep (GATE_US, now 0).

Measured (phone, 8580-file grid, slow 4 s drags):
  in-burst cadence: 8.29-8.44 ms median, p90 8.6-10.2 ms
  (was 8.36 median / 10.2 p90 with 3.7-20% two-slot gaps)
  in-burst >16.7 ms gaps: 0-2 per burst (was 3-13)
  present-to-present: 27% exact one slot, 33% one-slot-late steady
  state (imvisible), 3% f-jumps (Skia core 2.5-5 ms variance).
Residual judder lever: Skia core cost variance (next step).

Test hygiene reminders (HANDOFF 8.10): verify ResumedActivity, keep
the task clean (sz=1), record the perf-log byte offset before each
run (the file accumulates across process launches).
2026-10-30 11:06:58 -04:00
..
i-slint-backend-android-activity-1.18.1 120Hz: early waker thread + render freshness guard (vsync-edge pacing) 2026-10-30 11:06:58 -04:00
i-slint-core Fix 120Hz scroll jank end-to-end: render-ahead present + full-cache eviction off the UI thread 2026-10-30 02:49:23 -04:00
i-slint-renderer-skia 120Hz: early waker thread + render freshness guard (vsync-edge pacing) 2026-10-30 11:06:58 -04:00
wgpu-hal-30.0.1 Fix 120Hz scroll jank end-to-end: render-ahead present + full-cache eviction off the UI thread 2026-10-30 02:49:23 -04:00