Repository navigation
Ocarina of Time: frame step in whole vsyncs (fps_target 60, 30 when 60 does not hold) - #1584
kylerodriguezmusic wants to merge 2 commits into
Conversation
…0 does not hold) The game never changes its present interval (its frame-rate tick returns in mode 1), so below 60 fps it played in slow motion. Stubs open the framework's interval controller and feed it the host's step; the game's logic follows the interval (23 frames for the bed-to-door run at interval 2 against 59 at 1). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MvzZTbmYKSqzD7rWeQmzei
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MvzZTbmYKSqzD7rWeQmzei
|
Compared #1543 and #1584 in game on an M4 MacBook Air (24 GB, macOS 27.2, built-in 60 Hz screen). Setup. Two Mac apps from the same tree: main b2d46b8 + #1544 + #1555, one with #1543 (f301c698; the later commit only changes the test) and one with #1584 (bf5dc97).
Route. Scripted runs from the Kokiri Forest autosave in Link's house: 60 s in the house, a timed walk to the door, out of the door, Saria's greeting, 8 screenshots on the balcony, then 180 s of scripted stick pushes outside (the walk). The runs alternated between the two apps. Game speed: both run at real time.
Frame pacing (house = 60 s idle, walk = 180 s outside):
"Present → display" is the host's At a 30 cap the two behave the same on this Mac: every frame is held 2 vsyncs, and the game runs at real time. At #1584's default 60 target, this Mac does not hold 60 (21–24 ms of GPU per frame at hold 1).
At the door, #1543 shows the game's one-frame stall (119–146 ms in 3 of 4 runs), as does #1584 at a 30 cap (128 ms). #1584 at its default has no frame over 74 ms there, since it is already at hold 3. Launcher. #1584's No GPU errors, and the same Not covered: docked mode, MetalFX, areas past the start of Kokiri Forest, a Mac that holds 60, and code in the game that might use 1/60 directly (#1543's note). |
…syncs, 30 when 60 does not hold) into switch2; one FRAME_STEP entry runs it and the fork's render-scale ceiling Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
|
Closing: superseded by 7d8dcdf on main, which places the host's frame step at the game's own frame-ratio division (fingerprint-matched, build-independent) instead of opening the framework's interval controller as this PR did. Thanks to PucaVaz for the M4 comparison against #1543; the note here about automatic mode on the M1 Ultra (the game raising its render resolution when told 20 or 30 fps, so a 3-vsync hold sticks) may still be useful, a 30 fps cap avoids it. |
Ocarina of Time (0400486024DEC000, v131072): frame step in whole vsyncs
Symptom: on a Mac that does not hold 60 fps (M1 Ultra, about 39 fps in Kokiri Forest) the game plays in slow motion. It runs one game tick per frame and never changes its present interval.
Cause: the sead framework's frame-rate tick (vtable +0x128,
main+0x4dbd60) returns at once because the framework's frame-rate mode(fw+0x24f) & 3is 1, so the interval controller embedded at fw+0x270 (main+0x3b4ef60, the same design as Breath of the Wild's) never runs and the interval stays 1 whatever the frame time.The logic does follow the interval: with cuts forcing the controller to interval 2 / 30 fps, Link's run from the bed to the door took 23 presented frames against 59 at interval 1 (
DM_NVN_REGLUMper-frame luminance; screenshots stall the present thread and let the game race, so they cannot time it). Two ticks a frame, as BotW's VFR does.Fix:
FRAME_STEPstubs in the profile'spatches.py,fps_target 60ingame.tsv:main+0x4dbd6c: with a target fps the mode check is skipped and the interval controller runs (never the VRR frame-rate controller);main+0x3b4ef90/+0x3b4ef9c: the controller's paused flag and "no frame time yet" exits are skipped with a target, so it reaches its output every frame;main+0x3b4f054(the controller's output, w21 = its interval): the host's step in whole vsyncs (state +0x20) once decided, vsyncs stepped counted at +0x30.setFrameRate(main+0x4dc0f0→nvnWindowSetPresentInterval) andsetWaitVsyncInterval(main+0x346c5c4, fps at fw+0xfc) take it from there.Measured (M1 Ultra, Encode Thread on, Handheld, MetalFX,
DM_FPS_TARGET=30, scripted Kokiri route):frame step: game time 60.00 s in 60.00 s (1.000 of real time); held 1 / 2 / 3 vsyncs 0 / 1800 / 0, frame p50 33.4 / p95 36.2 ms. Movies play, no first-start freeze, the Kokiri route works.Note on automatic mode (60 with 30 when it does not hold) on that Mac: told 30 or 20 fps the game raises its render resolution, GPU time grows to about 33 ms at a 3-vsync hold and the hold sticks at 20 fps (probes fail). The 30 fps cap keeps the hold at 2 and is steady. A later change could keep the game's resolution budget at the cap while the hold varies; not attempted here.
Profile README has the same note under "Frame rate".
🤖 Generated with Claude Code
https://claude.ai/code/session_01MvzZTbmYKSqzD7rWeQmzei