Skip to content

feat(agc): accept UINT16_ABGR color exports into unsigned integer targets - #1073

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
alfalfa-star:feat/agc-uint16-color-export
Oct 9, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
alfalfa-star:feat/agc-uint16-color-export

Conversation

@alfalfa-star

@alfalfa-star alfalfa-star commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

What

SPI_SHADER_COL_FORMAT 7 (UINT16_ABGR) is accepted when the target's CB_COLOR_INFO number type is UINT. DecodeState rejected it although the recompiler already handles it: an MRT output under mode 7 is a uvec4 (SpirvEmitterHelpers), and a compressed export's 16-bit halves are taken with OpBitFieldUExtract (ExportVector).

  • The target records the export (ColorTarget::uintExport). Shader validation then requires a u32x4 output at its location instead of f32x4.
  • Blending into such a target is refused, since Vulkan has no blending of integer attachments.
  • Format 7 into a target that is not UINT still throws, as does SINT16_ABGR (8), whose halves would need sign extension.
  • A TechnicalDebt line records that a 16-bit value beyond a narrower target's range (R8_UINT) is undefined in Vulkan and the console's behaviour is not confirmed.

Tested

Linux 7.2.9 (Arch), Mesa 26.2.4 RADV, RX 9070 XT.

  • PPSA14632 (LEGO Horizon Adventures) draws into a 2848x1600 R8_UINT target with export format 7. About 290 draws per 3 minutes were dropped; they now record.
  • New execution test agc_driver_pixel_uint16_export draws compressed MRT0 exports under mode 7 into a linear 16_16_16_16 UINT target, one row per pair of packed words (0x0000ffff/0xffff0000, 0x00010002/0xffffffff, the two swapped, and four distinct halves), and reads every 16-bit component back under the identity, STD_REV (0x1b) and ALT_REV (0x93) export mappings. A sixth row stays untouched. It fails if the halves are swapped or the mapping is ignored. agc_driver_graphics covers the decode, the uintExport flag and the blend refusal.
  • ctest: 464 of 464 pass on current main.

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
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#1485 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp L556
#1492 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderValidation.cpp L556
#1735 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp L56
#2169 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp L56
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp L595-596
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp L1092, L2846

@Celegans12

Copy link
Copy Markdown
Contributor

I've had this PR in our Ghost of Yotei (PPSA26344 v1.008) integration tree for two long runs, and it removes the only UINT16_ABGR skips the game hit. Without it, DRAW_INDEX_AUTO draws with export format 7 were skipped about 0.2 times per present from the menus on, 75 times in a 1,500 s run. Most of them went into four colour targets (0x201b871200 and three neighbours, about 15 each), plus 14 others once each.

With this PR at 7487092 on main 0d3c1ee, a 2,700 s run has no color export format 7 is unsupported lines at all, and those targets don't show up in any other error either. A second 2,700 s run that got past the New Game settings had none too. Neither run had a FATAL or a device lost, on Windows 11 with an RTX 3080 Laptop GPU. The branch still merges cleanly onto current main (68010df).

One thing this doesn't tell you: our log names a target only when a draw is skipped, so I can't see which integer format those targets have or what values reached them. The clamp-or-truncate question in your TechnicalDebt line stays open as far as Yotei goes.

Details

Builds:

The skip, from stderr of the run without the PR:

[gpu] skipped draw: AGC graphics: color export format 7 is unsupported [DRAW_INDEX_AUTO, color target 0x201d25e100]
phase (run without the PR) skips per present
boot, 0-680 s 18 0.02
menus, 680-1,092 s 28 0.22
gamma screen, 1,092-1,396 s 20 0.26
world, 1,396-1,600 s 8 0.20

The log has 75 such lines, all DRAW_INDEX_AUTO with format 7 (the per-phase counts cover the presents' windows, 74). By target: 0x201c296300 16, 0x201b871200 15, 0x201bbd2d00 15, 0x201ccbb400 15, and 0x201b750900, 0x201bab2400, 0x201be13f00, 0x201bf34800, 0x201c175a00, 0x201c4d7500, 0x201c5f7e00, 0x201c839000, 0x201c959900, 0x201cb9ab00, 0x201cefc600, 0x201d01cf00, 0x201d25e100 and 0x201d37ea00 once each.

With the PR: 0 lines in the cold 2,700 s run (1,115 presents) and 0 in the warm one, and none of the four main targets appears anywhere in the cold run's 526 MB stdout or its stderr.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the decode/validation side looks right: the NUMBER_TYPE check matches the recompiler's existing mode 7 handling, blending is refused, and the TechnicalDebt line is in the right section. ctest passes locally (416/416) and CI is green.

One thing to fix:

  • tests/PixelUint16Export.cpp:15-26: the test counts SPIR-V opcodes (OpBitFieldUExtract, half unpacks), so it pins the IR shape, not the result. A different but correct lowering would fail it, and a wrong extraction (swapped halves, wrong shift) with four extracts would pass. Please run the shader and compare values, as the other execution tests do: export packed words with edge rows (0x0000ffff, 0xffff0000, 0x00010002, 0xffffffff) and check each 16-bit half arrives as the expected uvec4 component, including the targetExportMapping swizzle. Keep the mode 4 case for contrast if you like.

…gets

SPI_SHADER_COL_FORMAT 7 (UINT16_ABGR) was rejected by DecodeState,
though the recompiler already handles it: a pixel shader's MRT output
under mode 7 is a uvec4, and a compressed export's 16-bit halves are
taken with OpBitFieldUExtract. The format is now accepted when the
target's CB_COLOR_INFO number type is UINT; into any other target it
still throws, as does SINT16_ABGR (8), whose halves would need sign
extension.

The target records the export (ColorTarget::uintExport). Shader
validation then requires a uint4 output at its location instead of a
float4 one, and blending into it is refused (Vulkan has no blending of
integer attachments).

PPSA14632 (LEGO Horizon Adventures) writes a 2848x1600 R8_UINT target
this way; those draws were dropped.

agc_driver_pixel_uint16_export draws compressed MRT0 exports under mode
7 into a linear 16_16_16_16 UINT target, one row per pair of packed
words (0x0000ffff/0xffff0000, 0x00010002/0xffffffff and four distinct
halves), and reads every 16-bit component back under the identity,
STD_REV and ALT_REV export mappings. agc_driver_graphics covers the
decode and the blend refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alfalfa-star
alfalfa-star force-pushed the feat/agc-uint16-color-export branch from 7487092 to 4554135 Compare October 8, 2026 16:52
@alfalfa-star

Copy link
Copy Markdown
Contributor Author

@adriadam10 Done in 4554135, rebased onto current main. The opcode-count test is gone. agc_driver_pixel_uint16_export is an execution test now: it draws compressed mode 7 exports into a linear 16_16_16_16 UINT target and reads every 16-bit component back. Each scissored row exports one pair of packed words: the edge rows you listed (0x0000ffff/0xffff0000, 0x00010002/0xffffffff, and the same pairs swapped), plus one row with four distinct halves, so any component swap shows. It runs under the identity, STD_REV (0x1b) and ALT_REV (0x93) targetExportMappings. I checked that it catches both failure modes: with the halves swapped in ExportVector it fails on row 0, and with the mapping shuffle skipped it fails under STD_REV. I left out the mode 4 case. ctest: 464/464 on RADV (RX 9070 XT).

@XairRrR

XairRrR commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Uncharted: Legacy of Thieves Collection (PPSA05684) stops at this on main:

AGC graphics: color export format 7 is unsupported

I made the same change independently (format 7 into UINT targets only, uvec4 outputs, no blending) while bringing the title up to its main menu, so I'm not opening a competing PR. I have not run this branch itself with the title.

@johnmaia johnmaia mentioned this pull request Oct 9, 2026
9 tasks done
@alfalfa-star

Copy link
Copy Markdown
Contributor Author

@adriadam10 Could you take another look? The opcode-count test is replaced by the execution test you asked for (4554135, details above). CI is green and it still merges cleanly onto main.

@XairRrR Thanks for the Uncharted report.

@adriadam10 adriadam10 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the decode/validation change against the recompiler's mode 7 handling, ran the new agc_driver_pixel_uint16_export execution test (all three export mappings) plus agc_driver_graphics, full ctest green on top of current main; the test does not build without the change. Merging.

Nit for later: the new TechnicalDebt line lacks a final period.

@adriadam10
adriadam10 merged commit 2d537f1 into boykopovar:main Oct 9, 2026
8 checks passed
@alfalfa-star
alfalfa-star deleted the feat/agc-uint16-color-export branch October 10, 2026 07:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants