Skip to content

fix(agc): keep guest stores over freed storage-image memory - #6960

Closed
romainveurrier wants to merge 1 commit into
boykopovar:mainfrom
romainveurrier:fix/agc-5934-storage-writeback
Closed

romainveurrier wants to merge 1 commit into
boykopovar:mainfrom
romainveurrier:fix/agc-5934-storage-writeback

Conversation

@romainveurrier

@romainveurrier romainveurrier commented Oct 16, 2026 •

Copy link
Copy Markdown

What

SONIC SUPERSTARS crashes in its allocator after respawns: the free-list links at the start of a freed 64 KiB block hold 0x00ffffff00ffffff, the texels of a 32x32 RGBA8 R64KBX storage image at that address (#5934). The image's results stay on the GPU past the label after its dispatch and are stored later, when the title may have freed the block. Two cases lose the title's stores:

  1. Same bytes. Outside the write watch (every Windows host import, see decideImportWatch), a CPU store is found only by comparing with the bytes saved at upload. A free that writes the links the block already held reads as no store, and the results are stored over it. Deterministic.
  2. Decision to store. writeBackLayers chooses the 64 KiB blocks the CPU owns, then stores the others after a GPU round trip (CPU path) or when the recorded copy runs (import path). A CPU store landing in between is overwritten. On the CPU path the bytes the store compares against were also read after the decision.

Changes:

  • GuestMemory::WriteChangedOverOriginal[Committed]: each changed 8-byte word is stored by compare-exchange against the bytes the decision used, now read before the decision. A refused range leaves its layers stale, so they re-upload.
  • StorageTexture::StoreBeforeGuestCompletion, called from WriteLabelOnGpu and for end-of-pipe interrupts without a label: pending results over compared memory are stored in queue order before the label.
  • The recorded GPU-direct store is used only while no label or interrupt has passed since the results became pending; later results take the compare-exchange store.
  • APS5_DEFER_COMPARED_RESULTS=1 and APS5_RECORDED_WRITEBACK=1 restore the previous behaviour of each part, for comparison.

New tests, through AgcDriver::Submit (PM4 dispatch, then a RELEASE_MEM label the test waits for, then CPU stores; no hooks):

  • StorageWriteBackWindowR64Kbx: links stored at random times around a driver read that triggers the write-back, in compared and in watched memory.
  • StorageSameBytesReuseR64Kbx: the block freed with the links it held at upload.

Not addressed:

  • In watched memory an identical-byte store is still lost: unchangedSinceBaseline (dfe147f) stores over a stamped block equal to its baseline, a rule for stamps on unchanged bytes (PPSA12544). APS5_TEST_WATCHED_SAME_BYTES=1 runs that case; it fails before and after this change.
  • Results in compared memory that were never written back before are now stored at every label: a synthetic cost probe (not part of this PR; 8 GPU-only images, a label per frame) measured, in ms per frame for 4 MiB images on main -> this PR: RTX 2050 2.7 -> 18.6 (import) and 2.6 -> 32.3 (CPU path), Iris Xe 4.6 -> 21.4 (import) and 4.5 -> 33.9 (CPU path); for 256 KiB images RTX 2050 0.22 -> 1.29 (import). Watched memory is unaffected. No title measured.
  • Not yet confirmed on the title; the report asks the reporter to test this branch.

Tested

Fedora 44, Release build of main at 4986aca with and without this change, tests only (no title run).

  • StorageWriteBackWindowR64Kbx, links lost of 96 attempts per memory kind: main 4-21 per GPU, path and memory kind; this PR 0 in every case. In watched memory 16–29 attempts per run had the compare-exchange keep a store made after the decision.
  • StorageSameBytesReuseR64Kbx: main 8/8 lost; this PR 0/8.
  • Each with APS5_NO_HOST_IMPORT=1 (CPU path) and with the host import.
  • lavapipe: 0.4 s and 0.2 s.
  • AGC ctest selection, 132 tests (execution tests touching storage images, imports and labels; recorder, driver, graphics, pm4 and flip suites): main 129 passed per GPU, this PR 131. The two new tests account for the difference. The one remaining failure fails on main too: agc_driver_store_over_untracked on the RTX 2050 ("the result did not reach a block the CPU left alone") and agc_driver_sample_multisample_target on the Iris Xe.

Investigation report and logs attached.

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: PPSA06888 SONIC SUPERSTARS (PPSA06888) #5382
  • GPUs tested: NVIDIA GeForce RTX 2050 (driver 615.71.09) and Intel Iris Xe (Mesa), Fedora 44; lavapipe
  • AI-assisted: yes

@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 862 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1368 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 2434 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4847 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6108 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6146 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6185 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6187 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6209 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6273 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6280 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6290 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6501 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 6615 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6782 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6804 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6921 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6926 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6971 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6973 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6987 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6989 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6995 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7048 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7275 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7310 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7369 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7449 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
PR 7464 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7604 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7622 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 7643 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7922 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7963 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 7978 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 8004 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8014 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8212 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 8246 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8484 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8707 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 8887 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9176 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9287 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9289 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9356 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9385 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 9387 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9432 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9445 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9489 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9508 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9533 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 9674 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9717 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 9742 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 9875 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9881 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9884 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 9891 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9898 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 9999 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10026 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10043 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10064 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10069 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10159 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10193 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10194 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10249 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10256 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10351 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10442 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10472 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10547 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10652 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10656 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10668 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10678 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10743 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10773 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10846 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10859 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10867 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 10886 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 10940 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11265 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11280 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11351 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11435 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11436 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11444 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11447 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 11483 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11485 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11554 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11557 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 11920 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 11995 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12070 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12120 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12246 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12452 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 12536 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12567 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12568 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12617 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12662 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12696 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12745 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12746 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12764 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12792 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12813 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12828 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12840 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12855 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12904 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12921 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 12944 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 12980 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13021 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 13023 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 13044 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13125 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 13145 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 13148 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 13159 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 13251 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13499 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13613 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 13621 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13646 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13648 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13656 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13678 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13796 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 13807 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp

@github-actions github-actions Bot added the agc libSceAgc* label Oct 16, 2026
@romainveurrier

Copy link
Copy Markdown
Author

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 6108 core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp L351
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp L2056
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp L4682-4683
PR 6367 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp L4863-4865
PR 6820 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp L4863-4865
PR 6914 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp L89

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/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 1896 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4048 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4650 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4891 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5390 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5431 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5480 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5499 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5761 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5987 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/include/GuestMemory.hpp
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6222 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6259 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6503 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6553 core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp
PR 6718 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Texture.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Texture.cpp

Overlap check:

This PR is a draft until the #5934 reporter tests it in-game, so the others can go first; I'll rebase. Depends on: none.

@CnRJay CnRJay left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bug is real and the two tests show it (main loses 4-21 of 96 stores, this PR 0). The cost is the problem, and the PR already measures it.

"Results in compared memory that were never written back before are now stored at every label": 2.7 to 18.6 ms per frame (RTX 2050, import path) and 2.6 to 32.3 ms (CPU path) for 4 MiB images, 4.6 to 21.4 / 4.5 to 33.9 ms on the Iris Xe, 0.22 to 1.29 ms for 256 KiB images. That is a GPU-to-CPU round trip of every pending storage image at every label, on by default, for every title on every Windows host import. A title that writes a few large GPU-only render targets and has a label per frame goes from 60 fps to about 30 for this fix alone. "No title measured" does not make that acceptable, and storing at every label is the wrong approach: the SONIC SUPERSTARS case is a 32x32 RGBA8 image in a 64 KiB block, and the large images never needed this.

What I would do instead:

  • Bound the label store to the surfaces the existing small-store rule covers (StorageTexture::SmallStoreBytes, 64 KiB), which is the class that shares a block with something a title allocates over. Large render targets stay on the current path.
  • Or gate the new store on the image's results having been read back before (the image is known to be CPU-visible), so GPU-only targets are never touched.
  • Whichever is chosen, the per-frame cost on a title with several large GPU-only targets and a label per frame belongs in the test, as a bound, not in the description as a known limit.

Please also post the cost on the title this was found on (SONIC SUPERSTARS), with the summary lines of main and this PR from the same scene, no APS5_PROFILE_*. The report asks the reporter to test the branch; until they have, the PR can't show that the crash is gone or what it costs.

#6948 stores linear storage images after every dispatch for a similar reason and touches the same write-back path; the two should be reconciled so that a label does not store the same image twice.

@keravyn-ops

Copy link
Copy Markdown
Contributor

AMD / Windows run of this PR at 36df663: 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.

  • agc_driver_storage_same_bytes_reuse_r64_kbx: pass (0.39 s)
  • agc_driver_storage_write_back_window_r64_kbx: pass (0.56 s)

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

@hugodearaujo

hugodearaujo commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Data point from Linux, AMD Radeon RX 9070 XT, RADV (Mesa 26.2.5): EA SPORTS FC 25 (PPSA20049), main e5f18ea with #6343, #7606 and #7413.

  • Without this PR, 3 runs. One crashed in the title's own allocator 280 s after start with the signature of SONIC SUPERSTARS (PPSA06888): guest heap metadata overwritten with texel data after respawns #5934: the memory around the chunk it was splitting (0x10f4ae7e00–0x10f4ae8800) held the repeated texel 0xff1b181c where its heap headers should be, and that memory lies inside a 1920x1080 RGBA8 storage image created earlier at 0x10f4800000. Another reached Kick Off but sat on its tunnel scene with no menu and did not react to input. The third lost the GPU under gdb before that.
  • With this PR's head 36df663 merged on top, 2 runs. Both reached Kick Off's menus; one went on through team and kit selection to the pre-match cutscene, where it lost the GPU (VK_ERROR_DEVICE_LOST, amdgpu ring gfx_0.0.0 timeout). That also happened once without this PR, so I'm treating it as a separate issue.

Few runs, so this is a hint, not proof.

@MarcZX10

Copy link
Copy Markdown
Contributor

I am investigating issue #8152, where a CPU write to the right half of a resident linear target shares 64 KiB blocks with a recorded draw to the left. I added a local regression variant that seeds the left half, draws only there, writes 0x42 to the right half, and checks that both results survive. It compiles, but this host's CPU guard prevents the AGC test from running.

Does #6960's GPU-direct imported write-back path cover that partial-draw case? The current-main block selection can retain a whole touched block, preserving the CPU bytes while dropping GPU output elsewhere in that block. I want to coordinate this with your write-back changes before opening a related PR.

@orezraey

Copy link
Copy Markdown
Contributor

Data point: Cult of the Lamb (PPSA06465, 01.000.023) hits the same corruption as #5934 on main, and does not with this PR.

Build

  • main 6b6c701
  • this PR at 36df663, cherry-picked onto that main (it conflicts today). In Texture.hpp I kept both WaitForFlushing and StoreBeforeGuestCompletion; in Texture.cpp I kept both atomic blocks and took this PR's side of the third hunk (the late ReadCommitted block removed).

Host: Windows 11 Pro 26200, Ryzen 7 9700X, NVIDIA GeForce RTX 5070 Ti, driver 616.64, 239 Hz display, AC. Shader cache warm.

Method: APS5_PROFILE_DRAW=1, input from an APS5_PAD_INPUT_FILE timeline (cross at the splash, Play, then New Save), each run 250 s from launch, all on 2026-10-21. The machine was in normal desktop use during the runs.

Build Runs Crashed Reached gameplay
main 5 2 (40 s in the menu; 165 s while loading the new save) 3
this PR 5 0 5

Both crashes are an access violation inside Unity's TLSF allocator (ALLOC_GFX_THREAD), unlinking a free block whose header is no longer valid (mov [rdx+0x18], rbx with rdx = 0). The broken headers sat at 0x2359bbff0 and 0x235ec4ff8, in the region where the title sub-allocates its textures and storage images.

Earlier runs on the same main, driven by keyboard, toggling one switch at a time:

Switch Runs Crashed
none 6 4
APS5_GPU_NO_WRITEBACK=1 4 0
APS5_STORE_AT_LABEL=1 3 0
APS5_NO_UNIT_SHADOW=1 3 0

No VUID- lines in any log; presents per 10 s are the same on both builds (about 430 to 590).

Analysis (AI-assisted, not measured): the switches point at a deferred write-back of a GPU-written 64 KiB unit landing after the title's label, over memory the allocator had already freed and reused for the next block's header, which is what this PR stops.

Logs on request.

@orezraey

Copy link
Copy Markdown
Contributor

Data point: Cult of the Lamb (PPSA06465, 01.000.023) still crashes on current main with the same corruption this PR fixes, so it is still needed there. I reran the same input timeline as my earlier report: splash, Play, new save, then 60 s.

main a3987a1 (relinked with that commit's relinker), Windows 11, WinLibs GCC 15.2, Release: 2 crashes in 3 runs.

  • Run 1 survived the new save plus 60 s.
  • Run 2 crashed 21 s after launch, before the splash. Job.Worker 12 wrote to 0x18 at app.exe+0x16a3270.
  • Run 3 crashed right after the new save. UnityGfxDeviceWorker read from 0x46bc47ff0 at app.exe+0x16a36ef.
  • Both crashes are in the title's allocator. ALLOC_GFX_THREAD strings sit in the registers, and the writes go through a corrupted free-list node. This is the same signature as before, now also hit during startup.

This PR at 36df663 on main 6b6c701 (my earlier build): no crash in 2 runs today (5 of 5 in my earlier report), with the same timeline on the same machine.

This PR now conflicts with main in PacketMemory.cpp, VulkanDevice.cpp and Texture.{hpp,cpp}. main's StoreDrawnLinear / StoreReadbackBeforeLabel calls sit where this PR adds StoreBeforeGuestCompletion. Both run at the label and interrupt sites, so a rebase would need to decide whether the new main stores already cover the case this PR handles. On this title they do not: main alone still corrupts.

@orezraey

Copy link
Copy Markdown
Contributor

@romainveurrier Do you plan to continue this one? CnRJay's review (bound the label store to the small-store class, StorageTexture::SmallStoreBytes, or to images already read back, and measure the per-frame cost) looks like the way forward. Cult of the Lamb gives a reproducible title to measure both the crash and the cost on. If you'd rather not pick it up again, I'd like to do that version in a new PR that builds on yours and credits you. I'll wait to hear from you first.

@JJenkx

JJenkx commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Current-main control for the original StorageSameBytesReuseR64Kbx.cpp fixture at 36df6631b6 (byte-identical to GitHub blob 7d0f1855991c4f02e770aa72e46ab426a60ed798): it passes on Linux/RADV without this PR's production changes.

  • main a4eca2a056bf; RX 6650 XT, Release. Full SDK source is 818a96b59c83 (additional HTTP-only work); AGC, libc and libkernel production trees are byte-identical to main. Actual loaded raw-library paths/hashes are recorded.
  • Compared memory: new links 8/8 kept, same links 8/8 kept; 16/16 results already published at the label.
  • Watched memory: same result, 8/8 + 8/8 kept; 16/16 already published. PASS=2 SKIP=0 FAIL=0.
  • Validation required and inserted in two Vulkan instances; 0 VUIDs, unchanged executable/libraries after execution. The run allowed host imports; per-image import coverage was not measured.

Current main's StoreReadbackBeforeLabel already covers linear images or guestBytes <= SmallStoreBytes; this result covers this fixture's 32×32 RGBA8 R64KBX case. It does not establish that the separate concurrent write-back-window fixture, larger images, or the Windows title reports are resolved. One run on one GPU; no performance comparison and no candidate branch test.

Original fixture, build commands, loader identities and full log, SHA-256 ee10623d58f3ca7e269a7f0205851271121bbd1792446f18b550d320eae31309.

Larger-surface follow-up: extending the same fixture to 256×256 RGBA8 R64KBX (256 KiB) reproduces a remaining case on current main. The variant asserts the decoded dimensions/footprint and verifies a control GPU dispatch actually writes both tested offsets before the reuse trials.

Mode Compared memory Watched memory
Host imports allowed Changed links 8/8 kept; identical links 8/8 lost to texels Skipped: the requested region was not fully watched
APS5_NO_HOST_IMPORT=1 Changed links 8/8 kept; identical links 8/8 lost Changed links 8/8 kept; identical links 8/8 lost

The same executable and frozen libraries were used in both modes; each run inserted validation in two instances, logged 0 VUIDs, and left the binaries unchanged. The second run has 0 skipped memory classes and exits 1 with both classes failing. This is baseline failure evidence, not a production fix. It covers a larger footprint than SmallStoreBytes; the original small fixture above still passes.

Inference to investigate: the current writeBackLayers keep-block predicate includes !unchangedSinceBaseline when considering written blocks. Value-stable CPU stores are worth checking there, but these experiments do not establish that predicate as the sole cause. No completion-order-aware fix is installed, and this result does not demonstrate KLONOA's exact cause or a performance effect.

Variant source, geometry/control checks, exact build/run commands and both full logs, SHA-256 8823fdde3943a63f379d4de411deea7836b10a8e8d1adee3229ef889e43cfd96.

AI-assisted: yes (Codex).

@JJenkx

JJenkx commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Windows result for the 256×256 RGBA8 R64KBX same-value variant: it reproduces as on Linux, in both modes.

  • Build: main 7feb37ee3e (no other changes) with LargeStorageSameBytesReuse.cpp from the archive above (archive SHA-256 8823fdde… as posted) added to tests/execution, file SHA-256 450df085c9d13f9d32599cdb6635e485e13c3c5df14a64f3cd10fb7c7878e4d4. Registered by the existing glob as agc_driver_large_storage_same_bytes_reuse.
  • Host: Windows 11 22621, MinGW-w64 GCC 15.2.0 UCRT, Release, Radeon RX 6700 XT with the AMD proprietary driver 26.10.1.
  • Validation: VVL 1.4.363 inserted in both instances of each run, 0 VUIDs. APS5_TEST_WATCHED_SAME_BYTES=1, ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1.
Mode Compared memory Watched memory
Host imports allowed New links 8/8 kept; identical links 8/8 lost to texels (0x00ffffff00ffffff) Skipped: watched=0, the write watch does not cover the surface
APS5_NO_HOST_IMPORT=1 New links 8/8 kept; identical links 8/8 lost watched=1; new links 8/8 kept; identical links 8/8 lost

notPendingAtLabel=0 in every mode, so all 16 results were still pending at their label each time. The skip with host imports allowed is expected on Windows, where the driver does not write-watch GPU surface memory. With host imports disabled the surface is watched and still loses identical links, as in your Linux run. So on Windows too, the loss does not depend on whether the region is compared or watched.

AI-assisted: yes.

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

Labels

agc libSceAgc* needs rebase Conflicts with main, rebase needed unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants