From review (CodeRabbit):
- A static frame's inline save now waits for a queued write in flight and
drops a stale queued frame, under one write lock taken by both paths, so
the last scrolling frame can no longer land on top of the first static one.
- A background write that fails clears the recorded digest, so an unchanged
frame is written again instead of mtime-touching a stale file into looking
healthy.
- cleanup() stops and joins the writer thread, dropping a frame it hasn't
started, instead of leaving it (and its DisplayManager) alive.
- Vegas measures the panel's refresh from the 10th percentile of swap gaps,
not the median: a late swap only lengthens a gap, so with most frames late
in the window the median tracked the loop and locked in a rate too low
(then the scroll ran fast until restart). Samples are dropped whenever
the pacing is re-solved, so gaps from an old frame hold aren't divided by
a new one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vegas advanced by elapsed time, blended neighbouring columns every frame,
and paced itself with a sleep to target_fps. On hdpi (4x128x64 on one
chain, a 120Hz cap the chain cannot reach, ~95-100Hz real) that ran at
73fps with target 90 and ~89fps with target 125: the sleep drifted
against the refresh and missed a vsync every few frames, and the blend
read as shimmer on the panel (and as "anti-aliased" text in the preview).
smooth_scroll now means the crisp pacing the plugin tickers already use:
a whole number of pixels per presented frame, each held for frame_hold
refreshes, with SwapOnVSync as the clock. The speed is solved against the
panel's measured refresh, timed from our own swaps once scrolling starts,
because the configured limit is only a cap -- at "120Hz" 90px/s solves to
3px every 4 refreshes, at the real ~97Hz to 1px every refresh. The old
blend stays available as sub_pixel_blend (default off).
With the web preview open, the render thread also PNG-encoded the whole
512x64 frame five times a second, 12-14ms each -- longer than a refresh.
Mid-scroll that encode now runs on a single-slot writer thread (Pillow
releases the GIL while compressing); static frames still write inline.
Measured on hdpi, 3-minute soak with the preview open: 3 of 17,280
frames held an extra refresh (0.02%), down from ~6-20%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>