Skip to content

The visibility ring grows on demand to 128 buffers, so a counting submission in flight no longer makes and drops a buffer of its own (#2535) - #2536

Open
stan69b wants to merge 1 commit into
seedds:mainfrom
stan69b:pr/vis-ring-grow
Open

stan69b wants to merge 1 commit into
seedds:mainfrom
stan69b:pr/vis-ring-grow

Conversation

@stan69b

@stan69b stan69b commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Fixes #2535.

What changes

VIS_RING goes from 8 (ALLOC_MAX) to 128 in nvn_mtl.m. vis_take already grows the ring lazily and reuses a buffer once its submission's fence passes, so the ring only grows to the number of counting submissions actually in flight. That's at most 8 MiB, all kept resident.

Why it matters: since fd8188c9, a frame's submissions share a command allocator, so more counting submissions are in flight than allocators. With the GPU behind, the ring of 8 was often all in flight. Each counting submission then made a 64 KiB buffer of its own and added it to the residency set, then removed it after the submission. That's two residency commits through the kernel's GPU driver per counting submission.

Measured

iPhone 17 (A19, 8 GB, iOS 27.2.1), Ocarina of Time at the launcher's 30 fps cap with dynamic resolution, from a save. The build was the owner's local build (main 547c5db6 with #1971, #2270 and #2241), with and without this change:

Before After
Kakariko Village, fps 8–12 25–26
Kakariko, frame p50 62–118 ms 37 ms
Kakariko, GPU p50 25–45 ms 20 ms
Kakariko, residency commits per 300 frames 1,700–5,000 51–89
Hyrule Field, fps 10–12 29.5
Hyrule Field, frame p50 69–78 ms 33 ms

The cause was found from a sysdiagnose spindump. The game's main thread was in nvnSyncWait → mtl_wait_at, and the Metal 4 submission threads were in IOGPUFamily. Details are in the issue.

Checked

  • t_wait_event: a new case runs 24 counting submissions in flight, none complete. Each takes a distinct ring buffer, and once they complete the next one reuses one without growing the ring. The case fails on main (2 of its 3 checks).
  • t_render_enable_queue, t_render_counter_overlap, t_counter_clock and test_docs pass.
  • The Mac host builds.
  • Docs: a reference entry in docs/reference/frame-rate.md after the shared-allocator entry, the symptom index, and a line under Ocarina of Time's "Found on this game".

Regression check

Not run yet. On this Mac only Ocarina of Time reaches counting submissions often enough to matter, and a Mac never ran the ring dry (the reference entry for fd8188c9 says the same for an M4 Pro). A scripts/regress.py check on Ocarina of Time will be added here when it has run.

…mission in flight no longer makes and drops a buffer of its own (issue seedds#2535)

Since a frame's submissions share a command allocator (fd8188c), more counting submissions are in flight than the ring of 8 held. With the GPU behind, none was free, and each one made a 64 KiB visibility buffer, added it to the residency set and removed it after the submission: two residency commits through the kernel's GPU driver per counting submission. Ocarina of Time on an iPhone 17 made about 9 a frame in Kakariko Village. The game's main thread waited in nvnSyncWait for 30-60 ms a frame, and it ran at 8-12 fps with 25-45 ms of GPU time.

VIS_RING is 128. vis_take already grows the ring lazily and reuses a buffer once its submission's fence passes, so only as many buffers are made as are in flight: at most 8 MiB, all kept resident. A pass past 128 in flight still takes a buffer of its own, as before.

Measured on the iPhone 17 (iOS 27.2.1, 30 fps cap, dynamic resolution) from the owner's save, on the owner's local build (main 547c5db with PRs seedds#1971, seedds#2270 and seedds#2241):
- Kakariko Village: residency commits per 300 frames 1,700-5,000 → 51-89; 8-12 → 25-26 fps; frame p50 62-118 → 37 ms; GPU 25-45 → 20 ms.
- Hyrule Field: 10-12 → 29.5 fps; frame p50 69-78 → 33 ms.

Checked: t_wait_event, with a new case (24 counting submissions in flight each take a distinct ring buffer, and the next one reuses one once they complete) that fails with a ring of 8; t_render_enable_queue, t_render_counter_overlap, t_counter_clock and test_docs pass; the Mac host builds.
@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation game: 0400486024DEC000 A game 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 game: 0400486024DEC000 A game 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.

iPhone: counting submissions make and drop a visibility buffer each, 16 residency commits a frame (Ocarina of Time 8-12 fps)

2 participants