Skip to content

dbe: fix frame timing at high frame rates - #69

Merged
marler8997 merged 1 commit into
masterfrom
dbe-frame-timing
Oct 18, 2026
Merged

marler8997 merged 1 commit into
masterfrom
dbe-frame-timing

Conversation

@marler8997

Copy link
Copy Markdown
Owner

Since the zig 0.17 upgrade, dbe stops rendering when the rate is turned up to 1000 FPS with double buffering disabled.

Cause: dbe waits for socket data with io.operateTimeout. std 0.17's posix batch wait converts the time left to milliseconds with @divTrunc before calling poll, and returns error.Timeout when poll times out (its comments say spurious timeouts are OK). So a timeout always comes back up to 1ms early: measured, a 1ms timeout returns after 0–11µs, 2ms after ~1ms, 15ms after ~14ms. dbe rendered on every timeout, so at the 1ms frame setting it rendered ~56,000 frames/s and flooded the X server. 0.15's poll(timeout_ms) never woke early.

Fix:

  • after a timeout, re-check whether it's time to render (continue) instead of rendering unconditionally
  • round the timeout up (add just under 1ms) so the wait doesn't spin with poll(0) until the frame is due
  • compute animation progress from nanoseconds instead of truncated milliseconds, which slowed the animation at high frame rates (pre-existing)

Verification

Instrumented build on Xvfb with double buffering disabled, logging frames per second and animation progress (should advance 0.5/s):

frame setting before after
1ms (1000 FPS) ~56,000–62,000 frames/s 938 frames/s, ~1% CPU
15ms — 66 frames/s

With only the re-check (no rounding up) it was 999 frames/s but used 100% of a core spinning. Animation progress now advances 0.50/s at both settings. zig build install install-xauth test-non-interactive passes; x86_64 windows compiles.

https://ampcode.com/threads/T-01a14b88-aff8-717e-bb9f-364137832240

In zig 0.17 the dbe example waits for socket data with io.operateTimeout,
which rounds the time left down to whole milliseconds when it polls (and
is allowed to return early). A 1ms timeout returned immediately, so at the
"1000 FPS" setting the example rendered ~56000 frames per second and
flooded the X server, which looked like rendering stopping. 0.15's
poll(timeout_ms) never woke up early.

- after an early timeout, check whether it's time to render instead of
  rendering unconditionally
- round the timeout up so the wait doesn't spin until it's reached
- compute the animation progress from nanoseconds instead of truncated
  milliseconds, which slowed the animation at high frame rates

Amp-Thread-ID: https://ampcode.com/threads/T-01a14b88-aff8-717e-bb9f-364137832240
Co-authored-by: Amp <amp@ampcode.com>
@marler8997
marler8997 merged commit bfcafa7 into master Oct 18, 2026
4 checks passed
@marler8997
marler8997 deleted the dbe-frame-timing branch October 18, 2026 04:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant