-
Notifications
You must be signed in to change notification settings - Fork 0
Emulation Timing
The Linux port runs each game in a separate game-host process. The emulation loop and the GL/Vulkan window live there; the library window only feeds it a target geometry. Presentation is a native Wayland toplevel with a vsync'd EGL swap. See Emulator/EmulatorSession.cs for the decoupled loop.
The loop is audio-master-clocked with dynamic rate control (DRC) — RetroArch's model. Each frame, SdlAudio.ApplyDrc() nudges the resampler frequency ratio by ≤0.5% to hold the audio input queue at a target cushion. That servo is the primary sync mechanism: the core is paced to its content rate (_fps) and audio is resampled to match, instead of letting raw buffer drain dictate the loop. Coarse watermark guards (backpressure / low-watermark catch-up) are only far-extreme backstops.
SdlAudio exposes two buffer readouts and you must use the right one for the right job:
-
QueuedMs— a wall-clock estimate (total samples enqueued minus playback time elapsed). Use it where you want a smooth time-based figure. -
QueuedMsReal/QueuedMsSmoothed— reflect the actual device drain, so they're the correct control signal for pacing and DRC. The coarse guards servo the smoothed value so a single device gulp can't fire a spurious drain-stall.
The in-loop pacing is a lever for A/B testing on real hardware:
-
stopwatch(default) — high-res frame timer to the content rate; sleep most of the budget, spin the last ~1 ms. Audio thresholds are guards only. -
audio— sound-clock: after eachretro_run()adds ~1 frame of audio, wait for the device to drain back to the cushion. The device consumes at exactlysample_rate, so this paces the loop to real time at the core's true rate with no timer wobble. -
spin— pure busy-spin to the budget (lowest timer wobble, burns a core).
DRC is opt-in via EMUTASTIC_DRC=1 outside the GL spike path; the default decoupled GL path applies it every frame.
HW cores (Dreamcast, GameCube, N64 GL path) are paced to a fixed content rate the same way. The rate comes from the console handler's HardwareTargetFps (e.g. Dreamcast forces 60) when it returns a positive value, otherwise the core's reported av_info.timing.fps. Pacing the emu to that fixed rate — rather than free-running on audio drain, which drifts toward ~61fps and beats against the ~60Hz display — keeps speed and audio correct while the present thread is vsync-paced separately and just shows the latest produced frame. A missed vblank repeats a frame instead of slowing the core.
Because the loop is rate-paced rather than tied to N audio-buffer drain steps, 30fps titles need no special-casing — a 30fps content rate is just a different targetFrameMs.
EMUTASTIC_GL_PRESENT_THREAD (on by default) runs the core on the emu thread paced as above, while a separate present thread owns the GL window and shows the latest frame at vsync. The blocking FIFO swap on Wayland provides the vsync backpressure; re-presenting a duplicate on a slow frame is correct. This is what decouples display hitches from emulation speed. A single-threaded "swap-is-the-clock" path (EMUTASTIC_GL_PRESENT_THREAD=0) and an opt-in Vulkan overlay (EMUTASTIC_VULKAN=1) exist for A/B comparison.
The Windows build had a class of bugs rooted in WaveOut draining in steps synchronized to the DWM compositor rate (the notorious "N64 locked at 48fps on a 144Hz monitor" — 144 ÷ 3 = 48 drain steps/sec). The Linux port has neither WaveOut nor DWM: audio goes through SDL3 audio streams whose drain we read directly, and presentation is our own vsync'd Wayland toplevel. The compositor-synchronized-drain failure mode therefore doesn't exist on Linux — frame pacing is governed entirely by the audio-master clock + DRC and the present thread's vsync swap described above.
Console Notes
- Nintendo 64
- Nintendo 3DS
- GameCube
- Sega Saturn
- Dreamcast
- PlayStation
- PlayStation Portable
- TurboGrafx-CD
- Neo Geo
- Arcade
- Vectrex
- Philips CD-i
- Atari Jaguar
Features
- Artwork & Metadata
- Cheats
- Cloud Sync
- Controllers
- Disc-Based Systems
- Disk Swapping
- Portable Mode
- RetroAchievements
- ROM Hacks
- Hardcore Compliance
Technical
Platforms
Legal