Skip to content

fix(agc): run draws whose pixel stage cannot run without its program - #1139

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
alfalfa-star:fix/agc-inert-pixel-stage
Oct 8, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
alfalfa-star:fix/agc-inert-pixel-stage

Conversation

@alfalfa-star

Copy link
Copy Markdown
Contributor

What

A draw whose pixel stage the hardware would not run no longer fails with missing register at DWORD 0x1b3. Before, a draw went without a pixel program only when SPI_SHADER_PGM_LO/HI_PS were zero. A depth-only pass can instead leave a stale pixel program address from earlier state and never set the pixel registers it doesn't need (SPI_PS_INPUT_ENA/ADDR, SPI_SHADER_COL_FORMAT).

The pixel shader has no effect and is not launched when all of these hold:

  • no color is written (CB_TARGET_MASK & CB_SHADER_MASK == 0);
  • there is no depth, stencil or mask export (SPI_SHADER_Z_FORMAT 0, and the export enables of DB_SHADER_CONTROL clear);
  • KILL_ENABLE, EXEC_ON_HIER_FAIL, EXEC_ON_NOOP and EXEC_IF_OVERLAPPED are all clear. radeonsi sets EXEC_ON_NOOP exactly when a pixel shader writes memory.

Changes:

  • PixelProgramUnset becomes PixelProgramSkipped. It is true for a zero program address, as before, and also for such an inert pixel stage. A register the rule needs that is absent means "not skipped", which keeps today's behavior.
  • DrawRejection and the draw decode both use it, so a skipped stage takes the driver's null pixel program, as a zero address already did, and the precheck and the decode agree.

Tested

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

  • PPSA14632 (LEGO Horizon Adventures) issues an HTILE expand this way once per run. The pass is marked "Decompress Htile" and sets DB_RENDER_CONTROL DEPTH/STENCIL_COMPRESS_DISABLE, CB disabled, depth test and writes off, DB_SHADER_CONTROL 0, and a stale PS address. With this change it draws, and a 180 s run had no skipped draws (on top of fix(agc): bind a null index buffer to non-indexed mesh draws #1134).
  • agc_driver_graphics: a stale address with nothing written and nothing exported is skipped and passes the precheck. EXEC_ON_NOOP, KILL_ENABLE, a Z export, a Z format or a color write each keep the program, and the first two still need SPI_PS_INPUT_ENA. The existing zero-address and missing-register cases are unchanged.
  • ctest: 396 of 396 pass.

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

A depth-only pass can leave a stale pixel program address in
SPI_SHADER_PGM_LO/HI_PS while never setting the pixel registers it does
not need. The draw then failed with "missing register at DWORD 0x1b3"
(SPI_PS_INPUT_ENA), although the hardware never launches that program:
with no color written (CB_TARGET_MASK & CB_SHADER_MASK == 0), no depth,
stencil or mask export (SPI_SHADER_Z_FORMAT 0 and those enables of
DB_SHADER_CONTROL clear), and neither KILL_ENABLE, EXEC_ON_HIER_FAIL,
EXEC_ON_NOOP nor EXEC_IF_OVERLAPPED set, the pixel shader has no effect
and is not executed.

PixelProgramUnset becomes PixelProgramSkipped: true for a zero program
address as before, and for such an inert pixel stage. Both use the
driver's null pixel program; the precheck and the decode agree.

PPSA14632 (LEGO Horizon Adventures) issues an HTILE expand this way
(DB_RENDER_CONTROL DEPTH/STENCIL_COMPRESS_DISABLE, CB disabled, depth
test and writes off) once per run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@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
#1348 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp L222

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked build + ctest (424/424, agc_driver_graphics passes), CI green on the head. The new test cases pin skipped vs. kept for EXEC_ON_NOOP, KILL_ENABLE, Z export, Z format and color write, and unsupported DB_SHADER_CONTROL bits are still rejected (State.cpp:792). Merging.

@adriadam10
adriadam10 merged commit e705d43 into boykopovar:main Oct 8, 2026
3 checks passed
@alfalfa-star
alfalfa-star deleted the fix/agc-inert-pixel-stage branch October 8, 2026 16:33
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.

2 participants