gallery/vendor/i-slint-renderer-skia/scn.rs
Greg Pomerantz 2f4768f354 Fix 120Hz scroll jank end-to-end: render-ahead present + full-cache eviction off the UI thread
Three root causes, all fixed and verified on the Pixel 9 Pro:

1. Present phase (backend + renderer): VSYNC_LOCKED_RENDER defers the
   render to the vsync wake; RENDER_AHEAD presents the previous frame at
   the start of render() (phase = wake + ~1.1 ms) and holds the new
   frame one slot. Crash fix: a held wgpu frame must be PRESENTED, never
   merely dropped, before the next acquire (AlreadyAcquired panic at
   launch otherwise); discard_pending_frame presents too.

2. Full-res prefetch churn (src/lib.rs): the 8-slot full cache cycled
   through a ~20-cell viewport forever (137 decodes/20 s) and each
   eviction free()'d a 50 MB Vec on the UI thread (20-52 ms CPU spikes,
   ~7/s = the residual SLOWEV NonMain jank). Fix: 60 s tombstone
   cooldown on evicted paths (idle prefetch skips, urgent tap bypasses)
   + off-thread reaper for the freed blobs (insert: 21 ms -> 4 us).

3. (earlier) Skia final flush + Mailbox present mode (vendor, M3).

Instrumentation (all behind --features perf): OTHR/INVK/INVK_TAG/FLCK
lines for cross-thread closure timing and push-site tagging.

Warm measured swipe, 8580-file grid: cadence median 8.33 ms (exact
120 Hz), p99 15.5 ms, 5/552 gaps >16.7 ms (0.9%, max 28.3 ms, zero
>33 ms); PRES phase median ~994 us, zero late frames. Docs updated
(docs/BUGS/scroll-jank-120hz.md, full scorecard + line reference).

Also: vendored i-slint-core + wgpu-hal (vkshim interposition patch),
vkshim profiling tooling, backend made a non-optional dep, debuggable
flag for simpleperf (REMOVE before shipping).
2026-10-30 02:49:23 -04:00

69 lines
2.5 KiB
Rust

// Jank-hunt: per-frame draw-op census. Answers "is the scene we hand to
// Skia/Mali unnecessarily big or expensive?" A scrolling 3-column grid of
// thumbnails should be a few dozen cheap ops per frame; if the counts (or
// the total drawn area, or the image upscale ratio) are large or growing,
// that explains the Mali GPU backpressure. See docs/BUGS/scroll-jank-120hz.md.
use std::sync::atomic::{AtomicU64, Ordering};
pub static SCN_RECT: AtomicU64 = AtomicU64::new(0);
pub static SCN_RECT_AREA: AtomicU64 = AtomicU64::new(0);
pub static SCN_IMG: AtomicU64 = AtomicU64::new(0);
pub static SCN_IMG_AREA: AtomicU64 = AtomicU64::new(0);
/// Max (drawn area / source area) x 100, i.e. a value of 200 = drawn at 2x
/// the source area (a 1.41x linear upscale). High values = the GPU is
/// upscaling small textures a lot (or the "source" is a tiny fallback).
pub static SCN_IMG_UP: AtomicU64 = AtomicU64::new(0);
pub static SCN_TEXT: AtomicU64 = AtomicU64::new(0);
pub static SCN_BORDER: AtomicU64 = AtomicU64::new(0);
pub static SCN_SHADOW: AtomicU64 = AtomicU64::new(0);
pub static SCN_CLIP: AtomicU64 = AtomicU64::new(0);
pub fn reset() {
for s in [
&SCN_RECT,
&SCN_RECT_AREA,
&SCN_IMG,
&SCN_IMG_AREA,
&SCN_IMG_UP,
&SCN_TEXT,
&SCN_BORDER,
&SCN_SHADOW,
&SCN_CLIP,
] {
s.store(0, Ordering::Relaxed);
}
}
/// Add a value to an atomic (relaxed), used by the item renderer.
#[inline]
pub fn add(slot: &AtomicU64, v: u64) {
slot.fetch_add(v, Ordering::Relaxed);
}
#[inline]
pub fn inc(slot: &AtomicU64) {
slot.fetch_add(1, Ordering::Relaxed);
}
#[inline]
pub fn max(slot: &AtomicU64, v: u64) {
let _ = slot.fetch_max(v, Ordering::Relaxed);
}
pub fn report(frame: u64) {
let rect = SCN_RECT.load(Ordering::Relaxed);
let img = SCN_IMG.load(Ordering::Relaxed);
let text = SCN_TEXT.load(Ordering::Relaxed);
let border = SCN_BORDER.load(Ordering::Relaxed);
let shadow = SCN_SHADOW.load(Ordering::Relaxed);
let clip = SCN_CLIP.load(Ordering::Relaxed);
let rect_area = SCN_RECT_AREA.load(Ordering::Relaxed);
let img_area = SCN_IMG_AREA.load(Ordering::Relaxed);
let img_up = SCN_IMG_UP.load(Ordering::Relaxed);
let total = rect + img + text + border + shadow;
log::info!(
"SCN f={} rect={} rarea={} img={} iarea={} iup={} text={} border={} shadow={} clip={} total={}ops",
frame, rect, rect_area, img, img_area, img_up, text, border, shadow, clip, total
);
}