Repository navigation
A clear covers every layer of the bound render target view (Little Nightmares point-light shadows) - #808
A clear covers every layer of the bound render target view (Little Nightmares point-light shadows)#808keanu-stitch8 wants to merge 2 commits into
Conversation
texraw saved slice 0 only, so a cube, array or layered render target could be checked only through its first face or layer. It now saves level 0 of every slice one after another (a cube's six faces), with the slice count after the header's four fields when there is more than one. A single-slice texture's file is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
NVN clears every layer of the render target view that is bound (the whole texture when the view sets no layer range). A clear folded into a Metal pass's load action clears only the layers the pass attaches, and a pass that is not layered attaches one, so the other layers of an array, cube or 3D target kept their old or zero content. Little Nightmares (01002FC00412C000, Unreal Engine 4) clears the 512x512 cube of each point light's one-pass shadow (geometry shader ffc21034b958840b) in the pass that captures the vertex shader's output, which is not layered. Only the +X face was cleared; faces 1-5 kept the zero depth they were created with, every fragment the layered pass drew there failed the depth test, and the comparison sampler read them as fully shadowed: the lantern and the lighter lit only one side of the room, with straight edges. rp_begin_ex_ now clears such an attachment in a pass of its own with renderTargetArrayLength set to the view's layers (att_layers), then loads it in the real pass, as it already did for attachments larger than the pass. A view limited to some layers clears only those; layered passes and single-layer targets are unchanged. t_clear_layers runs the production replay on a cube depth target and a 2D array colour target, with and without layer ranges (4 of its 6 cases fail without the fix). Checked on the Mac: Little Nightmares' shadow cube holds depth on all six faces after the fix (texraw), and the lantern room is lit all around with Six's shadow on the floor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cb3e314 to
abbfb62
Compare
NVN clears all layers of the bound render-target view. A load-action clear in a non-layered Metal pass covered only its first layer, leaving the remaining shadow-cube faces and array layers unchanged. Extend the existing standalone clear pass to cover the view's full layer range before loading it in the draw pass. Extend texraw diagnostics to save every array slice and cube face, and test the production replay. Integrate with #730 by marking a raster clear only when the draw pass's actual load action clears. A clear already completed in a standalone pass must not keep a stale tile store over later shader image writes. The literal GPU regression fails four checks without this tracking fix. Before rebasing, the full Metal graphics suite, LLVM 23 lint, all 11 documentation tests and Breath of the Wild's full outdoors route passed. Those comparisons used the documented Xcode 27.2 compiler override on both revisions against the old compiler lock. After rebasing onto the Xcode 27.2 pin and #730, focused lint and documentation checks pass, as do 120 image-store checks and 30 layered-clear checks under Metal validation. The maintainer stopped the remaining Tears of the Kingdom and Pokemon Scarlet regression runs; document that partial coverage. Co-authored-by: Riski Aditiawarman <62930684+keanu-stitch8@users.noreply.github.com>
|
Landed on main as ffdf67de. Thank you, @keanu-stitch8, for the diagnosis, implementation and GPU coverage. Your clear implementation, texraw improvement and tests are retained, and you are credited as co-author. This is good general graphics design: NVN clears the complete bound view, so the Metal load-action path must cover that view. High confidence in the original bug and fix; this is a generalized root-cause correction with no game-specific rule or renderer workaround. The rebase onto #730 exposed one integration issue. A clear already completed in a standalone pass was still counted as a tile write in the following pass, retaining a stale store over shader image writes. Store tracking now uses the following pass's actual clear load action. The added literal GPU case failed four assertions before the correction and passes afterward. Validation:
Closing after landing the reviewed change on main. |
What
NVN clears every layer of the render target view that is bound (the whole texture when the view sets no layer range). The host folds a clear into the next Metal pass's load action, and a pass that is not layered (
renderTargetArrayLengthunset) clears only its one attached layer. Layers above the first of an array, cube or 3D target kept their old or zero content.rp_begin_ex_already clears an attachment that is larger than the pass in a pass of its own (Clears of attachments larger than the render pass, Bayonetta 2). This PR does the same for layers. A cleared attachment whose view covers more than one layer, in a pass that is not layered, is cleared in a pass of its own withrenderTargetArrayLengthset to the view's layers (att_layers), then loaded in the real pass. A view limited to some layers clears only those. Layered passes and single-layer targets are unchanged.Found on
Little Nightmares (
01002FC00412C000, 1.0.4, Unreal Engine 4, SDK 3.5.1, provisional profile):ffc21034b958840b, emitting every triangle into six faces) clears the 512x512 D32F_S8 cube in the pass that captures the vertex shader's output. That pass is not layered.tex_zero_fillgives a new texture, so every fragment of the layered pass failed the depth test there.Diagnostics (first commit)
DM_CTL
texrawsaved slice 0 only, which hid the bug (face 0 looked plausible). It now saves level 0 of every slice, one after another, with the slice count after the header's four fields when there is more than one. A single-slice file is unchanged.Tests
t_clear_layers(production replay,MTL_DEBUG_LAYER=1) covers:make -C dm/gfx/tests GAME=010015100B514000 run: all pass (on the fork's tree, which carries this change).t_clear_ds,t_clear_tex,t_clear_layersanddm/tools/tests/test_docs.pypass on this branch.scripts/regress.py check --gameswas not run. This Mac has no NSP folders laid out for the harness (<name> [<id>]with<id>_build) for the other local games. The change only acts when a cleared attachment has more than one layer in a pass that is not layered, and the pass dump printsC … cleared in a pass of its own (… N layers …)whenever it does.🤖 Generated with Claude Code