Residual scroll jank at 120 Hz (suspected Slint event-loop bug) needs
per-frame + per-stage timing the logcat ring buffer can't hold. New
cargo feature `perf` (default OFF — all sites are cfg-gated, zero
overhead when off):
- FR: per-frame app-side render cost + frame gap, from the rendering
notifier (BeforeRendering/AfterRendering).
- STG: event-loop stage costs (wake/timers/events/poll/lastrender) from
timestamps instrumented into the pinned vendor copy of
i-slint-backend-android-activity (stg.rs; Cargo.toml now depends on
it directly + optional under `perf`).
- DECODE: per-thumbnail-job cost on the workers.
- All lines mirrored to /sdcard/Download/.gallery_perf.log (logcat
rotates too fast at ~120 lines/s).
Format + reading guide: docs/BUGS/scroll-jank-120hz.md.
The 19-26 ms mid-scroll stalls (Mali-only, fixed content offsets) were
the Skia renderer's final synchronous GrDirectContext::flush() blocking
the UI thread on Mali driver back-pressure — proven by per-stage
timestamps in the vendored renderer (stall frames: flush 19-24 ms,
walk 1-3 ms, 1 binding re-eval, image imports 0.1 ms each).
- vendor/i-slint-renderer-skia (pinned 1.18.1, [patch.crates-io]):
remove that one flush. Redundant on the wgpu backend: the surface
already calls flush_and_submit before queue.present, same Vulkan
queue, in-order. Phone: 0 stalls across 4 runs (max 3.6-7.4 ms vs
the 8.3 ms budget), display verified clean.
- docs/BUGS/slint-skia-final-flush-jank.md: full evidence, prior art
(slint-ui/slint#12030 closest), open question for a future
upstream filing (not filed yet).
- Profiling also retired the O(n)-walk theory: Slint 1.18 prunes the
item walk to ~133-152 items; the windowed Flickable built on that
theory was already reverted (ListView is smooth with the fix).
- Strip all jank-hunt instrumentation: FR/SCR/TICK/APLYD/STG logging,
stg markers, .gallery_* file knobs, jsamp thread sampler,
DbgScroll programmatic scroll, nblog perf-file mirroring.
Also fixes the 'launches into unstoppable fast scroll' bug: a
leftover .gallery_cmd was re-read on every launch (file never
deleted) and overrode user swipes — the hook is gone.
- Keep: nblog (logd backpressure is real), zero-dimension decode
guards, keep-alive (default-off).
- HANDOFF: replace stale windowed-Flickable section with the actual
root cause/fix; 15 unit tests pass.
Verified on phone (aarch64, 8580 photos) and emulator (x86_64).