Skip to content

fix(agc): dump a failing shader capture's own request - #6856

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
milescoviello:fix/dump-failing-capture
Oct 20, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
milescoviello:fix/dump-failing-capture

Conversation

@milescoviello

@milescoviello milescoviello commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What

With APS5_DUMP_SHADERS=1, a dispatch or draw stage whose capture or recompile fails names a request file in its error. Crimson Desert, for example, stops with compute shader 0x2154440100 (shader_2154440100.req): SrtWalker::EvaluateRuntimeSources failed to evaluate runtime sources: descriptor source 2 dword 0: ....

That file is not the failing call's request. shader_<address>.req is written once per shader address, by the first dispatch or draw that captures the shader. So when a later call of the same shader fails, the file holds an earlier call's user data and memory. When the capture itself throws, the failing capture's memory was never part of the dumped request at all. Replaying Crimson Desert's file with agc_shader_replay gives recompiled: 116609 SPIR-V words, so the stop cannot be reproduced from it.

A failure now writes shader_<address>_failed.req, once per address, and names it in the error. It holds the failing call's request together with the memory its capture read (ShaderMemory::Regions(); for a draw stage that fails after its capture, the request's own memory). The dump of a successful capture is unchanged. Registration failures (PrepareShaderWithDiagnostics) are written as shader_<address>.prepare.req since main's 1db31b9, and this PR leaves them alone. It uses that change's name suffix for its own dumps (_failed).

Tested

Ubuntu 24.04, GCC 13.3, RTX 4070 Ti (NVIDIA 595.99).

  • New agc_driver_failed_capture_dump: a compute shader loads its V# through a user-data pointer and stores through it. The first dispatch goes through a valid V#. The second goes through a pointer to a type 2 V# and fails with buffer descriptor uses an unsupported type. The error must name shader_<address>_failed.req; that file must hold the second dispatch's user data and replay to the same refusal, while shader_<address>.req holds the first dispatch's user data and replays cleanly. With main's four sources the test fails 3 of 3, for example with compute shader 0x59360d7c4400 (shader_59360d7c4400.req): buffer descriptor uses an unsupported type (...). With the change it passes 3 of 3.
  • The 502 tests matching ^agc_driver_|^agc_vertex_barrier|recompiler|shader_cache|request_serializer|spirv|^agc_shader|bda|journal|prepared pass except agc_driver_graphics (Linux GCC13.3: agc_driver_graphics reports VOP2 for an all-zero vertex request #6792, fixed by test(agc): keep the vertex terminate case's code in static storage #6789) and agc_driver_store_over_untracked (test(agc): keep waiting for the neighbour copy case's result #6385), which fail on main too.
  • Concurrent runs (found by @Dextroid17): copies of the test running at the same time shared one folder under the temp directory, and 66 of 72 failed when 12 ran at once. 8eb3180 adds a std::random_device value to the folder name. With it, the test passes 3 of 3 alone and 12 of 12 in each of two rounds of 12 at once. @Dextroid17 reran their setup on 8eb3180 (Release, GCC 16.2.1, lavapipe): 72 of 72 pass, against 6 of 72 before (comment).

@LeandroLP23 ran it on Windows 11 with an AMD Radeon 860M (RDNA 3.5, driver 32.0.13058.8001) (comment), in one build of main 6efb726 with this PR and six other pull requests: agc_driver_failed_capture_dump, agc_driver_graphics and agc_driver_store_over_untracked pass 3 runs of 3.

Not checked: macOS, Intel.

  • Rebased onto main 0c25997 (79874b9), onto 1db31b9's suffix-based dumpRequest. The 595 tests matching the regex above pass, except agc_driver_bda_device, which fails on main here too (fix(shader): leave the BDA lookup functions through one return #7571).
  • Khronos validation layer (LunarG SDK 1.4.363), NVIDIA RTX 4070 Ti (595.99.02), Ubuntu 24.04: VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 ctest -R '^agc_' -V on main e2a2914 and on main + this PR (79874b9, a local merge). main: 815 of 815 pass; with this PR: 816 of 816 pass. Neither log reports the layer missing. VUIDs on main: VUID-VkImageViewCreateInfo-usage-02275 ×6, VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 ×18, VUID-vkCmdCopyBuffer-srcBuffer-00118 ×2, VUID-vkCmdDraw-multisampledRenderToSingleSampled-07285 ×2, VUID-vkCmdWaitEvents-srcStageMask-01158 ×2, VUID-vkSetEvent-event-09543 ×2; with this PR: VUID-VkImageViewCreateInfo-usage-02275 ×6, VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 ×18, VUID-vkCmdCopyBuffer-srcBuffer-00118 ×2, VUID-vkCmdDraw-multisampledRenderToSingleSampled-07285 ×2, VUID-vkCmdWaitEvents-srcStageMask-01158 ×2, VUID-vkSetEvent-event-09543 ×2. None is new with this PR.

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 (diagnostics)
  • GPUs tested: NVIDIA GeForce RTX 4070 Ti, driver 595.99, Ubuntu 24.04; AMD Radeon 860M, driver 32.0.13058.8001, Windows 11 (tests, by @LeandroLP23)
  • AI-assisted: yes

🤖 Generated with Claude Code

@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 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5426 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5609 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6146 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6185 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6186 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6539 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 6611 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6682 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6683 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6718 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6820 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6937 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7085 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 7223 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7332 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 7395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7446 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7615 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp
PR 7644 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7677 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7948 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8160 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8161 core/libs/prx/libSceAgcDriver/CMakeLists.txt

@milescoviello

Copy link
Copy Markdown
Contributor Author

Rebased onto main af1e3ae (bb24f2e). The only conflict was in libSceAgcDriver/CMakeLists.txt, where main (#6641) added the agc_driver_shutdown_threads_tests include line next to this PR's agc_driver_failed_capture_dump_tests line. I kept both. No other change.

On Ubuntu 24.04 (GCC 13.3, Release, RTX 4070 Ti), agc_driver_failed_capture_dump passes 3 of 3, and ctest -R '^agc_driver_' passes 498 of 498.

AI-assisted: yes (Claude Code)

@Dextroid17

Copy link
Copy Markdown
Contributor

I ran the new test binary directly (not through ctest), 12 copies at once. It passes when it runs alone, but most copies fail when they run together, because every copy uses the same working folder. A normal ctest run starts this test only once, so this is a small issue (scope below).

Setup: head bb24f2e50 (merge-base with main af1e3ae90), BUILD_TESTING=ON, CMAKE_BUILD_TYPE=Release, Ninja, CachyOS (kernel 7.2.9), i9-11900K, GCC 16.2.1, lavapipe. I started agc_driver_failed_capture_dump_tests under env -i (only HOME, PATH, the lavapipe ICD and its LD_LIBRARY_PATH), and gave each run its own empty ANYPS5_SHADER_CACHE_DIR, MESA_SHADER_CACHE_DIR and XDG_CACHE_HOME.

  • One at a time: 20 of 20 pass.
  • 12 at once, sharing /tmp: 66 of 72 fail. 65 of them end with AGC graphics: shader request shader_<address>.req was not written, and 1 with filesystem error: cannot set current path: No such file or directory. The other 6 pass.
  • 12 at once, each with its own TMPDIR: 36 of 36 pass.
  • 12 at once, sharing /tmp, with getpid() added to the folder name (a local edit, not pushed): 72 of 72 pass.

Cause: main() in tests/execution/FailedCaptureDump.cpp (line 117) uses the fixed path temp_directory_path() / "agc_failed_capture_dump". Each copy runs remove_all and create_directories on that path at the start, moves into it, and runs remove_all on it again at the end. When copies overlap, one deletes the folder another is writing its captures into. In the 65 runs the Read() at line 105 finds no .req file. The one other run fits current_path at line 125 finding the folder already gone, but I inferred that from the message. With their own TMPDIR, or with getpid() in the folder name, the copies do not fail.

If you want to change it, a unique folder name works. Other tests already do this: tests/execution/PipelineJournal.cpp:402, tests/Graphics.cpp:7712 and tests/Recorder.cpp:7432 add std::random_device{}() (from <random>, which this file does not include yet), and tests/Pm4.cpp:1268 adds getpid(). I tested the getpid() version on Linux only. It would need a Windows branch, like the one Pm4.cpp has at line 1262, because this test also builds on Windows. std::random_device works on both.

Scope: ctest registers and starts this test once per run, so a normal ctest -j run will not hit this. It shows up only when two or more copies of this test run at the same time with the same temp folder, for example two build directories tested at once, or two jobs on one shared runner. So it is a small fix, not a blocker.

Not checked: Windows, macOS, a real GPU, PS5 hardware, and a retail title. I did not review the capture and replay code itself. These runs only cover the test's working folder.

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

AI-assisted: yes

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @Dextroid17, that's right. 8eb3180 names the folder agc_failed_capture_dump-<std::random_device value>, as PipelineJournal.cpp does, so it also works on Windows. Run alone, it passes 3 of 3. With 12 copies started at once and sharing /tmp, which is your failing case, 12 of 12 passed in each of two rounds (Ubuntu 24.04, GCC 13.3, Release, RTX 4070 Ti).

AI-assisted: yes (Claude Code)

@Dextroid17

Dextroid17 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Thanks @milescoviello, 8eb318073 fixes it here too. I used the same script and setup as my earlier run (Release, GCC 16.2.1, lavapipe, env -i, separate empty shader caches). With 12 copies started at once sharing /tmp, all 72 of 72 runs now pass. On bb24f2e50, only 6 of 72 passed. So the failure I reported no longer reproduces on Linux with lavapipe. I did not run the Windows build.

AI-assisted: yes

@LeandroLP23

Copy link
Copy Markdown
Contributor

AMD on Windows run. Radeon 860M (RDNA 3.5, driver 32.0.13058.8001), Windows 11 26300, WinLibs GCC 15.2.0 r7, Release, BUILD_TESTING=ON. Build: main 6efb7261b with #7524, #7006, #6612, #6929, #7119, #6896 and #6856 merged together (each merge clean, built once).

agc_driver_failed_capture_dump, agc_driver_graphics and agc_driver_store_over_untracked pass 3 runs of 3. agc_shader_replay is not a ctest name in this build, so I did not run a replay.

AI-assisted

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @LeandroLP23 for the AMD run on Windows. I added it to the description.

AI-assisted: yes (Claude Code)

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
milescoviello and others added 2 commits October 19, 2026 01:09
With APS5_DUMP_SHADERS, a dispatch or draw stage that failed named
shader_<address>.req, which is written once per address by the first call
that captures the shader: a later call's failure pointed at an earlier
call's user data and memory, and a failing capture's memory was never in
the dump. A failure now writes shader_<address>_failed.req with the failing
call's request and the memory its capture read, and names that file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two copies of agc_driver_failed_capture_dump that ran at once shared
temp_directory_path()/agc_failed_capture_dump, and one removed the
folder while the other was writing its captures there. The folder name
now carries a std::random_device value, as the pipeline journal test's
does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milescoviello

Copy link
Copy Markdown
Contributor Author

Rebased onto main 0c25997 (79874b9). In the meantime main took 1db31b9, which names preparation-failure dumps shader_<address>.prepare.req and gives dumpRequest a name suffix, with de-duplication by file name. This PR now uses that API: a failing dispatch or draw capture is dumped with the suffix _failed, so the file is still shader_<address>_failed.req, and its own failed flag and pair-keyed set are gone. The rest is unchanged: the failing call's request together with the memory its capture read, and the new agc_driver_failed_capture_dump test. The 595 tests matching ^agc_driver_|^agc_vertex_barrier|recompiler|shader_cache|request_serializer|spirv|^agc_shader|bda|journal|prepared pass, except agc_driver_bda_device, which fails on main here too (#7571).

AI-assisted: yes (Claude Code)

@milescoviello
milescoviello force-pushed the fix/dump-failing-capture branch from 8eb3180 to 79874b9 Compare October 19, 2026 01:34
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 19, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit 43cd8f4 into boykopovar:main Oct 20, 2026
14 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Re-checked against current main: it merges cleanly, the _failed dump paths in Dispatch.cpp and DrawCapture.cpp still use dumpRequest with the same signature, and the new test still pins both calls' user data and the replayed refusal; merged.

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

Labels

agc libSceAgc* build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants