Skip to content

fix(shader): read the ancillary render target index as 0 - #4842

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
LeandroLP23:fix/agc-ancillary-layer-unwritten
Oct 13, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
LeandroLP23:fix/agc-ancillary-layer-unwritten

Conversation

@LeandroLP23

Copy link
Copy Markdown
Contributor

What

Fixes #4800.

The packed pixel ancillary lowering now uses the constant 0 for the render target index field (bits 16+) instead of reading the Layer builtin.

Why 0 is right. No pre-rasterization stage writes Layer today:

  • State.cpp ignores the vertex layer and viewport exports of PA_CL_VS_OUT_CNTL.
  • The vertex request's paClVsOutCntl is never set, so no Layer output is emitted.

When the last pre-rasterization stage has no Layer output, Vulkan uses the first layer (Layer). So the value the field stood for is 0.

Why reading Layer is wrong here. On AMD's Windows driver, a fragment shader that consumes the unwritten Layer loses its colour writes, even when the value never reaches the output. lavapipe returns 0, so CI didn't see it.

#4800 has the module dumps and the edited-module runs that isolate this:

  • gl_SampleID replaced by 0: still loses the writes.
  • gl_Layer replaced by 0: writes land.
  • gl_Layer loaded but unused: writes land.

The shader.md debt entry for the packed ancillary word now says where the 0 comes from. #423 and #1077 (@alfalfa-star) make layered draws export Layer through PA_CL_VS_OUT_CNTL. Once they land, those draws need the real value: read Layer when the draw exports it, and 0 otherwise, which is the case this change covers. Nothing on main exports it yet, so I left that condition out.

Tested

Windows 11 (26300), AMD Radeon 860M (RDNA 3.5, driver 32.0.13058.8001), WinLibs GCC 15.2.0, Release, BUILD_TESTING=ON, on main 43e3a70f8:

  • agc_driver_relative_ancillary: failed on main on this GPU; passes 3/3 with this change.
  • pixel_ancillary: 3/3. It now requires the render target index field to be 0 for rows whose layer is not 0.
  • ctest -R '^agc_' -j 1 (shader cache emptied): 445/445.
  • ctest -E '^agc_' -j 4: 574/574.
  • Revert check: with main's ConstantFolder.cpp, pixel_ancillary and agc_driver_relative_ancillary both fail.
  • Six homebrew titles run 60 s with no stop, as on main: Stremio Plus, Capy Mobile, DriftCheck, EVO Player, DOOM and OpenRCT2.
  • Fork CI (run): Linux 1001/1002, Windows 1018/1019, relinker 142/143, 133/134 and 137/138. The one failure in each job is conventions_ci_gate, because my fork runs the old build.yml without file filters, which main's checker rejects. It is not this change.
  • tools/check_conventions.py --base origin/main and git diff --check pass.

Not run on Linux locally. No title on hand reads the ancillary layer field; that is #2548's set: Stray, Kena, Lies of P and others.

Overlap. #4031 (@AlxcBTW) also changes lowerPackedAncillary and PixelAncillary.cpp: it adds the primitive class field. The two don't depend on each other. Whichever merges second has to take this into account:

I merged #4031's head dd8403112 onto this branch locally and applied the same 0 at that read. Its new agc_driver_pixel_ancillary_word then passes on this AMD GPU, 3/3, where it failed on #4031 alone, and so does agc_driver_relative_ancillary. pixel_ancillary needs that merge reconciled. If #4031 goes in first, I'll rebase this one and do it.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none
  • AI-assisted: yes (Claude Code)

No pre-rasterization stage writes Layer: vertex layer exports are
ignored, so the first layer is used and the render target index field
of the packed ancillary word is 0. The lowering read the Layer builtin
for it instead. AMD's Windows driver drops the color writes of a
fragment shader that consumes an unwritten Layer, which made
agc_driver_relative_ancillary fail on AMD hardware (boykopovar#4800); lavapipe
returns 0 there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@oneandonlydean
oneandonlydean force-pushed the fix/agc-ancillary-layer-unwritten branch from 6f3f3fa to 3334e41 Compare October 13, 2026 00:59
@oneandonlydean oneandonlydean self-assigned this Oct 13, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

#4031 is merged, so I rebased this onto it and pushed (3334e41, your commit and message kept). The ConstantFolder.cpp change is the same: the render target index field is a constant 0, and the helper #4031 added now takes SampleId only. The debt entry in docs/dev/debt/shader.md is merged with the one #4031 added. Full build is running; agc_driver_relative_ancillary on AMD is the part we can't run here.

@LeandroLP23

Copy link
Copy Markdown
Contributor Author

Confirmed on AMD after the merge: main 88107b7de (with #4031 and this), Windows 11, Radeon 860M (driver 32.0.13058.8001), Release. agc_driver_relative_ancillary, agc_driver_pixel_ancillary_word and pixel_ancillary pass 3/3, and ctest -R '^agc_' -j 1 is 460/460. Thanks for carrying it over #4031.

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.

AMD Windows: draws whose pixel shader reads the packed ancillary VGPR leave pixels unwritten (agc_driver_relative_ancillary fails on main)

2 participants