Skip to content

nvn: a uniform slot with no buffer bound is reported once per shader, stage, slot and reason - #2517

Open
akratch wants to merge 1 commit into
seedds:mainfrom
akratch:contrib/cb-unbound-per-case-20261112
Open

akratch wants to merge 1 commit into
seedds:mainfrom
akratch:contrib/cb-unbound-per-case-20261112

Conversation

@akratch

@akratch akratch commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

The stage N cbM has no uniform buffer bound diagnostic used one RED_ONCE(16, …) counter for every case, so only the first missing binding of a session was printed. Which slot that line named depended on the scene, and no other shader's unbound slot could show after it. On Ocarina of Time the same foliage compute shader (a039399e6336de1b_b, stage 5) printed cb3 at one save's load and cb2 in other scenes, which read like two different faults.

Change: cbuf_slot now reports each (shader, stage, slot, reason) once through cb_miss_first, where the reason is nothing bound or an address in no pool. Up to 64 cases are listed, then one closing line (more than 64 uniform slots have no buffer bound: the others are not listed). The message text (stage %d cb%d has no uniform buffer bound: shader %s, address %#llx size %#llx (frame %llu)) is kept as on main, so existing allowlists and normalized [RED] texts match; a run can now print more than one such line. What the slot reads (the zero bank) is unchanged.

The Ocarina of Time note explains the foliage line: the shader's slot 0 holds ten task-range ends, one per kind of item; slot 3 is read only by kind 2 and slot 2 only by kind 3. At the save examined kind 2 had no task, so the game binds nothing at slot 3 and the shader never reaches that read. The host misses no bind.

Validation on head 1f75398c based on upstream 0c078130f6db7d0d32c1dc28146feaf97713f008, Apple M4 Max / macOS 27.2, Xcode 27.2, profile 0400486024DEC000:

  • make -C dm/gfx/tests GAME=0400486024DEC000 check_t_cb_unbound (new, Metal validation): 28 checks, 0 failed. Two synthetic compute shaders with two unbound slots each give four reports, none repeated on a second encode; unbound slots read 0 at any offset on the GPU; a read of an unbound slot behind an untaken branch stores nothing (the game's shape), and takes the bound value once the guard is set and the slot bound; shader, stage, slot and reason each make a new case; the list stops at 64 with one closing line.
  • Negative control: the same test with the call site put back on the single counter (!g_red_once[16]++) fails 7 of 28 checks and prints one line. Fix restored, test rebuilt and passed again.
  • make -C dm/host GAME=0400486024DEC000 builds.
  • python3 dm/tools/tests/test_docs.py: 6 tests pass; python3 dm/tools/docs_symptoms.py --check: current.

Limits:

  • Diagnostic only: no rendering, binding or shader behaviour changes, and no picture or performance change is claimed.
  • The Ocarina of Time observations in the note (task-range ends, queue serials, buffer sizes) were made on a local branch on 2026-11-12, before this port, with that branch's older message format; the game was not run on this head, so the note quotes the line only up to the shader key.
  • Games that leave several slots unbound will now print one line for each instead of one in total; regress.py may show these as new [RED] lines against a baseline. regress.py check was not run. Other game notes that say "once per run" for this line are not edited.
  • The 64-case list is searched linearly under a lock on the miss path only; a bound slot does not reach it.
  • Not run: the full gfx suite, any game, iOS. No chain, profile-key or front-end interface change.

Docs: the existing docs/reference/rendering.md entry "An unbound uniform slot reads the zero bank" is extended (symptom, cause, fix, Found on, Check), the symptom index regenerated, and the Ocarina of Time note gains the explanation under Shaders and a line under "Found on this game".

… stage, slot and reason

The report had one RED_ONCE counter for every case, so the first case of a
run hid all the others, and which slot the line named changed with the
scene (Ocarina of Time's foliage compute shader a039399e6336de1b: stage 5
cb3 at one save's load, cb2 elsewhere). cb_miss_first lists up to 64
cases, then one closing line. The line's text is unchanged.

On Ocarina of Time the game leaves that slot unbound for a kind of item
the scene has none of, and the shader reads it only inside that kind's
empty task range, so the zero bank is never read there; the host misses
no bind (game note, Shaders).

t_cb_unbound (28 checks, Metal validation) dispatches two compute shaders
with two unbound slots each: four reports, none repeated, zeros read at
any offset, nothing stored by a read behind an untaken branch, and the
list's limit. 7 of its checks fail with the single counter.
@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 12, 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.

2 participants