Skip to content

feat(agc): run DB depth copies into a single-sample R32 float target - #8975

Merged
oneandonlydean merged 5 commits into
boykopovar:mainfrom
milescoviello:rebase/5499-db-depth-copy
Oct 21, 2026
Merged

oneandonlydean merged 5 commits into
boykopovar:mainfrom
milescoviello:rebase/5499-db-depth-copy

Conversation

@milescoviello

@milescoviello milescoviello commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

This carries #5499 by @codingreapermaps, rebased onto current main, with a fix for one-sample depth surfaces and the review fixes below on top. Their commit keeps its authorship. @oneandonlydean offered this route on #5499: a new PR crediting them, with #5499 closed in its favour.

The change (codingreapermaps's commit, 191c8a8d2b). A draw with DB_RENDER_CONTROL.DEPTH_COPY threw DB_RENDER_CONTROL depth copy, resummarize or decompress is unsupported. PPSA12361 (Transport Fever 2) issues one in every frame of a map: DB_RENDER_CONTROL = 0x84 (DEPTH_COPY with COPY_CENTROID), a two-sample Z_32_FLOAT depth surface and a single-sample R32 float color target of the same size, which its ambient occlusion pass samples next.

  • DecodeDepthCopyPass recognises the draw before shader compilation. It accepts only:

    • a depth copy (no stencil copy, clear, resummarize or decompress);
    • no depth or stencil tests;
    • a Z_32_FLOAT depth plane;
    • color writes to the red channel of color target 0 alone;
    • a single-sample R32 float target of the depth surface's extent;
    • the full PA_SC_AA_MASK;
    • a viewport and scissor covering the whole surface.

    Anything else throws, and draws without DEPTH_COPY are unchanged.

  • The copy runs as a compute pass (DepthSample.comp). It fetches one sample of the host depth image and stores it into the target's resident storage image, which is then marked dirty like any other GPU write.

  • With COPY_CENTROID, the copied sample is the first one the draw covers. radeonsi programs its DB-to-CB copies with COPY_CENTROID and a one-sample mask per sample; under the full sample mask required here, that is sample 0. Without COPY_CENTROID, COPY_SAMPLE selects it. The console is not measured; docs/dev/debt/libSceAgcDriver.md records this.

Rebase. CMakeLists.txt, TextureDetiler.hpp/.cpp, DepthSurface.cpp and the debt file conflicted.

One-sample surfaces (120900a342, mine). PPSA34501 and PPSA34502 (#6304) copy from a one-sample D32 surface. Before, its single-sample view was bound to the shader's sampler2DMS, which Vulkan allows only for multisampled views (VUID-RuntimeSpirv-samples-08726; it happened to work on NVIDIA).

  • DepthSample.comp is now built in a sampler2D variant and a sampler2DMS variant, and the copy picks one by the surface's sample count.
  • The copy no longer requires the native-multisample import state (samplingActive). It reads the host image the draws rendered into.
  • Its barriers name VK_PIPELINE_STAGE_HOST_BIT beside ALL_COMMANDS, as the CMASK clear's do, because their access masks include host bits.

Review fixes (127aba3ed6, mine).

  • The copy drains the draw pipeline before it is recorded, as the CB metadata pass above it does. This hunk was lost in my rebase.
  • The plane address is the one the depth surface registers under, as decodeDepth decodes it: a multisampled plane's pipe-bank XOR bits are stripped and a DB_DEPTH_VIEW slice is added. Mipmapped and partially resident planes are refused.
  • A color target with CMASK fast clears is refused, as the CB resolve refuses one.
  • The source is found through its depth owner (planeSurface), and it must be a 32-bit float surface with the decoded sample count.

The copy is still chosen from the viewport and scissor. The maintainers accepted that with its debt line, so the draw-based copy (the title's draw with a driver pixel program) will be its own PR.

Tested

Ubuntu 24.04, GCC 13.3, NVIDIA RTX 4070 Ti, driver 595.99.02.

  • On 223e90289b, the lavapipe fix for the CI failure: DepthCopyCase now copies at 2 samples when the device can sample them, otherwise 4, and skips the multisample half when neither works.

    • agc_driver_depth_storage passes 3 of 3 under lavapipe (llvmpipe, LLVM 20.1.2, which samples depth at 1 and 4 samples only).
    • The 30 depth tests pass under lavapipe (one of them skipped).
    • On the NVIDIA card they pass 3 of 3.
  • On 67cea1c314, @simonbbby's addition (co-author), which @oneandonlydean asked for: on a device that can't sample two-sample depth, DepthCopyCase creates a two-sample surface and expects the cannot sample at its sample count refusal.

    • Under lavapipe, agc_driver_depth_storage passes 3 of 3 and prints DB depth copy: unsupported two-sample source refused cleanly each time.
    • The 30 depth tests pass under lavapipe, and 3 of 3 on the RTX 4070 Ti, which samples two-sample depth and so skips the case.
    • simonbbby also ran it on an RTX 3090 and RADV (gfx1036), and confirmed under GDB that the earlier segfault was the cache teardown after the device was gone.
  • On 127aba3ed6, on main f894ba6: the 30 tests matching depth|Depth|db_copy|DbCopy|^agc_driver_graphics$ pass 3 of 3.

  • The decode tests now also cover XOR stripping, slice addressing and the mip refusal.

  • On 120900a342, before the review fixes, the 29 depth tests passed.

  • The tests for the one-sample fix:

    • depthCopyPassTests decodes a one-sample plane and refuses its sample 1.
    • DepthCopyCase, after the multisample checks, copies from a one-sample D32 surface, expects its clear value in every texel, and refuses sample 1.
  • Khronos validation layer (LunarG SDK 1.4.363) over ^agc_driver_(depth_storage|graphics): 127aba3ed6, 120900a342 and main f894ba6 each pass 5 of 5 with no VUID.

  • The same layer at the previous head (815c622, the same two commits on an older main), over agc_driver_depth_storage* and agc_driver_graphics:

    • Without the one-sample fix: 4 of 4 pass with VUID-RuntimeSpirv-samples-08726 ×2, plus -02815 ×6 and -02816 ×12 (host bits on ALL_COMMANDS).
    • With it: 4 of 4 pass with no VUID.
  • CoD Black Ops II (PPSA34502):

  • @alexpournaras: PPSA34501 gets past the 0x00000084 stop with this branch (feat(agc): run DB depth copies into a single-sample R32 float target #5499).

  • codingreapermaps's original testing (Windows 11, MinGW-w64 GCC 15.2.0, NVIDIA MX450): PPSA12361's map renders, and a RenderDoc capture shows the R32 float target holding the copied depth that the ambient occlusion pass reads.

  • @clairtonmichel, AMD Radeon RX 7900 XTX (RADV, Mesa 26.2.5, Fedora): the same 30 tests pass at 127aba3ed6.

Not tested: Intel at this head.

Checklist

🤖 Generated with Claude Code

codingreapermaps and others added 2 commits October 21, 2026 08:03
A draw with DB_RENDER_CONTROL.DEPTH_COPY copies one sample of the
Z_32_FLOAT depth surface into color target 0. It now runs as a compute
pass that fetches that sample and stores it into the R32 float target,
when the draw covers the whole surface without depth or stencil tests.
With COPY_CENTROID the sample is the first one the draw covers, which is
sample 0 under the full sample mask the driver requires, as radeonsi
programs its per-sample DB to CB copies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A one-sample depth surface was bound to the copy shader's sampler2DMS,
which Vulkan only allows for a multisampled view. The shader is now
built in a single-sample and a multisample variant, and the copy picks
one by the surface's sample count. The copy also no longer requires the
guest-memory import state of native multisample depth sampling: it reads
the host image the draws rendered into. Its barriers name the host stage
their host access bits need, as the CMASK clear's do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 21, 2026
@github-actions

github-actions Bot commented Oct 21, 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
PR 5499 core/libs/prx/libSceAgcDriver/Graphics/shaders/DepthSample.comp
PR 6146 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp L324
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp L67
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp L203
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp L1899-1916
PR 6887 core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp L58
PR 6965 core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp L58
PR 9077 docs/dev/debt/libSceAgcDriver.md L157

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 1191 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 4448 docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/shaders/DepthSample.comp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6044 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/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6194 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6202 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6235 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6290 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6548 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6879 core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6973 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6987 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6989 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6995 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7410 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 7449 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7484 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawPrecheck.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Draw.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7659 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7803 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7883 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7893 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7910 docs/dev/debt/libSceAgcDriver.md
PR 8004 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8105 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/DepthSurface.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8212 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
PR 8278 core/libs/prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/TextureDetiler.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/TextureDetiler.cpp
PR 8489 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8538 core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8552 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8564 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8612 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8658 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
PR 8992 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9020 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/State.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/State.cpp
core/libs/prx/libSceAgcDriver/tests/Graphics.cpp
docs/dev/debt/libSceAgcDriver.md

@clairtonmichel

Copy link
Copy Markdown

Tested on AMD Ryzen 7 9800X3D and AMD Radeon RX 7900 XTX (RADV NAVI31) with Fedora Linux (Mesa 26.2.5):

  • Built cleanly with zero errors.
  • Ran the AGC test suite: all relevant depth copy and storage write-back tests passed successfully (including agc_driver_storage_write_back_no_window, which passes cleanly when isolated).
  • No regressions observed with these DB depth changes on RADV. Great work!

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @clairtonmichel, that's the first AMD run of this. Heads-up: the next push replaces the compute copy you tested (120900a342) with the draw-based copy the review asked for. The title's own draw then runs with a driver pixel program reading the depth sample, so coverage comes from its geometry. The tests change with it. I'll say here when that's up, in case you'd like to rerun on RADV.

AI-assisted: yes (Claude Code)

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@milescoviello an update from the maintainer side: the whole-surface copy has been accepted as it is, with its debt line, so #8975 doesn't need to wait for the draw-based copy. If you mark it ready as it stands, we'll run full CI and merge it, then close #5499 as carried. The draw-based copy can follow as its own PR whenever you get to it.

- Drain the draw pipeline before recording the copy, as the CB metadata
  pass does, so the copy follows the queued draws that render the plane.
- Address the plane as decodeDepth registers it: a multisampled plane's
  pipe-bank XOR bits are stripped and a DB_DEPTH_VIEW slice is added.
  Mipmapped or partially resident planes are refused.
- Refuse a color target with CMASK fast clears, as the CB resolve does.
- Find the source through the depth owner (planeSurface) and require a
  32-bit float surface with the decoded sample count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the fix error Closes an issue (Fixes #N) label Oct 21, 2026
@milescoviello
milescoviello marked this pull request as ready for review October 21, 2026 08:56
@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @oneandonlydean. Before marking it ready I went over the rebase once more and fixed four things in 127aba3ed6 (one commit on top, codingreapermaps's commit unchanged):

  1. The copy didn't drain the draw pipeline. That's my rebase error. Main's CB metadata branch right above drains the pipelined draws before recording, and the depth-copy branch predated that. Without the drain, the copy could be recorded before the queued draws that render the depth plane. It now drains the same way.
  2. The plane address now matches the one the depth surface registers under. A two-sample plane's address had its pipe-bank XOR bits left in, so a nonzero XOR missed the surface. A nonzero DB_DEPTH_VIEW slice would copy slice 0's surface. The address now strips the XOR and adds the slice offset, as decodeDepth does, and mipmapped or partially resident planes (DB_Z_INFO 0x000f1000, the view's mip level) are refused.
  3. A target with CMASK fast clears is refused, as the CB resolve does. The copy doesn't update the CMASK, so a later eliminate could overwrite the copied depth with the clear color.
  4. The surface lookup uses the depth owner (planeSurface), like the texture and storage paths, instead of the last surface created at that address. It also requires a 32-bit float surface with the decoded sample count.

The decode tests cover 2: XOR stripping, slice addressing and the mip refusal. On 127aba3ed6, the 30 tests matching depth|Depth|db_copy|DbCopy|^agc_driver_graphics$ pass 3 of 3. The validation layer over ^agc_driver_(depth_storage|graphics) passes 5 of 5 with no VUID, as at 120900a342. It's marked ready now.

The draw-based copy will follow as its own PR. I have a first version of it locally: the title's draw with a driver pixel program, and a coverage test against a reference draw of the same triangle.

AI-assisted: yes (Claude Code)

@clairtonmichel

Copy link
Copy Markdown

Tested final rebase (127aba3) on AMD Ryzen 7 9800X3D and AMD Radeon RX 7900 XTX (RADV, Fedora Linux, Mesa 26.2.5):

  • Reran the 30 target depth/db_copy tests (depth|Depth|db_copy|DbCopy|^agc_driver_graphics$): 100% passed successfully (30/30 green).
  • Native depth clear refusals and all plane address/XOR/mip checks behave perfectly. Ready to merge!

@milescoviello

Copy link
Copy Markdown
Contributor Author

Thanks @clairtonmichel, that's this head on AMD. I added it to the Tested section and the GPU line.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor Author

The draw-based copy is up as #8999, stacked on this PR. It runs the copy as the title's draw with a driver pixel program, and a new execution test checks that only the texels a reference draw of the same triangle covers are written. It's for after this one merges.

AI-assisted: yes (Claude Code)

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@milescoviello thanks for marking it ready. Full CI found one problem on Linux (run 39574666009, llvmpipe; Windows is green): agc_driver_depth_storage segfaults right after the new refusal message:

AGC graphics: DB depth copy from a depth surface the device cannot sample at its sample count
... agc_driver_depth_storage ...***Exception: SegFault  1.69 sec

So on a device that can't sample the depth surface at its sample count, the refusal path crashes instead of refusing cleanly (llvmpipe hits it; the GPUs you tested probably don't). Could you take a look? We're reproducing it locally too and will add the line if we find it first.

The DB depth copy case drew a two-sample depth surface, which lavapipe
cannot sample (it samples depth at 1 and 4 samples only). The copy then
threw outside the expected-failure checks and the test crashed on exit.
Pick 2 samples when the device samples them, else 4, else skip the
multisample half, and copy every sample of that count.

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

Copy link
Copy Markdown
Contributor Author

@oneandonlydean found it, it's the test. lavapipe samples depth only at 1 and 4 samples: llvmpipe 20.1 reports sampledImageDepthSampleCounts and framebufferDepthSampleCounts as 1 | 4. The DB depth copy case in DepthStorage.cpp used a two-sample surface, so the refusal itself is right. But that copy ran outside the expected-failure checks, so the exception left the test with depth surfaces and cached textures still alive. The segfault is most likely their teardown after the device was gone.

The fix only touches the test. It uses 2 samples when the device can sample them, otherwise 4, and otherwise skips the multisample half. It also copies every sample of that count, not just 0 and 1. I'll push it as a new commit once it passes here under lavapipe and on the NVIDIA card. A title perf run has the machine for about another 15 minutes.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor Author

@oneandonlydean pushed as 223e90289b, a new commit that only touches the test. DepthCopyCase now uses 2 samples when the device can sample them, otherwise 4, and skips the multisample half when neither works. It also copies every sample of that count.

Under lavapipe (llvmpipe, LLVM 20.1.2), agc_driver_depth_storage now passes 3 of 3, and the 30 tests matching depth|Depth|db_copy|DbCopy|^agc_driver_graphics$ pass (one of them skipped). On the RTX 4070 Ti they pass 3 of 3. I added this to the Tested section.

#8999 is rebased on top of it. Its tree doesn't change, since it removes that test case anyway.

AI-assisted: yes (Claude Code)

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@milescoviello thanks, that matches what we see: lavapipe gives 1 | 4 for both depth sample counts, so the two-sample copy hit the refusal outside an expected-failure check. 223e90289b reads right to us. It picks a count the device can sample, copies every sample of it, and keeps the past-the-end and extent refusals.

One small addition, if you agree: with this change no device runs the new refusal itself. AMD and NVIDIA sample depth at 2, and lavapipe now takes the 4-sample path, so Require(sampleable, "… cannot sample at its sample count") (DepthSurface.cpp:497) has no test. Could DepthCopyCase also take 2 samples when 2 is not in sampledImageDepthSampleCounts (the old test showed DepthSurfaceView still creates that surface on lavapipe), and wrap the copy in ExpectFailure(…, "cannot sample at its sample count", …) before ClearDepthSurfaces? On lavapipe CI that runs the exact path that crashed, and it would show that the refusal fails cleanly once the exception is caught. That settles the "most likely teardown" question without anyone needing a debugger. On devices without such a count it just skips.

@simonbbby

Copy link
Copy Markdown
Contributor

I tested Dean's requested unsupported-count case at exact head 223e90289b643ba2465e82ffcd7d73c8c6794e26 on native Linux. The refusal returns cleanly when caught before normal cache/device cleanup.

  • Restoring only DepthStorage.cpp from the parent reproduces the original lavapipe failure: the expected cannot sample at its sample count message, then exit 139. A GDB run places the SIGSEGV during __run_exit_handlers → StorageTextureCache::~StorageTextureCache → StorageTexture::~StorageTexture → StorageTexture::release → Context::Function<vkDestroyImageView>, rather than in the depth copy. The exception bypasses ClearCachedTextures in main; unwinding destroys Device (including unloading the Vulkan library) before process-exit cache destruction. This confirms the teardown explanation for the secondary crash.
  • With the test-only addition below, agc_driver_depth_storage_tests passes 3/3 on lavapipe, printing unsupported two-sample source refused cleanly each time. ExpectFailure requires the specific sampling refusal, then the remaining one-sample copy/readback and normal teardown complete.
  • The same binary passes 3/3 on RTX 3090 and 3/3 on gfx1036/RADV. Those devices sample two-sample depth, so the conditional refusal case is not exercised there. agc_driver_graphics_tests also passes.

Ubuntu 24.04.3, GCC 13.3, Release; lavapipe Mesa 25.2.8 / LLVM 20.1.2; RTX 3090 / NVIDIA 595.99.02; gfx1036 (1002:13c0) / RADV Mesa 25.2.8. Required Vulkan, shader cache disabled. No Khronos validation layer available, and no title run. All temporary edits were removed, the exact head rebuilt and the stock lavapipe test rerun successfully; checkout is clean.

This can be folded into the existing PR; it adds the requested expected-refusal coverage without changing production code. It does not make arbitrary unexpected exceptions in this fixture safe to tear down.

diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
index 4aba6f4a2..27236f419 100644
--- a/core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
+++ b/core/libs/prx/libSceAgcDriver/tests/execution/DepthStorage.cpp
@@ -355,6 +355,12 @@ void DepthCopyCase(Context context, std::uint8_t* block) {
         ExpectFailure([&] { copy(samples, 0, {Side / 2, Side / 2}); }, "of another size", "a DB depth copy of another extent than the depth surface was accepted");
         ClearDepthSurfaces(context.device);
     }
+    if ((context.limits.sampledImageDepthSampleCounts & VK_SAMPLE_COUNT_2_BIT) == 0) {
+        Require(DepthSurfaceView(context, DepthTarget{depthAddress, 0, {Side, Side}, VK_FORMAT_D32_SFLOAT, 0.375f, 0, 0, false, 2}) != VK_NULL_HANDLE, "the unsampleable two-sample depth surface was not created");
+        ExpectFailure([&] { copy(2, 0, {Side, Side}); }, "cannot sample at its sample count", "a DB depth copy from an unsampleable two-sample depth surface was accepted");
+        ClearDepthSurfaces(context.device);
+        std::puts("DB depth copy: unsupported two-sample source refused cleanly");
+    }
     Require(DepthSurfaceView(context, DepthTarget{depthAddress, 0, {Side, Side}, VK_FORMAT_D32_SFLOAT, 0.625f, 0, 0, false, 1}) != VK_NULL_HANDLE, "the one-sample depth surface was not created");
     std::fill(block, block + BlockBytes, std::uint8_t{0});
     copy(1, 0, {Side, Side});

…not sample

On a device that cannot sample two-sample depth, as lavapipe, the DB
depth copy case now also creates a two-sample surface and expects the
copy's sampling refusal, so that refusal is covered where it applies.
Devices that sample two-sample depth skip it.

Co-authored-by: simonbbby <159568960+simonbbby@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@milescoviello

Copy link
Copy Markdown
Contributor Author

@oneandonlydean agreed. Thanks @simonbbby for the diff and for the GDB trace: the crash is the cache teardown after Device was gone, as you showed, so that settles it. I've committed your addition unchanged as 67cea1c314, with you as co-author. I'm building it now to run under lavapipe and on the 4070 Ti, and I'll push it when it passes.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor Author

Pushed 67cea1c314, @simonbbby's addition as is, with them as co-author. Under lavapipe, agc_driver_depth_storage passes 3 of 3 and prints DB depth copy: unsupported two-sample source refused cleanly each time. The 30 depth tests pass under lavapipe and 3 of 3 on the RTX 4070 Ti, which samples two-sample depth and so skips the case. It's in the Tested section, together with simonbbby's RTX 3090 and RADV runs and the GDB finding.

AI-assisted: yes (Claude Code)

@oneandonlydean
oneandonlydean merged commit 0c83831 into boykopovar:main Oct 21, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* build docs fix error Closes an issue (Fixes #N) unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PPSA34501] Unsupported DB_RENDER_CONTROL depth copy (0x84) causes fatal abort

5 participants