Skip to content

fix(gfx): the empty-grid guard dropped every indirect compute dispatch (Ocarina of Time's grass, #2152) - #2190

Open
peachtaozhutou wants to merge 1 commit into
ly05010419:mainfrom
peachtaozhutou:fix/indirect-dispatch-empty-grid
Open

peachtaozhutou wants to merge 1 commit into
ly05010419:mainfrom
peachtaozhutou:fix/indirect-dispatch-empty-grid

Conversation

@peachtaozhutou

Copy link
Copy Markdown
Contributor

The bug

The shared layer's dispatch() skips an empty grid before anything else:

if (!dp->x || !dp->y || !dp->z) return;

The guard is right for direct dispatches (Metal 4 rejects zero dimensions, and BotW's ordinary loading path submits them). But an indirect dispatch is recorded by nvnCommandBufferDispatchComputeIndirect (hle_nvn.c) with only its caller and the argument-buffer address — x/y/z are zero at record time by design; the real grid lives in the 12 bytes the buffer holds. The guard therefore returned before dp->indirect was ever looked at, and every indirect compute dispatch was silently dropped — the exact class of failure hle_nvn.c's own comment warns about ("entries that would silently drop GPU work (indirect draws/dispatch …) were removed").

The regression

This is #2152: Ocarina of Time's grass is generated through indirect compute dispatches, so Hyrule Field and Lon Lon Ranch lost their vegetation on the shared layer. The reported bisect (good b0d2f353, bad f9f7aa8d) is exactly the window this guard came in with. Ocarina of Time's own graphics layer had no such guard, and its indirect dispatches read their arguments and ran. Trees, characters and everything drawn through ordinary draws were unaffected, which is why the fields broke alone. The v28 mesh-output fix (#2166) did not touch this path and did not restore the grass.

The fix

One condition: if (!dp->indirect && (!dp->x || !dp->y || !dp->z)) return;. Direct zero grids keep being skipped; an indirect dispatch whose argument buffer holds zeros still runs and does nothing, as before.

Verification

MacBook Pro (Mac16,8) M4 Pro 24 GB, macOS 27.2.1, Ocarina of Time v131072, same save and settings, update_runtime.py rebuild:

Separately, this checkout also carries a local workaround for the pinned .sha256 format change of PR #2166 (#2184) — it is not part of this PR, which is the single nvn_mtl.m hunk only.

…he empty-grid guard dropped every one of them

The guard took the direct dispatches' zero grids before the dispatch's own
indirect branch: Metal 4 rejects zero dimensions and BotW's ordinary loading
path submits them. But nvnCommandBufferDispatchComputeIndirect records only
the caller and the argument-buffer address (hle_nvn.c): its x/y/z are zero
at record time by design, and their real values live in the 12 bytes the
buffer holds. The guard therefore silently dropped every indirect compute
dispatch before its arguments were ever read.

Ocarina of Time generates its grass through indirect compute dispatches and
lost its vegetation on the shared layer (ly05010419#2152: good at b0d2f35, bad at
f9f7aa8, the window this guard came in with). With the guard restricted to
direct dispatches the grass is back, verified on a MacBook Pro M4 Pro
(macOS 27.2.1), same save and settings. An indirect dispatch whose argument
buffer holds zeros still runs and does nothing, as it did on Ocarina of
Time's own graphics layer before the merge.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant