Skip to content

Ocarina of Time: keep gameplay at real speed below 60 FPS - #1704

Closed
nanotchec wants to merge 1 commit into
seedds:mainfrom
nanotchec:oot-simulation-real-speed-v131072
Closed

nanotchec wants to merge 1 commit into
seedds:mainfrom
nanotchec:oot-simulation-real-speed-v131072

Conversation

@nanotchec

Copy link
Copy Markdown
Contributor

Kokiri Forest can run below 60 updates per second while its time manager still advances by 16.667 ms per update. On an M3 Max, a probe of the native clock measured 3.000 seconds of gameplay time in 4.093 seconds of wall time.

This adds a build- and instruction-checked hook at the v131072 main's framework FPS load, main+0x6e6c98. It feeds the existing host's whole-vsync simulation step into the game's original time-manager conversion. Target zero follows the game's original FPS load. The opt-in settings used for validation were DM_FPS_TARGET=60 and DM_FPS_HOLD=off after repacking. The profile default stays at zero.

This overlaps #1584 and #1543. #1584 changes the framework's interval controller and presentation behavior at four guest sites and defaults to target 60. #1543 adds a host measured-delta path and hooks the guest's calculated delta. This PR offers a single guest FPS-load hook with the existing host controller. It shares the build's frame-step registration with #1497 if those changes are combined.

Validation

  • In docked Kokiri Forest at 2560 × 1440 on an M3 Max, the player confirmed correct movement and rendering with the local event-ordering fix active. The gameplay clock advanced 3.700 seconds in 3.6982 seconds (1.000487× real time) at 48.672 updates/s over 180 intervals. The steps were 138 × 16.667 ms and 42 × 33.333 ms. These figures measure the game clock in this scene. Movie timing and other scenes remain open.
  • Rewriting the clean v131072 main with this PR on bd979ced reproduced the gameplay-tested guest image and fixups byte for byte. The actual emitted instructions passed seven ARM64 cases with each of the game's two time-manager numerators.
  • Three asset-free ARM64 tests, 16 registry tests, 11 documentation tests and the Python lint ratchet passed.
  • Local regression scope is Ocarina of Time v131072, the only profile with this build ID. regress.py impact found one game-profile change and zero NVN or HLE entry points. The baseline and candidate use identical host source, shader chain and shader inputs. The profile has no committed smoke route. The runtime evidence above comes from the manual run and instrumented game clock. A fresh all-shader regression build was omitted.

@github-actions github-actions Bot added rewriter The NSO rewriter and per-build patches tools Tools and scripts (dm/tools, scripts) docs Documentation game: 0400486024DEC000 A game labels Nov 7, 2026
@autoclave73

autoclave73 commented Nov 7, 2026 •

Copy link
Copy Markdown

Will this also keep gameplay at real speed above 60 FPS?
Edit:tested it myself, no it does not.

@pythopect

Copy link
Copy Markdown

Tested on an M1 Max MacBook Pro (macOS 26.7.2, Xcode 27.2), Mac app build.

Applied this PR as a cherry-pick on top of db206a4, full shader map.
env.txt: DM_FPS_TARGET=60, DM_FPS_HOLD=off. Docked, fullscreen.

Before: Kokiri Forest ran at about 30–35 fps and the game was in slow motion.
After: same 30–35 fps, but gameplay runs at real speed. Walking, camera and
NPCs look normal.

Only tested around Link's house and Kokiri Forest so far. Thanks for this,
it makes the game playable on M1-class GPUs.

Aznracer pushed a commit to Aznracer/Mighty-Green-Kokiri-Kid that referenced this pull request Nov 8, 2026
@aksmith-git

aksmith-git commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

Tested on an iPad Pro (M5) as part of our Ocarina of Time (0400486024DEC000 v131072) branch, merged with #1245, #1707 and #1714 on our branch (main of 2026-11-08 plus our changes); the unicorn test passes (3 tests) and DM_FPS_TARGET=60 gives real speed on the Mac as described.

One thing from the device: the iPad runs best with DM_FPS_TARGET=0 (no target; Docked 1536x864 it holds 44-49 fps, GPU-bound, and a fixed 60 target with fps_hold off makes a late frame step 2 vsyncs, so motion judders). With target 0 the new stub reads the state page's target, finds zero and runs the original ldr s0,[x21,#0x2c8], so the game still steps 16.667 ms per update and runs in slow motion below 60 fps, as before the PR (your test_target_zero_keeps_the_original_fps covers exactly that).

Could the hook take the host's measured frame interval when the target is 0? The host already knows the presented interval (the display link / present pacing), so the stub could convert from 60 / measured vsyncs per frame instead of from the target. That would give real time on a device that runs at 45-50 fps without pinning it to 30 or 60. Happy to test a revision on the iPad.

@nanotchec

Copy link
Copy Markdown
Contributor Author

Closing this older hook as superseded by official main's Ocarina frame-ratio implementation, verified at d8b2b64a1fc52035f44cfa487637ba0d6f7fe69c in dm/games/0400486024DEC000/patches.py.

Main now matches the frame-ratio function by fingerprint and uses the host's vsync step directly (step * base_rate / 60), retaining the game's base-rate distinction and accounting for stepped vsyncs. This PR instead changes the earlier integer-FPS load. Reapplying it would overlap the official hook and replace the newer profile file, including its dynamic-resolution handling. The two hooks should not be stacked.

Thanks for the Mac and iPad reports. The DM_FPS_TARGET=0 observation remains relevant: both this PR and the current official hook retain the game's original calculation in that mode. Closing this superseded implementation does not claim that untargeted mode, or the reported iPad pacing, is fixed. That is a distinct follow-up to the official hook.

The old failed tool checks belong to this branch's previous base. This closure is based on the implementation already present upstream, not on treating those checks as passed. No player app or saves were changed during this audit.

@nanotchec nanotchec closed this Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation game: 0400486024DEC000 A game rewriter The NSO rewriter and per-build patches tools Tools and scripts (dm/tools, scripts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants