fix(vi): keep the game at real speed under a Frame rate cap above 60 #1612
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1612
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/frame-rate-cap-game-speed"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
With the Frame rate cap above 60 (the Insert menu's row from #1485, or
HOS_FPS_MAX), the game runs faster than real time: 4 times too fast in the menus at 240 fps, and 1.2 to 1.4 times in Kokiri Forest at 74 to 85 fps. This makes the game keep real time at any rate up to the cap.Why it happens
The cap raises the pacing and writes the measured rate, up to the cap, into the engine's nominal rate (
+0x2c8), from which the engine makes its time step (60 / rate). But the engine's own rate is 60 divided by a whole number of display intervals, never above 60, and its frame-rate controller puts 60 back over a higher value before the step is made from it. So above 60 fps every frame still steps 1/60 s.What changes
nx2/oot_patches.pypatch_frame_seconds: at the two places where the engine turns the nominal rate into a time step (the frame's step inf_80706be0, the global step inf_83b6ea90), the lifted code takesbase * <the frame's seconds>when the host gives it a frame time, and the game's own divide when it does not. The hook goes into both places or neither; a lift where they are not both found is left as it is, with a warning.host/nn_vi.crealtime_step: with a cap above 60 it publishes the frames' own time (the same 5-frame average the real-time step already uses, at most 1/15 s as before, at least 1/240 s) and keeps the rate under it within the engine's own 15 to 60.HOS_FPS_STEP=0keeps the rate-up-to-the-cap behaviour, for comparisons. A build whose lift does not have the hook keeps it too.HOS_FPS_LOG=1also logs the game clock against the wall clock every 300 presents (vi: game clock ...: ... (speed 1.000) at 85.1 fps), which is how the numbers below were read.Tested
Windows 11, Ryzen 7 5700X3D, Radeon RX 9070 XT (Vulkan 1.4, driver 0x8001a0), this branch on main
779bdcf. Kokiri Forest from a save, 5120x1440 (32:9), a scripted run measured over the 20 s after the save load. "Speed" is the game clock's advance against the wall clock, 1.000 being real time.HOS_FPS_MAX=240, this PRHOS_FPS_MAX=240 HOS_FPS_STEP=0(as main is)tests/test_frame_rate_cap_step.py(registered intests/run_all.py): the patch on a synthetic function of the lifted shape (both places, a second run, another game version, one place missing, a rerun after one file changed), andrealtime_stepcut fromhost/nn_vi.cand run with the cap at 120 and 60, withHOS_FPS_STEP=0and without the hook. It fails on main'snn_vi.cand on main'soot_patches.py, each on its own.the frame's time at 1 step divide(s)in two files).Not covered
Related
#1485 added the cap. #1367 (closed in its favour) and #340 (closed) stepped the game by wall time at the first of the two places; this one uses the real-time step's own average at both.
🤖 Generated with Claude Code