port: D186 — refuse a sub-30 Video.FpsCap instead of throttling the sim

sync_framerate_with_timer() runs inline on the scheduler thread
(osSpTaskStartGo -> gfx_run -> swap_buffers_begin), so a low frame cap
blocks VI-retrace delivery and drags every game thread down to the cap
rate rather than just dropping presented frames. There is no N64 analogue
(RSP/RDP/VI are separate silicon; the CPU never waits on them).

Clamp 0 < FpsCap < 30 to 0 (uncapped) with a warning, at both:
  - videoInit, so a bad ge007.ini value (e.g. dinged to 10 via the F10
    options overlay) is normalised and persists sane on next configSave();
  - gfx_sdl_set_target_fps, the fast3d chokepoint, which also covers the
    overlay's live set path.

Caps >= 30 are unchanged. Default (FpsCap = 0) is byte-identical to
golden (-level_09 framediff 3/3). The real fix — moving frame pacing off
the scheduler thread — is documented as owed in findings.md D186.
This commit is contained in:
James Dansereau committed 2026-09-03 00:51:40 -04:00
1 parent e548dec129
commit 7863ec096f
4 files changed
+68

No files matched your search

+9
View File
@@ -586,6 +586,15 @@ past it (walk off the end).
fixed-tick mode was assessed not-narrow (redesigns retrace/tick
semantics); design is in §F D117 if someone picks it up, after which
`framediff.py --exact` becomes usable.
- **Anything blocking on the scheduler thread throttles the whole sim**
(D186, cf. D134). The gfx task runs synchronously on `src/sched.c`'s
thread, and that same thread delivers VI-retrace events; any `sysSleep` /
busy-wait on that path (frame-rate cap, a lock, an asset load) stops
retrace delivery, so every game thread blocked on `osRecvMesg(retraceQ)`
stalls with it. On console the CPU never waits on RSP/RDP/VI. A PC frame
cap must therefore drop *presented* frames without sleeping that thread —
`Video.FpsCap < 30` is currently just refused (clamped to uncapped) as a
stopgap.
- **D24-implications — host-scheduling nondeterminism / fake priority
semantics:** the pthread kernel does not enforce N64's 0–31 priorities
(`osYieldThread` = `Sleep(0)`), so interleavings impossible on console can