Skip to content

fix(agc): keep CPU stores made after a deferred DCC key store was recorded - #6186

Open
ee6aba54 wants to merge 8 commits into
boykopovar:mainfrom
ee6aba54:fix/agc-key-store-guard
Open

ee6aba54 wants to merge 8 commits into
boykopovar:mainfrom
ee6aba54:fix/agc-key-store-guard

Conversation

@ee6aba54

@ee6aba54 ee6aba54 commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

What

After a storage write-back the driver records a fill of the "uncompressed" DCC keys into the keys' host import (StoreUncompressedOnGpu, Recorder::QueueKeyStore). The fill lands whenever the GPU reaches it. A title that waited for its label, released the metadata block and reused it for something else had the 0xff pattern written over its new bytes. In PPSA15304 the reused block held a descriptor table, and the next dispatch built from it stopped the title in the recompiler:

[videoout] presentation failed: compute shader 0x1641a9c200: buffer descriptor uses an unsupported type

Four commits:

  • The queued key store takes a snapshot of the key bytes at record time and the batch stores the 0xff pattern through the changed-copy kernel of fix(agc): copy only the dwords a shader changed back from a GPU-copied buffer #6185: a dword is stored only where the import still holds the snapshot's value, so a CPU store made after the record keeps the CPU's value. A range whose pending writers are only earlier 0xff fills of the same keys stays guarded; a pending kernel of the title writing the keys, or a range without a device address or a snapshot, is filled as before. APS5_NO_GUARDED_KEY_STORE=1 restores the fills, and the [labels] line counts the guarded stores.
  • A unit shadow publish notes its pending write with its own value, so the key store queued right behind the publish of the key range's edge units stays guarded (the publish leaves the key bytes as they are).
  • The snapshot predicts the import: a title's key clear is a recorded fill of a known value, and after perf(agc): read DCC keys from the pending GPU fills that cover them instead of waiting for the fills #5520 a third of the key stores in PPSA15304 had such a fill pending. The pending fills of known value are applied to the snapshot in note order, so the kernel stores over the clear's bytes and still keeps a later CPU store. APS5_TRACE_KEY_GUARD=1 prints the pending writers of the stores that stay unguarded.
  • The value compare cannot tell a late CPU store of the value the keys already held from no store. The queued store therefore collects the guest writes of its range before the snapshot, and when it is recorded, every 64 KiB block the CPU wrote since then is left as the CPU left it. The [labels] line counts those blocks. Without write watching, the value compare stays the only guard.

Scope: the guard covers the deferred key stores; the unit shadow publishes (slab to import) stay unguarded, since a kernel over every published dword read the snapshot and the import over PCIe and halved the present rate of PPSA15304. #4794 stores results right behind the draw instead; on this title that mode (then APS5_EAGER_WRITEBACK=1) ran at 0.3 presents per second against 15 to 20 per 10 s with the deferred path and this guard, so the deferred path stays the one heavy titles need, and this guard keeps it safe where it crashed.

Tested

Linux, Ubuntu 24.04, NVIDIA GeForce RTX 5080 (driver 595.99.02). New test agc_guarded_key_store (a key clear recorded before the store: the keys end up stored; CPU stores made after the record survive, including one of the value the keys held, and the keys of a block the CPU left alone are stored). ctest -R agc_ passes. PPSA15304 on current main with #6185 alone stopped three times after 10 to 11 minutes in the section after the first drop with the descriptor fault above; with this change two runs of 20 and 25 minutes of continuous movement showed no fault, with 99.6 percent of the key stores guarded. Upstream's APS5_STORE_AT_LABEL=1 did not prevent the fault in the same section.

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; no silent stubs added
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source (none added)
  • Generic behaviour, not specific to one title
  • Depends on: fix(agc): copy only the dwords a shader changed back from a GPU-copied buffer #6185
  • Unblocks: PPSA15304 (no Game bring-up discussion yet)
  • GPUs tested: NVIDIA GeForce RTX 5080, driver 595.99.02, Ubuntu 24.04 (Linux)
  • AI-assisted: yes

@github-actions

github-actions Bot commented Oct 15, 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/tests/Recorder.cpp
PR 1191 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1324 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 4449 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5372 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 5426 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 5481 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 5656 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5883 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6146 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6169 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6182 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/UnitShadow.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6218 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6249 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6262 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6273 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6292 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6308 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6436 core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6548 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6549 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 6588 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6611 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6615 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6636 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6658 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6682 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/UnitShadow.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6683 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6718 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6741 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6743 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6759 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6820 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6848 core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6887 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6905 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6913 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6918 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6921 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6926 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6937 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/UnitShadow.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/UnitShadow.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6948 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6951 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6959 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6965 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6970 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6971 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6973 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6982 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6987 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6989 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6995 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7082 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7085 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7154 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7223 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7233 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7261 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7292 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7307 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7310 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7332 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7340 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7371 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7427 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7446 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketFlush.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7465 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7466 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7473 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7535 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7615 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7618 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7622 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7629 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/UnitShadow.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7644 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7647 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7659 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 7677 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7683 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 7705 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7717 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7803 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7817 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7833 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7844 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7849 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7867 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 7894 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7896 core/libs/prx/libSceAgcDriver/Graphics/src/DccMetadata.cpp
PR 7911 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 7919 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7945 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7948 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7961 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7981 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 7984 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8016 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8047 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8066 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 8089 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8091 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8104 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 8108 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 8126 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 8134 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8139 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 8160 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 8161 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 8167 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8206 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8246 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8267 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8274 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8293 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8295 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8326 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8336 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 8365 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8369 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8372 core/libs/prx/libSceAgcDriver/CMakeLists.txt

@ee6aba54

Copy link
Copy Markdown
Contributor Author

The overlap with #6182 is the option list in the test binary's main (tests/Recorder.cpp), both add a --...-only entry at the same spot; whichever lands second rebases in a minute, no dependency.

@Amoenus

Amoenus commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Same-value late CPU store: GPU reproduction

At unchanged head dce8f47370a69581928466e3b93029a9b6e0d913, both agc_changed_copy and agc_guarded_key_store pass five runs each. Changing only the existing late store from 0x12345678u to 0u and its expected preserved value to zero fails 5/5 with:

AGC graphics: a guarded key store overwrote a CPU store made after it was recorded

Two-line reproducer on our fork; production is unchanged. This commit intentionally fails the test, not a proposed fix. Restoring the original head, rebuilding and rerunning both groups gives five passes each again. No internal skips; each run identifies the RTX 5080. Maximum iteration: 0.69s; same-value case 0.32s.

Environment: Windows 11 Enterprise 26200, WinLibs GCC 15.2.0, Release, NVIDIA GeForce RTX 5080, driver 610.62 / 32.0.16.1062. Built the recorder target/dependencies; shader caches disabled, APS5_NO_GUARDED_KEY_STORE and APS5_CHANGED_COPY_ALWAYS absent. Ran ctest -R '^agc_(guarded_key_store|changed_copy)$' -V --timeout 30 --repeat until-fail:5 -j 1; for the expected-failure variant, only agc_guarded_key_store with --repeat until-pass:5.

The shader sees value=0xffffffff, before=0, held=0 for both a same-value late store and no late store, so equality cannot distinguish them. Could the test retain this case? If preservation includes it, ordering/write provenance is needed beyond value equality; if the intended guest ordering forbids it, please state and test that constraint.

Scope: public synthetic test on this PR head, not current-main integration, AMD/Linux/console coverage, or attribution of Sonic's loading stop. AI-assisted: yes (Codex).

@ee6aba54

Copy link
Copy Markdown
Contributor Author

Thanks, the reproduction is right. A late CPU store of the value the keys already held is indistinguishable from no store at all to the value compare. That case matters: zeroing reused memory that was already zero is exactly how a freed metadata block gets taken over. So preservation has to include it.

Pushed eb65a65, which adds write provenance on top of the value compare:

  • QueueKeyStore collects the guest writes of the fill range (GuestMemory::CollectWritesUncached) right before it takes the snapshot, and keeps that generation with the store.
  • When the run is recorded, it collects the range again. Every 64 KiB tracker block the CPU wrote since that generation (the CPU stamps from ChangedBlocks, not the driver's own MarkWritten stamps) is left as the CPU left it. The kernel only runs over the other blocks, which keeps a store whatever value it wrote.
  • The [labels] line counts the key blocks left to a later CPU store.

agc_guarded_key_store now places the keys across a block boundary. Your same-value case is part of it: a late store of 0u must survive, and the keys of the other block must still be stored. With the provenance check disabled, the test fails. On Linux with an RTX 5080, agc_guarded_key_store and agc_changed_copy pass five runs each, and ctest -R agc_ passes.

Limits:

  • The block granularity is coarser than the store. Key bytes that share a 64 KiB block with a late CPU store keep their old value instead of 0xff. A title writing into a block of keys it still uses while their store is pending is racing the GPU anyway, while a write into a released block is the reuse this guards against.
  • Without write watching (an arena reserved without it) the value compare stays the only guard. The test then prints that the same-value case was not tested.
  • A same-value CPU store that lands after the run was recorded but before the GPU executes it is still covered only by the value compare.

In PPSA15304, two runs on top of current main (about 160,000 guarded key stores in the longer one) left no key block to a later CPU store, and neither run had a fault. So in that section the new check never changes what is stored, and it closes the same-value case for titles that do reuse such memory.

This was referenced Oct 15, 2026
…s GPU results

A copied buffer's write-back stored every byte the GPU changed against the uploaded copy, even where the CPU had written the same bytes since the upload. The title's completion label is stored on the GPU before the CPU write-back runs, so a title may free and reuse the memory in between; the write-back then overwrote the allocator's free-list link with two dwords of shader output, and the next allocation of that size class faulted (PPSA15304: three general protection faults within minutes of walking, each at a free-list pop, each with a float pair in the popped link).

WriteChanged now stores a byte only when the GPU changed it and the CPU has not changed it since the upload, a three-way compare of result, uploaded copy and current guest memory; the storage image, mirror and tiled color target write-backs share it. The test that filled guest memory with foreign bytes before the write-back expected the GPU's bytes to win; it now uploads what it holds, and a new test checks that CPU-changed bytes keep their value while the rest take the GPU's.

(cherry picked from commit b7ee3fc376750b57115e0b5c2d0b1ef9d3d9f1f9)
…U-copied buffer

A buffer region staged in device memory was copied back whole when its
batch completed, so a CPU store the title made into the region meanwhile was
overwritten by the GPU's copy of the bytes it had been given.

The copy-in now keeps a snapshot of the uploaded bytes, and the copy-back
runs a kernel that stores a dword only where the shader's result differs
from the snapshot and the import still holds the snapshot's value: a dword
the CPU wrote after the upload keeps the CPU's value, as the CPU write-back
path does since the previous commit. Unaligned edges copy as before.
APS5_NO_CHANGED_COPY_BACK=1 restores the whole copies, APS5_CHANGED_COPY_ALWAYS=1
makes the kernel store every dword, and APS5_TRACE_COPY_BACK=1 counts the
dwords the import changed while the shader left them.
…on Windows

The test binary needs the libc DLL next to it like the other recorder test modes; without it Windows stops it with 0xc0000135.
…was recorded

The "uncompressed" key store recorded behind a storage write-back filled the
keys' host import whenever the GPU reached it. A title that had released the
metadata block by then and reused it (a descriptor table, for one) got the fill
pattern over its own bytes; the next dispatch built from such a V# failed in
the recompiler with an unsupported format or type.

The queued key store now takes a snapshot of the key bytes at record time and
the batch stores the 0xff pattern through the changed-copy kernel, so a dword
the CPU wrote after the record keeps the CPU's value. A range whose only
pending writers are earlier 0xff fills of the same keys stays guarded (the
kernel need not repeat them); a pending kernel of the title writing the keys,
or a range without a device address or a snapshot, is filled as before. The
[labels] line counts the guarded stores; APS5_NO_GUARDED_KEY_STORE=1 restores
the fills.
…hat precedes it

The publish of the key range's edge units notes a pending write over the keys,
which made the key store queued right after it fall back to the plain fill.
The publish leaves the key bytes as they are (its slab holds the seed the
import had), so the store's snapshot stays exact: publishes note their writes
with their own value and the key store treats them like its own fills.

(cherry picked from commit a3c8286502a94b13d2fb7676a76c82e87f677d76)
…ded before it

A title's DCC key clear is a recorded fill of a known value over the keys. The
key store queued behind it saw a pending writer it did not know and fell back
to the plain fill, which was a third of the stores in PPSA15304 after boykopovar#5520
and brought the descriptor faults back.

The snapshot now predicts the import: the bytes read at queue time with every
pending fill of a known value applied in note order, so the kernel stores the
0xff pattern over the clear's bytes and still keeps a CPU store made after the
record. APS5_TRACE_KEY_GUARD=1 prints the pending writers of the stores that
stay unguarded. The test records a key clear before the store and expects the
keys stored, then a late CPU store kept.

(cherry picked from commit 3da4934731c9231976f395b8f517bd2b03578968)
…to the CPU

The guarded key store stored the 0xff pattern wherever the import still
held the snapshot's value, so a CPU store of the value the keys already
held (zeroing reused memory that was zero) read as untouched and was
overwritten.

The queued store now collects the guest writes of its range before taking
the snapshot and keeps that generation. When the store is recorded, every
64 KiB block of the range the CPU wrote since then is left as the CPU left
it, and the kernel only runs over the other blocks, so a store is kept
whatever value it wrote. Without write watching the value compare stays
the only guard. The [labels] line counts the key blocks left to the CPU.
The test places the keys across a block boundary and adds a late store of
the value the keys held.
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 15, 2026
@ee6aba54
ee6aba54 force-pushed the fix/agc-key-store-guard branch from dea2cda to 1b755cb Compare October 15, 2026 14:15
@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 15, 2026
@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 18, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 20, 2026

This branch has not been deployed

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

Labels

agc libSceAgc* build 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.

3 participants