TOTK notes: the opening cave's stone blocks get no torch light; what is ruled out, and the layout bug MacNativeGames found

The blocks keep their texture and ambient light but stay black beside the torch (Mac and iPhone; lit on the Switch). Drawn by 54e8c08998050e79, they write roughness 0 into colour target 3, sampled from a 5120x5120 BC4 atlas that nothing tracked ever writes; filling it by hand did not light them, so that is not the cause. Still open: the torch's shadow map, the light volumes' half-resolution depth test, the normal map.

MacNativeGames (a TOTK port on an older copy of this replay layer, MIT) reports that NVN truncates height_in_blocks * 1.5 / 8 when choosing the automatic block height, where nvn_tex.c rounds up: textures of some sizes are read with the wrong layout. The fix touches every game and waits for a check across the profiles. Fast loop and session patch location recorded.
This commit is contained in:
seedds committed 2026-10-19 11:13:33 +08:00
1 parent abb8226c62
commit 7f9c16bc93
1 file changed
+5
+5
View File
@@ -171,6 +171,11 @@ So the translator leaves z alone (`QueryGraphicsState` depth mode false in `Prog
- **How the tile lighting was traced**: the G-buffer class byte selects per-class half-resolution passes through a depth buffer of class values (`gl_FragDepth = mix(0.5, 1, nibble-swapped class / 255)`, then full-screen or per-tile quads with depth `EQUAL`), so `DM_NVN_DEPTHOVR` (depth test forced to `ALWAYS`) with `HILITE` tells "rejected by depth" from "never rasterized". `TEXSNAP` copies used to run before the pass they were meant to show (classic-queue command buffer committed ahead of the Metal 4 one); they now go through the replay's copy encoder.
- **Clears inside a pass, with a partial channel mask or with a partial scissor** were dropped (red 「通道中途 / 部分掩码 / 部分剪裁的清色未实现」, 「通道中途的剪裁深度模板清除未实现」). NVN clears obey the scissor and the clear's own channel or stencil write mask, and can come between draws, while a Metal load action clears a whole attachment at the start of a pass. Such clears are now drawn as one triangle over the pass in the open render encoder (`clear_color_tri` / `clear_ds_tri` in `nvn_mtl.m`, adapted from MacNativeGames, MIT). The pipeline has the pass's formats, the clear's mask as the write mask of its slot and no writes to the other slots. Depth is `ALWAYS` (and written for a depth clear), stencil `REPLACE` through the clear's write mask, the scissor is clamped as for draws, and visibility counting is off for the triangle. The value comes from the frame arena through the triangle's own argument tables, and the draws' tables are put back after it. A clear outside a pass opens the pass as a draw would. Clears a load action can express keep it, and two cases are still cleared whole, logged once as 「深度模板清除带剪裁或部分模板掩码,按整张清」: a depth / stencil clear with a scissor outside a pass, and a partial stencil write mask. TOTK issues the first (a depth clear scissored to 8×8 of a 64×64 target), and so does Wonder. With `render_cond` TOTK's scissored colour clears are all skipped; without it they are 50×50 tiles of a 500×400 target cleared to opaque black, about five a frame. Metroid Dread logged the red line once while loading on its smoke route.
- **8-bit indices written earlier in the same submission** were read stale (red 「8 位索引缓冲本提交里有 GPU 侧写入:按当前内容展开」). Metal has no 8-bit index type, so replay widens 8-bit indices to 16-bit on the CPU. When a copy, update or fill encoded earlier in the submission covers them (`pend_hits`), the CPU reads the bytes from before that write. Those draws are now widened on the GPU (`wide_run`): a compute pass reads the indices from a 16-byte-aligned address, with the byte shift as a constant, and writes 16-bit ones into the frame arena. As in `ixc_run`, the first such draw widens every such draw after it up to the next buffer write outside a render pass, so only a draw met inside an open render pass with no widening yet would split it. In TOTK about one draw per widening, up to a dozen widenings a frame on the title and load screens, no pass split (log line `8 位索引 GPU 展开`). Draws whose indices no write covers keep the CPU widening.
- **Open: the stone blocks and steps of the opening cave get no torch light (Mac and iPhone).** On the Switch they are grey stone lit warm on the side facing Zelda's torch; here they keep their stone texture and the ambient light but stay black beside the torch, while the cave walls next to them are lit. Fast loop: the in-cave autosave (`run/save` in the work folder, keys `f2500:A,f2800:A,f3100:A,f3600:A`, shot at frame 4500 with the torch on its stand right of Link; the scene timing varies, check the flame is in the shot). `DM_DETCLOCK` cannot be used: TOTK stops at frame 1, waiting for guest time that only moves on presents. What is known so far (2026-10-19):
- The blocks are drawn by fragment shader `54e8c08998050e79` (two draws in the terrain G-buffer pass). Colour target 3 holds the normal in red and green and, in blue, the normal's sign bits plus a roughness term (`(blue & 252) / 252`, read by the tile-light shaders such as `c23ef1f842fcfba5` in the pass that adds point lights into the RG11B10 light buffer). The blocks write roughness 0 there: they sample it from a 5120×5120 BC4 atlas (texture slot 25, `ser=86` in that run) that is all zero, unless bit 25 of their material uniform `c7[8].y` is set, which it is not.
- Nothing tracked writes that atlas: its guest memory holds 6 non-zero bytes, no copy, render target, image or texture over the same memory touches it. Filling it by hand (BC4 value 200) did not light the blocks, so the zero roughness is not the cause.
- Not yet ruled out: the torch's shadow map (casters such as the blocks fully in their own shadow), the light volumes' half-resolution depth test, and the blocks' normal map. MacNativeGames (github.com/ly05010419/MacNativeGames, MIT), a TOTK port built on an older copy of this replay layer, reports a texture-layout bug that is also ours: NVN chooses the automatic block height by truncating `height_in_blocks * 1.5 / 8`, while `nvn_tex.c` rounds the division up, so some sizes (a 160×160 BC3 texture: H3 instead of H2) are read with the wrong layout and show padding as black texels. The fix (`pick_tile(ah * 3 / 16)`) changes every game's layouts at those sizes and waits for a check across the profiles. The same project renders into BC textures through a block-sized auxiliary texture (here those draws are dropped: red 「渲染目标是压缩格式贴图」, a 32×32 BC4 target in TOTK) and gives compressible storage to the newest format when a texture of another format takes it.
- The diagnostic patch of this session (tagged `[DEBUG-c4]` logging, a later-write poll for `tex_dirty_upload`, a CPU-side read-back for CPU-written textures, the block-height change) is kept outside the repository in `_agent/power/totk_blocks_wip.patch` on the T7.
## 7. Diagnostic switches (host)