Go to file
Greg Pomerantz 32aa2af9cb 120Hz: app-owned frame driver (spin) — the OS no longer paces renders
The user's ask: 'put in our own frame rate timer that doesn't drop
frames so we are not depending on the OS.' The OS can still own the
display latch (SF) — render-ahead presents ~1 ms after the edge with
~7 ms margin, so owning the RENDER clock is sufficient.

WHILE ANIMATING, the UI thread no longer waits on any OS wake:
  * poll is non-blocking (timeout 0); the loop spins at ~3-4k iters/s
    (250 us hrtimer park after each no-render iteration — an hrtimer
    park cannot be swallowed the way ALooper timeouts were, measured
    4-6 ms late from inside kernel/epoll)
  * the render decision is grid-driven: render when in a not-yet-
    rendered slot AND >=0.3 ms past its edge. No saw_wake.
  * the Choreographer + eventfd remain only as the GRID SENSOR.

Two grid bugs found and fixed while landing this (both made the first
driver build DOUBLES 8-10% of frames):
  * ANCHOR POLICY (wgpu_30_surface::note_vsync_edge): VSYNC_EDGE_NS is
    a SMOOTH grid anchor, not 'last observed edge'. A callback that
    fits the extrapolation (<1.5 ms deviation) does not move the
    anchor — a LATE callback re-anchoring shifts the anchor by
    (interval - P) and makes an already-rendered slot look NEW to a
    value-space guard. Period updates now require single-slot deltas.
  * BOOKKEEPING in SLOT-INDEX space (last_rendered_slot), not edge
    values, and ALL render paths mark it: locked accept, unlocked
    dirty render, and the render-ahead FLUSH (the flush not marking
    caused the +1.1/+1.2 true doubles after animating flickers).
  * POINTER window 200 -> 400 ms: bursty input (adb drags; finger
    pauses) expired 'animating' mid-drag, firing the locked->unlocked
    flush on top of the dirty render (double per flicker, ~5%).
  * flush now also skips when the iteration already rendered.

Phone, sltest (3s+1s+3s adb drags, jank_eval referee):
  buildC (pre-wake-fd-fix):   127 drops + 12 stalls
  slt14-spin (this driver):     2 drops +  1 stall + 8 dbl + 4 late
                                in 978 frames; phase p10-p90 0.86-0.90 ms
  gallery (real textures, same driver): drag windows 6+2 drops,
  7+11 doubles in 820 frames; phase p10-p90 0.73-0.95 ms
Remaining (visible next): drag-START warmup (first frame 20-40 ms:
CPU clock ramp after idle — the 'fling start jank' the user reports)
and isolated 2-slot drops (gallery: FullCache insert/eviction cost on
the UI thread).

Cost: ~60-70% of one core during active scroll; the perpetual
runnability also forces EAS big-core placement (the thread was
measured at 820 MHz on little cores during scroll — a large part of
the gallery's finger jank).
2026-10-30 18:21:50 -04:00
docs/BUGS 120Hz: jank_eval referee + slot-based wake guard + MISS ledger 2026-10-30 13:29:50 -04:00
scripts 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
shim 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
src 120Hz: jank_eval referee + slot-based wake guard + MISS ledger 2026-10-30 13:29:50 -04:00
tools 2ms poll cap during active scroll + record_check.py (display-side referee) 2026-10-30 16:40:09 -04:00
vendor 120Hz: app-owned frame driver (spin) — the OS no longer paces renders 2026-10-30 18:21:50 -04:00
.gitignore 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
build.rs M0: Slint gallery scaffold + development hand-off 2026-10-27 12:22:59 -04:00
Cargo.lock 120Hz: app-owned frame driver (spin) — the OS no longer paces renders 2026-10-30 18:21:50 -04:00
Cargo.toml Fix thumbnail pop-in: hold-queue for paint-cap overflow + append-only scan streaming + window-liveness watchdog 2026-10-30 09:04:01 -04:00
HANDOFF.md handoff: section 8.10 — the zero-jank perf tooling (jank_eval + jank_capture) 2026-10-30 14:46:37 -04:00
LICENSE Initial commit 2026-10-27 12:13:22 -04:00
README.md M1: metadata scan + sqlite DB + placeholder list 2026-10-27 13:28:33 -04:00

gallery

A high-performance image gallery for Android (primary), Linux and macOS — Rust + Slint 1.18.

Status: M1 (metadata scan + DB) done. See HANDOFF.md — the development hand-off with the full plan: architecture, thumbnail pipeline, milestones M1–M7, Slint gotchas, permission flow, and performance targets. Next: M2 (thumbnail engine).

Build

./scripts/build.sh debug     # debug x86_64 APK + install on emulator
./scripts/build.sh           # release x86_64 (emulator)
./scripts/build.sh aarch64   # release aarch64 (device)
cargo run                    # desktop (Linux needs libfontconfig1 + pkg-config)

Requires: Rust (rustup), cargo-apk2, Android SDK + NDK 27 (see HANDOFF.md §3 for exact paths/env).

License

GPL-3.0 (see LICENSE). Built on Slint, used under the Slint royalty-free license for proprietary apps (see HANDOFF.md §10.4).