Skip to content

fix(agc): look up a merged color target again when a recovery evicted its resident image - #13178

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
Tehshortbus:fix/agc-merge-target-resident-rebuild
Nov 2, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
Tehshortbus:fix/agc-merge-target-resident-rebuild

Conversation

@Tehshortbus

Copy link
Copy Markdown
Contributor

What

A draw whose color target merges in the pixel shader (a 4_4_4_4 partial write, or an unclamped normalized blend) stopped with the partial write of a packed color target does not store into the target's resident image when the texture caches were released in the middle of the draw. PPSA26344 (02.002.000) stopped on it at 528 s in a run with #12684 (comment), right after two vkAllocateMemory storage texture recovered ... initialResult=-2 lines.

How it happens:

  • prepareDraw looks up each target's resident image first, then resolves the draw's resources, which bind the merged target's surface as a storage image through the storage image cache.
  • When an image allocation in between runs out of device memory, BufferPool::AllocateMemory releases the texture caches. The storage half of ReleaseTextureCaches evicts every clean image, including one the draw holds; it only leaves it out of the bytes it counts as freed. In a draw with two merged targets, creating MRT1's image can evict MRT0's.
  • The resources then miss in the cache and bind a new image of the surface, while the target still holds the evicted one, so the check fails.

The change: after the resources are resolved, a merged target whose resident image the resources do not store into is looked up again (CachedStorageSurface, or CachedStorageLayers for an array slice) through refreshResidentTarget, and its attachment view is replaced. That finds the image the resources bound. The existing check stays, so a draw that still disagrees stops as before. Draw.cpp +12/−2, the test +61/−4.

Tested

CachyOS Linux (kernel 7.3.0-4-cachyos), GCC 16.2.1, Release, NVIDIA GeForce RTX 4070 SUPER (615.78.08). Head 5fda10d3d4 on main 422f96b3a9.

  • New case in agc_driver_unclamped_normalized_blend. Two 8_8 UNORM targets blend in one draw, as in the title. MRT0's resident image is created before the draw. During the draw, MRT1's image creation calls ReleaseTextureCaches(..., true), as the recovery of an out-of-memory image allocation does at that point, and the test checks that the release evicted storage images. Both targets are then checked per pixel against the CPU reference.

    • With this change it passes. With main's Draw.cpp and the same test it stops with the title's message.
    • The release is called from a vkCreateImage wrapper in a test Context rather than by failing vkAllocateMemory. A failing allocation needs a second BufferPool, and the pipeline store treats a context with another pool as a new device, so it abandoned the device's cached pipelines and the validation layer reported them leaked at vkDestroyDevice.
  • Focused run. ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ctest --test-dir build-tests -V -R '^agc_driver_(unclamped_normalized_blend|packed_unorm4444.*|linear_target.*|dcc_keys.*|partially_resident.*|uint8x4.*|stencil.*|multisample.*|multisampled.*|pass_.*|sample_order.*|draw.*)$', the draw-path tests:

    main this change
    tests 82/82 pass 82/82 pass
    VUID- lines 0 0
    was not found but was requested by env var VK_INSTANCE_LAYERS 0 0
    validation layer inserted 106 106

    agc_driver_stencil_ref_export and agc_driver_sample_order_grid_reference skip on this device in both runs. The main column ran main's Draw.cpp and test file in the same build tree.

  • Full suite. All 2955 pass under the same environment; 34 of them skip on this machine, most of them VideoOut flip tests.

  • PPSA26344. Not run on this head. The stop was seen once, in the run with perf(agc): let the sampled texture cache grow into host memory while a frame's textures don't fit #12684, which put the storage image cache under more pressure.

Overlap: tools/pr_overlap.py --branch lists #13145, #13146, #13147, #13148 and #13149 in UnclampedNormalizedBlend.cpp; each of them sets the files #12916 changed back to their contents before #12916. The 28 pull requests it could not compare give the same conflicts in Draw.cpp and the test with this branch as with main. The second lookup goes through the cache directly instead of moving the resident lookup into a function, which would have conflicted with #7310 and #11825.

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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: NVIDIA GeForce RTX 4070 SUPER, driver 615.78.08, CachyOS Linux (kernel 7.3.0-4-cachyos)
  • AI-assisted: yes

🤖 Generated with Claude Code

… its resident image

A texture cache release during a draw (the recovery of an out-of-memory image
allocation) evicts every clean storage image, including the resident image a
merged color target was just bound to. The draw's resources then bind the
surface's new image, and the draw stopped with "the partial write of a packed
color target does not store into the target's resident image". The target is
now looked up again so it renders into the image the resources store into.

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

github-actions Bot commented Oct 30, 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/Graphics/src/Draw.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7275 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7668 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 8246 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9020 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9335 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9356 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9387 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9712 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9748 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9852 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9897 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 9915 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 10442 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 11452 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 11825 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 12125 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 13148 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 13863 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 13920 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 13928 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 13929 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 14032 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 14943 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 14944 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp

@Tehshortbus

Copy link
Copy Markdown
Contributor Author

Checked the overlap report by hand, as in the Overlap section of the description: each of the 27 pull requests listed here gives the same conflicts in Draw.cpp and UnclampedNormalizedBlend.cpp when merged with this branch as when merged with main, so none of them needs a Depends on.

AI-assisted: yes (Claude Code)

@bunbeans2-arch

bunbeans2-arch commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

An AMD RDNA 4 run on Windows, since the description lists an NVIDIA RTX 4070 SUPER on Linux only.

Windows 11 Pro 10.0.22631, AMD Radeon RX 9070 XT (1002:7550, driver 32.0.32015.7029, amdvlk64), MSYS2 UCRT64 g++ 16.1.0, Release. ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation; with VK_LOADER_DEBUG=layer the loader logs Insert instance layer "VK_LAYER_KHRONOS_validation" in every run of every test below that creates a Vulkan instance (agc_driver_graphics and agc_shader_memory create none). 3 runs per side:

  • This head (5fda10d3d4) merged onto main f7f03daf52: agc_driver_unclamped_normalized_blend passes 3 of 3, printing 3 draws blending two targets each (1 with a texture cache release at MRT1's image creation). agc_shader_memory, agc_driver_cmask_fast_clear, agc_driver_graphics and agc_driver_sample_multisample_target also pass 3 of 3, as on main.
  • Control, main f7f03daf52 with only this PR's UnclampedNormalizedBlend.cpp: fails 3 of 3 with AGC graphics: the partial write of a packed color target does not store into the target's resident image, the message in the description.
  • No VUID- line on any side. Each log has the same 30 Undefined-Value-ShaderOutputNotConsumed-DynamicRendering warnings, on main, the control and this head alike.

AI-assisted: yes (Claude Code)

@oneandonlydean oneandonlydean self-assigned this Oct 30, 2026
@TechLevelZero

TechLevelZero commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

✅ NVIDIA GPU test: passed

PR head 5fda10d merged onto main e6f5730 · tested 2026-11-01 17:40 UTC · 17 min

GPU NVIDIA RTX 2000 Ada Generation, driver 595.99.02, Vulkan 1.4.329
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 2,429 passed · 6 failed (0 new, 3 also fail on main, 3 unstable on main) · 45 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 2,480 of 3,148 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (931 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.4 s, ⚠️ agc_driver_graphics 35.7 s, ⚠️ agc_driver_graphics_maps_fallback 35.3 s
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 1 of the last 10 main runs
agc_submit_progress: failed in 6 of the last 10 main runs
agc_submit_progress_no_timeline: failed in 8 of the last 10 main runs
Failing on main too (3, not counted against this PR)
agc_driver_image_table
guest_mmap_executable
guest_socket_options_multicast
Validation IDs already present on main (5 IDs in 484 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (484 tests): agc_driver, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 476 more
VUID-vkCmdCopyImage-srcImage-01548 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (7 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_sampling, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_prepared_exports
VUID-VkShaderModuleCreateInfo-pCode-08737 (1 test): agc_driver_image_sample_derivatives
Skipped (45)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_sample_order_grid_reference: skipped, the device does not keep depth drawn at custom sample locations at those locations, even after a transition that names them: the composite of uniform renders holds the guest's depth in 0 of 3005 sloped samples, so no path can be compared with it bit for bit
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_controls: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_cpuflip_in_order: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_dcc: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_deferred: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_eop_main: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_fps_limit: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_o
Reproduce
git fetch origin 5fda10d3d41bcd2fef35fb6fc2c0e163e36e0790 e6f57307fa7f47165d7fc1bee945abdb2f6816e7
git checkout e6f57307fa7f47165d7fc1bee945abdb2f6816e7 && git merge --no-ff 5fda10d3d41bcd2fef35fb6fc2c0e163e36e0790
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 32 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 4 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@JJenkx

JJenkx commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Windows GPU run of head 5fda10d3d4, merged onto main 1c6b316cf7 (clean merge, local only).

Windows 11 Enterprise 10.0.22621, Ryzen 9 5950X, Radeon RX 6700 XT with AMD proprietary driver 26.10.1 (Vulkan 1.4.315), WinLibs GCC 15.2.0 UCRT r7, Ninja, Release, BUILD_TESTING=ON. Khronos validation layer 1.4.309 requested for every test (VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation).

  • agc_driver_unclamped_normalized_blend, built from the test files this PR changes: pass, 3 of 3 runs each (--repeat until-fail:3), no failures, no skips.
  • They create Vulkan instances on the RX 6700 XT: the validation layer was inserted 3 times across the runs and reported no VUIDs.
  • Negative control: this PR's test files on main sources (one run) fail: agc_driver_unclamped_normalized_blend. So the test catches what the change fixes on this GPU.

AI-assisted: yes (Claude Code).

@github-actions github-actions Bot added the agc libSceAgc* label Oct 30, 2026
@Tehshortbus

Copy link
Copy Markdown
Contributor Author

The overlap report now lists 30 pull requests; 8 are new since my earlier check (13021, 13023, 7085, 9533, 9717, 9742, 9852, 9875). Merging each into main d6401d794e and into main with this branch gives the same conflicts both ways, none in Draw.cpp, so none of them needs a Depends on either.

AI-assisted: yes (Claude Code)

@Dextroid17

Copy link
Copy Markdown
Contributor

A lavapipe run, since the Linux CI job was skipped for this PR and the thread has NVIDIA and AMD results only.

Head 5fda10d3d4 merged onto main 4e2c5a72e6. CachyOS Linux (kernel 7.3.0), GCC 16.2.1, Release, clean environment, ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1. Two arms in one build tree, 3 runs of agc_driver_unclamped_normalized_blend each per device:

llvmpipe (Mesa 26.2.4, LLVM 23.1.1, GALLIUM_OVERRIDE_CPU_CAPS=avx)
  this change                    3/3 pass
  main's Draw.cpp, same test     3/3 fail
NVIDIA GeForce RTX 3080 Ti, 615.78.08
  this change                    3/3 pass
  main's Draw.cpp, same test     3/3 fail

The control stops with AGC graphics: the partial write of a packed color target does not store into the target's resident image. The passing runs print 3 draws blending two targets each (1 with a texture cache release at MRT1's image creation) on both devices, so the eviction case is exercised. No validation layer in these runs.

AI-assisted: yes

@oneandonlydean
oneandonlydean merged commit 9f33e54 into boykopovar:main Nov 2, 2026
11 checks passed
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.

6 participants