Skip to content

The frame step starts no GPU-slowed probe when the GPU's time at kmin does not fit kmin (Ocarina of Time probed at every camera turn) - #2611

Open
DeathKhan wants to merge 1 commit into
seedds:mainfrom
DeathKhan:claude/nx-fstep-probe
Open

DeathKhan wants to merge 1 commit into
seedds:mainfrom
DeathKhan:claude/nx-fstep-probe

Conversation

@DeathKhan

Copy link
Copy Markdown

What and why

The symptom: a GPU-bound game whose GPU time follows the view probes back to 60 fps at every turn of the camera. Its GPU time is more than a vsync at every hold, with the GPU clock already at its maximum. Each probe gives 60-90 late frames at hold 1, then the probe failed, and often hold 3 (20 fps) after it.

The cause: the GPU counts as slowed (nvn_fgpu_slow) when its time at the longer hold is FSTEP_GPU_SLOW (1.3) times its time at kmin (the reference). That comparison assumes the reference fits kmin, so that only the clock the longer hold left stands between the game and kmin. A reference above kmin means kmin was not held even at the clock kmin raised.

For example, Ocarina of Time in Kokiri Forest costs 1.2-2.1 vsyncs of GPU time, depending on where the camera looks. With a reference of about 1.25 learned in the light view at hold 1, the heavy view's 2.05 is 1.6 times it. So every heavy view counted as a slowed GPU and started a probe that could not hold.

The change (nvn_fstep.h, one line in hle_nvn.c):

  • nvn_fgpu keeps the kmin its reference belongs to.
  • nvn_fgpu_slow requires the reference to be at most kmin.
  • The probe line names the reference, e.g. GPU 1.60× its time at hold 1 (1.25).
  • The other probe reasons (the CPU on efficiency cores, the cost that held kmin) are unchanged.

Docs: a reference entry in docs/reference/frame-rate.md ("A GPU reference that does not fit the shorter hold starts no probe"), and the symptom index regenerated.

Where it comes from: DeathKhan/nx2android, an Android port that shares nvn_fstep.h (its commit 2a7881e66). DroidPlay Core (enjoyerofslop/droidplay-core) already carries the same rule in its nvn_fgpu_slow.

One difference from those trees: they also move the reference half-way toward a failed probe's frames after its grace (from shirai91/nx2android), and main doesn't. On main a failed probe leaves the reference as it was. So the t_fstep case here starts in the light view, where main learns its reference, rather than at a title screen.

Overlap: #2270 and #2566 also change nvn_fgpu_slow (a same-work check on draws and dispatches). Their condition and this one are independent, so whichever lands second has a one-line merge. I found no open PR with this rule.

Checked

  • Tests (Arch Linux, clang): clang -O1 -Wall -Werror dm/gfx/tests/t_fstep.c -lm.
    • With this change: 93 checks, 0 failed.
    • Main's nvn_fstep.h with the new case: 1 failed, the new one (19 probes and 546 frames at hold 1 in 7,200 frames).
  • Tool tests: dm/tools/tests test_docs, test_lint_c and test_env_switches pass (26).
  • Not run:
    • make -C dm/gfx/tests run, which needs Metal.
    • lint_c.py tidy, which needs the Mac compile database.
    • regress.py.
  • Games run: none on a Mac or an iPhone with this branch.
    • On DeathKhan/nx2android (Android, Ayn Odin 3, Adreno 830): The Legend of Zelda: Ocarina of Time, Kokiri Forest, a 110 s run with camera turns: 4 probes before, 1 after. The one left was the first, from the title screen's reference of 0.25.
  • Devices and OS: Arch Linux for the unit test. The Odin 3 (Android) for the game run, on the Android tree.

CI: main's own t_save_sync check fails on GitHub's macOS runners, which report VirtualMac2,1 where the test expects Mac (see #2246). A red run there is not from this change.

Docs

  • The finding is in its docs/reference/frame-rate.md entry, and python3 dm/tools/docs_symptoms.py was run (the symptom index)
  • No game files, keys or data extracted from a game in the change or the attachments

🤖 Generated with Claude Code

…e at kmin does not fit kmin

The GPU counts as slowed when its time at the longer hold is FSTEP_GPU_SLOW (1.3) times its
time at kmin. That assumes the reference fits kmin, so that only the clock the longer hold left
stands between the game and kmin. A reference above kmin means kmin was not held even at the
clock kmin raised. nvn_fgpu now keeps the kmin its reference belongs to, and nvn_fgpu_slow
requires the reference to be at most kmin. The probe line names the reference.

Ocarina of Time on an Android port that shares nvn_fstep.h (DeathKhan/nx2android, Ayn Odin 3,
GPU clock at its maximum at every hold) costs 1.2-2.1 vsyncs of GPU time in Kokiri Forest by
where the camera looks: the heavy views were 1.5 times the light view's reference, and each turn
of the camera started a probe to hold 1 (60-90 late frames, then hold 3). A 110 s run with camera
turns: 4 probes before, 1 after. DroidPlay Core carries the same rule.

t_fstep: the view case (1.25 vsyncs, 2.05 for 60 vsyncs in every 400): 19 probes in 7,200 frames
on main, none with this. Reference entry in frame-rate.md; symptom index regenerated.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation labels Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant