Skip to content

fix(agc): resolve a relocated AGC header whose arrays hold the registered bytes - #6966

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
ebosido444-ai:fix/agc-relocated-header
Oct 19, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
ebosido444-ai:fix/agc-relocated-header

Conversation

@ebosido444-ai

@ebosido444-ai ebosido444-ai commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What

A title can relocate a registered Shader header — and the register, special and semantic arrays it points at — into memory of its own, then resolve the ABI with that copy, which it never registered (ResolveShaderAbi, ResolveGraphicsStagesAbi, ResolveGraphicsAbi). SameHeader accepted such a copy only while its pointers stayed put: RelocatedRegisters covers a moved register array alone, and the fixed-field comparison covers the case where only user_data moved. Once another referenced array moved with the header, RegisteredHeader matched nothing and the resolution threw graphics ABI refers to a replaced shader header. Astro's Playroom (PPSA01325) resolves its vertex ABI with such a copy (#2914, discussion #3232).

A copy is now accepted when every array it names still holds the registered bytes. The registered header then decodes exactly what the copy describes, so nothing is copied, no snapshot is published and ShaderSnapshot stays immutable.

What a copy's pointers cannot change is content, and that is what the check now compares:

  • the fixed fields, with user_data not compared and the register, context-register, specials, input-semantic and output-semantic pointers masked;
  • every array those pointers name, through its guest bytes, against the registered header's bytes at the registered pointer (unreadable arrays refuse).

A copy whose registers, context registers, specials or semantics differ, or whose fixed fields differ, still throws ... refers to a replaced shader header — exact-or-throw is unchanged.

Not the earlier attempts

#2969, #4043 and #5830 published or mutated a snapshot for the relocated header. This keeps the registry, the snapshot and its decoded program untouched: the acceptance test reads guest memory only, so a relocated call costs a bounded comparison and no allocation. There is no new snapshot, no PublishRegisteredShader call and no mutable member.

Tested

Windows 11 26200.8117, winlibs GCC 15.2.0, Ninja, Release. GPU: NVIDIA GeForce GTX 1650 Ti, driver 617.14 (Vulkan).

tests/execution/PreparedShaders.cpp gains RelocatedHeaders(), called from the default run beside SharedCodeHeaders():

  • registers a vertex header, then resolves the ABI with a full copy of that header whose every embedded pointer points into the copy, and submits that draw;
  • resolves with a copy that moves only its user_data pointer;
  • requires three copies — one register patched, one special patched, one context register patched — to still throw replaced shader header.

On unmodified main (e9a3343) the same test fails at the first copy:

AGC driver: graphics ABI refers to a replaced shader header

With this change:

cmake --build build --parallel 8 --target agc_driver_prepared_shaders_tests
ctest --test-dir build -R ^agc_driver_prepared_shaders --output-on-failure
100% tests passed, 0 tests failed out of 11

The 11 modes are the default, indirect, uncached, debug, debug_failure, deferred, deferred_undecodable, registered_workgroup, registered_workgroup_sync, lazy and lazy_sync runs of the same binary; SharedCodeHeaders and Registration cases are inside them.

Checklist

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4448 docs/dev/debt/libSceAgcDriver.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5115 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp
PR 5431 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 5499 docs/dev/debt/libSceAgcDriver.md
PR 5925 docs/dev/debt/libSceAgcDriver.md
PR 6146 docs/dev/debt/libSceAgcDriver.md
PR 6188 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 6194 docs/dev/debt/libSceAgcDriver.md
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6252 docs/dev/debt/libSceAgcDriver.md
PR 6280 docs/dev/debt/libSceAgcDriver.md
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6457 docs/dev/debt/libSceAgcDriver.md
PR 6548 docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6588 docs/dev/debt/libSceAgcDriver.md
PR 6612 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6636 docs/dev/debt/libSceAgcDriver.md
PR 6679 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
PR 6683 docs/dev/debt/libSceAgcDriver.md
PR 6727 docs/dev/debt/libSceAgcDriver.md
PR 6808 docs/dev/debt/libSceAgcDriver.md
PR 6867 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
core/libs/prx/libSceAgcDriver/tests/execution/PreparedShaders.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6868 docs/dev/debt/libSceAgcDriver.md
PR 6887 docs/dev/debt/libSceAgcDriver.md
PR 6941 docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6965 docs/dev/debt/libSceAgcDriver.md
PR 6973 docs/dev/debt/libSceAgcDriver.md
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6987 docs/dev/debt/libSceAgcDriver.md
PR 6989 docs/dev/debt/libSceAgcDriver.md
PR 6995 docs/dev/debt/libSceAgcDriver.md
PR 7002 docs/dev/debt/libSceAgcDriver.md
PR 7085 docs/dev/debt/libSceAgcDriver.md
PR 7256 docs/dev/debt/libSceAgcDriver.md
PR 7332 docs/dev/debt/libSceAgcDriver.md
PR 7446 docs/dev/debt/libSceAgcDriver.md
PR 7449 docs/dev/debt/libSceAgcDriver.md
PR 7505 docs/dev/debt/libSceAgcDriver.md
PR 7604 docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Shaders/ShaderRegistry.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7659 docs/dev/debt/libSceAgcDriver.md
PR 7683 docs/dev/debt/libSceAgcDriver.md
PR 7800 docs/dev/debt/libSceAgcDriver.md
PR 7844 docs/dev/debt/libSceAgcDriver.md
PR 7912 docs/dev/debt/libSceAgcDriver.md

@keravyn-ops

Copy link
Copy Markdown
Contributor

AMD / Windows run of this PR at fb07b68: Radeon 780M (RDNA 3, 0x15bf), AMD driver 25.10.20.01 (32.0.21020.1007), Windows 11 Home 10.0.26100, WinLibs GCC 15.2.0 r7, Release.

Every ctest entry built from the test targets this PR changes passes (11):

  • agc_driver_prepared_shaders (1.01 s): 591: prepared shader and transactional registration tests passed
  • agc_driver_prepared_shaders_indirect (0.80 s): 784: prepared shader and transactional registration tests passed
  • agc_driver_prepared_shaders_uncached (0.80 s): 785: prepared shader and transactional registration tests passed
  • agc_driver_prepared_shaders_debug (0.80 s): 786: prepared shader and transactional registration tests passed
  • agc_driver_prepared_shaders_debug_failure (0.81 s): 787: injected failure before registration
  • agc_driver_prepared_shaders_deferred (0.20 s): 788: deferred shader preparation tests passed
  • agc_driver_prepared_shaders_deferred_undecodable (0.19 s): 789: deferred undecodable shader tests passed
  • agc_driver_prepared_shaders_registered_workgroup (0.19 s): 790: registered NGG preparation deferral passed; subgroup=64
  • agc_driver_prepared_shaders_registered_workgroup_sync (0.18 s): 791: registered NGG preparation deferral passed; subgroup=64
  • agc_driver_prepared_shaders_lazy (0.35 s): 792: lazy shader preparation tests passed
  • agc_driver_prepared_shaders_lazy_sync (0.21 s): 793: lazy shader preparation tests passed

AI-assisted: yes (runs made on the device above).

@github-actions github-actions Bot added unblocks title Names a title ID on the Unblocks line needs rebase Conflicts with main, rebase needed labels Oct 18, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
…ered bytes

A title can relocate a registered shader header, and the register, special and
semantic arrays it points at, into memory of its own and resolve the ABI with
that copy (Astro's Playroom, PPSA01325, boykopovar#2914). SameHeader accepted such a copy
only while every pointer inside it stayed put, so a moved array left the
resolution throwing "refers to a replaced shader header".

Accept the copy when every array it names still holds the registered bytes: the
registered header then decodes what the copy describes, nothing is copied and
ShaderSnapshot stays immutable. A copy whose arrays differ or are unreadable
still throws.
@adriadam10
adriadam10 force-pushed the fix/agc-relocated-header branch from fb07b68 to 943b700 Compare October 19, 2026 12:45
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 19, 2026
@adriadam10
adriadam10 merged commit 88a6b34 into boykopovar:main Oct 19, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the diff (array bounds in ReferredBytesMatch, unreadable arrays refuse, exact-or-throw unchanged), that the new test pins the relocated-copy case and the three patched copies still throw, and the Debt entry. Rebased onto current main (only a test-function adjacency conflict in PreparedShaders.cpp); the agc prepared-shader tests pass on the rebase, and keravyn-ops' AMD/Windows run covers the same targets. merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants