Skip to content

fix(agc): route compacted color exports to the slots CB_SHADER_MASK enables - #505

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
oneandonlydean:fix/agc-compacted-color-exports
Oct 5, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
oneandonlydean:fix/agc-compacted-color-exports

Conversation

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Title: fix(agc): route compacted color exports to the slots CB_SHADER_MASK enables

What

The follow-up to #294 that Michon asked for (comment). #294 is merged; this is one commit on current main.

Pixel shader color exports are compacted: export MRTi goes to the i-th MRT slot with a non-zero CB_SHADER_MASK nibble, and field i of SPI_SHADER_COL_FORMAT is the format of export i. main still maps export i to slot i and reads slot i's format field. A shader with CB_SHADER_MASK 0xf000f and SPI_SHADER_COL_FORMAT 0x44 (color to slot 0, velocity to slot 4) is therefore refused with "color export format 0": slot 4's field is 0. That is PPSA21564's glass material (60 shader variants); with those draws skipped, the glass floor and windows show the interior behind them.

  • ColorTarget gets exportIndex next to fix(agc): color targets with gaps between written MRT slots, depth array slices #294's slot. The attachment references, blend states, export mappings, ValidateShaders locations (through blends.size()), and the pipeline and pass keys now use the export index. The color buffer, CB_BLEND control and target mask still come from the slot.
  • An unwritten export below the highest written one stays a VK_ATTACHMENT_UNUSED reference with a disabled blend, as fix(agc): color targets with gaps between written MRT slots, depth array slices #294 does for gaps.
  • The recompiler already takes field i of SPI_SHADER_COL_FORMAT as the format of export MRTi (DecodePixelStageInfo, targetOutputMode[exp.index]). The decode now checks that same field.
  • Without holes in CB_SHADER_MASK, export i is slot i and nothing changes. With holes it does: for CB_SHADER_MASK 0xf0f, export 1 now goes to slot 2, not slot 1.

AMD's RDNA2 ISA guide lists the export targets (MRT0 to MRT7) but not how they map to CB slots. The mapping comes from Mesa (e5f06878):

Tested

  • Linux (CachyOS, x86-64, GCC): full build with BUILD_TESTING=ON and cmake --build build --target libs; ctest passes (183/183).
  • New CompactedExportTests in agc_driver_graphics_tests:
    • the glass state (CB_SHADER_MASK 0xf000f, CB_TARGET_MASK 0x3000f, SPI_SHADER_COL_FORMAT 0x44) decodes to two attachments: export 1 is slot 4's color buffer, with slot 4's blend control, target mask (R and G) and component mapping in ExportMappings()[1];
    • SPI_SHADER_COL_FORMAT 0x90009 (field 1 zero, slot 4's field set) is refused with "color export format 0";
    • CB_SHADER_MASK 0xf0f0f with slot 2 write-masked gives three blend states: export 1 is unused, and export 2 is slot 4.
  • On main (with only the new field added, so the test compiles), the test fails with "AGC graphics: color export format 0 is unsupported".
  • PPSA21564: the same mapping, on my integration branch's older MRT code, has been there since 2026-10-02; with it, the glass floor and windows render. This branch was not run in the title, only the tests above. Michon offered to check it on GTA V.
  • Fork CI (Linux and Windows) passes.

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 in TechnicalDebt
  • 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 (fix(agc): color targets with gaps between written MRT slots, depth array slices #294 is merged)
  • AI-assisted: yes

…nables

Pixel shader color exports are compacted: export MRTi goes to the i-th
MRT slot with a non-zero CB_SHADER_MASK nibble and takes the i-th
SPI_SHADER_COL_FORMAT field. Draws still mapped export i to slot i and
read slot i's format field, so a shader with CB_SHADER_MASK 0xf000f and
SPI_SHADER_COL_FORMAT 0x44 (export 1 to slot 4) was refused with
"color export format 0".

Each color target now carries its export index next to its slot.
Attachment references, blend states, export mappings and the pipeline
and pass keys follow the export index; the color buffer, blend control
and target mask come from the slot. An unwritten export below the
highest written one stays an unused attachment.
@oneandonlydean
oneandonlydean force-pushed the fix/agc-compacted-color-exports branch from 3775b56 to 1c4aadb Compare October 5, 2026 05:08
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 5, 2026
@oneandonlydean
oneandonlydean merged commit c0e8c89 into boykopovar:main Oct 5, 2026
3 checks passed
oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 5, 2026
Takes upstream's merged versions of our boykopovar#586 boykopovar#611 boykopovar#612 boykopovar#505 boykopovar#490 boykopovar#619
boykopovar#503 boykopovar#627 boykopovar#628 boykopovar#618 and drops astrobot's local copies, plus gate-batch-3
(boykopovar#469 boykopovar#500 boykopovar#504 boykopovar#509 boykopovar#510 boykopovar#514 boykopovar#525 boykopovar#526 boykopovar#528), round o/p (boykopovar#617 boykopovar#620
boykopovar#621 boykopovar#622 boykopovar#623 boykopovar#624 boykopovar#501 boykopovar#508 boykopovar#629 boykopovar#630 boykopovar#631).

Conflicts:
- SpirvAnalysis.hpp/.cpp, SpirvBufferAccess.cpp: upstream's boykopovar#586/boykopovar#612.
  The 64-bit LDS atomics keep the full array (f27d6e5 no longer needed).
- SpirvMemoryInstructions.cpp: upstream's constant slot plus offset;
  astrobot's split-wave append/consume kept.
- GuestTextureResource.cpp, TextureTiling.cpp and their tests: upstream's
  boykopovar#490/boykopovar#503 (astrobot had no other change there).
- MaskedSelect.cpp test, ShaderMemory.cpp LDS test: upstream's.
- State.cpp: upstream's boykopovar#505 export count and boykopovar#469 null pixel program;
  astrobot's depth export rejection and depth target model kept.
- Pipeline.cpp: upstream's pipeline key; astrobot's depth attachment and
  blend check (a trailing unused attachment stays valid, as
  colorGapPipelineTests expects).
- Draw.cpp, Recorder.cpp, ShaderResources.cpp: astrobot's (renderPassKey
  with depth, moved sample functions, residency maintenance), which
  already hold the merged boykopovar#505/boykopovar#628/boykopovar#490 changes.
- ShaderInputState.cpp: both register sets.
- State.hpp: the duplicate exportIndex member from the auto-merge removed.
- CMakeLists.txt: astrobot's test list (a superset of upstream's).
- tests/Graphics.cpp: upstream's CompactedExportTests replaces astrobot's
  inline copy; tests/Recorder.cpp: upstream's viewPastLastMipTests added.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant