Skip to content

nvn/barrier: dispatches after a draw pass wait for it only after a game barrier (M1 / M2): OoT −0.5 ms a frame - #2515

Closed
AdyaGMD wants to merge 1 commit into
seedds:mainfrom
AdyaGMD:compute-game-barrier-m1
Closed

AdyaGMD wants to merge 1 commit into
seedds:mainfrom
AdyaGMD:compute-game-barrier-m1

Conversation

@AdyaGMD

@AdyaGMD AdyaGMD commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

What

A draw pass's relaxed end barrier ordered every later dispatch after the pass's vertex and fragment work. So each change from rendering to compute drained the GPU, even when the compute had nothing to do with the pass.

NVN only orders a dispatch after earlier rendering when the game calls nvnCommandBufferBarrier. With DM_NVN_COMPUTE_GAME_BAR (on by default on Macs without mesh-shading hardware, i.e. M1 and M2):

  • A draw pass ends without the dispatch stage in its end barrier.
  • The copy encoder opened for a dispatch right after it waits for earlier vertex / object / mesh / fragment work only if the game issued a barrier since dispatches were last ordered after rendering (g_cgb_need). Otherwise it waits for earlier dispatches and copies only.
  • A copy, any other encoder in between, and the game barrier mode off all keep the full barrier.

Why

A counter-free Metal System Trace of Ocarina of Time's slow spot (Kokiri Forest) on an M1 showed the GPU idle about 25 % of each frame. About 3.5 ms of that was at render → compute changes, 134 µs each, roughly four times a pass → pass change.

Performance

Ocarina of Time (0400486024DEC000), Kokiri Forest, MacBook M1 (8-core GPU). Measured with the mesh compute and light-pass merge from #2413 / #2441 on, in a tree with other local changes. DM_NVN_COMPUTE_GAME_BAR=ab, DM_AB=600, one run, phases 2–9:

GPU p50 per phase Mean
On 34.97 / 35.08 / 35.02 / 34.69 ms 34.94 ms
Off 35.98 / 35.11 / 35.13 / 35.67 ms 35.47 ms

About −0.5 ms a frame, and on was lower in every adjacent pair. 68 % of the light opens still waited, because OoT issues a barrier before most of its post-pass compute.

Picture: screenshots at frames 1500 and 2100 (DM_NVN_SHOT) with the switch on, compared against two runs with it off. They differ no more than the two off runs differ from each other (animation), and look right.

Switch (in docs/env_switches.tsv)

  • DM_NVN_COMPUTE_GAME_BAR=0|1|ab: on by default on M1 / M2 Macs, off elsewhere.

Not run

  • This branch's host in game (the change was measured in the other tree).
  • Any test suite.
  • iPhone.
  • M3 and later.
  • Other games.

🤖 Generated with Claude Code

…me barrier (M1 / M2 default): Ocarina of Time -0.5 ms a frame on an M1

A draw pass's relaxed end barrier ordered every later dispatch after the pass's vertex and fragment work, so each change from rendering to compute drained the GPU. A counter-free
Metal System Trace of Ocarina of Time's slow spot (Kokiri Forest) on an M1 showed the GPU idle about 25 % of each frame, about 3.5 ms of it at render-to-compute changes, 134 us
each. NVN orders a dispatch after earlier rendering only through nvnCommandBufferBarrier. With DM_NVN_COMPUTE_GAME_BAR (on by default where the GPU lacks MTLGPUFamilyApple9 on
macOS, the M1 and M2; =0 off, ab for the DM_AB phases) a draw pass ends without the dispatch stage, and the copy encoder opened for a dispatch right after it waits for earlier
vertex, object, mesh and fragment work only if the game issued a barrier since dispatches were last ordered after rendering; otherwise it waits for earlier dispatches and copies
only. A copy, another encoder in between and the game barrier mode off keep the full barrier.

Measured (0400486024DEC000, Kokiri Forest, MacBook M1 8-core GPU, with mesh compute and the light-pass merge of seedds#2413 / seedds#2441 on, in a tree with other local
changes): DM_NVN_COMPUTE_GAME_BAR=ab, DM_AB=600, one run, phases 2-9: on GPU p50 34.97 / 35.08 / 35.02 / 34.69 ms (mean 34.94), off 35.98 / 35.11 / 35.13 / 35.67 (mean
35.47), on lower in every adjacent pair. 68 % of the light opens still waited (OoT issues a barrier before most of its post-pass compute). Picture: screenshots at frames 1500 and
2100 (DM_NVN_SHOT) with the switch on against two runs with it off differ no more than the two off runs differ from each other (animation), and look right.

Not run: this branch's host in game (the change was measured in the other tree), any test suite, the iPhone, M3 and later, other games.

Co-Authored-By: Claude Opus 5.5 <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 12, 2026
@AdyaGMD AdyaGMD closed this Nov 12, 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