Skip to content

perf(agc): read DCC keys from the pending GPU fills that cover them instead of waiting for the fills - #5520

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
Nesyth:perf/agc-dcc-keys-from-pending-fills
Oct 14, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
Nesyth:perf/agc-dcc-keys-from-pending-fills

Conversation

@Nesyth

@Nesyth Nesyth commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

What

A DCC key read that finds recorded GPU writes over the keys waits for the GPU unless the key-store memo holds one entry covering all of them. Keys filled in parts, a fill over part of the keys whose other part already holds the same byte, fills the fill HLE did not take as key fills, and keys under a unit shadow all wait, although the recorded fills already say what the keys will be. This change answers those reads from the recorded writes. In Ready or Not on main the GPU waits for DCC keys drop from 16.9 to 8.5 ms per frame, but the FPS doesn't move, because a buffer copy that #5372 fixes takes most of each frame there. On my Ready or Not bring-up build, an older base with other local changes, the slow color-target lookups went from 28.7 to 3.9 ms per frame over three steps, two of them this change's commits (table below).

  • When the newest recorded writer of every key byte is a fill of a known byte, or a byte has no recorded writer and is read from memory, the read returns what the writes will leave: one byte for all keys gives those keys, two different bytes give mixed keys. There is no GPU wait.
  • When the newest writer of some byte stores unknown bytes (a kernel, a copy, a label), the read waits as before. fix(agc): wait for recorded writes over a sampled texture's DCC keys before reading them #4554's wait for keys a kernel writes is kept. perf(agc): read DCC keys behind a pattern fill kernel's fast clear without a wait #5497 covers a different case, keys behind a pattern fill kernel's fast clear, through the memo; the two complement each other.
  • Sampled textures and storage images read their keys through the same path, so they get these answers too.
  • A unit shadow over the keys is published first. A stale one is dropped and the fills answer; a fresh one is copied into the import, and the read waits for that copy instead of draining the recorder.
  • The walk reads memory only when the whole key range is accessible; otherwise the read waits and returns unreadable keys, as on main. Writes are ordered by when they were recorded, as the memo already assumes.

Tested

Windows 11 Pro 10.0.22631, Ryzen 7 7800X3D, RX 7900 XTX, WinLibs GCC 15.2.0, Release, on main 0aa4cb1.

  • pendingKeyStoreTests gets its own ctest, agc_pending_key_stores, with new cases for fills over both halves of the keys, a later writer of unknown bytes, a fill over half of uncompressed keys, and keys that run past the end of committed memory.
  • agc_driver_dcc_keys_first_write now expects no wait where real GPU fills settle a storage image's keys, still expects one where a kernel's store is the newest writer, and checks the landed key bytes after each read.
  • New test shadowedKeyStoreTests in tests/Recorder.cpp (ctest agc_shadowed_key_stores): keys under a fresh unit shadow are published and read after a wait, a fill over a stale unit shadow answers without a wait, and the stale slab is never published.
  • Reverting each part of the change makes its test fail.
  • ctest -R "^agc_": 482 of 485 pass and 2 skip. agc_driver_layered_volume_vertex_no_gpl fails, as it does on main on this GPU.
  • Ready or Not (PPSA18605) on main 0aa4cb1, all libraries built from it and only the driver swapped, same scene, one run each, 30 s profiler windows. In this scene main copies a 768 KiB buffer on most draws (the case perf(agc-driver): join every range a bound buffer crosses #5372 fixes), so a frame takes about 500 ms of queue-0 time and the FPS does not move:
FPS queue 0 per frame GPU waits for DCC keys per frame slow color-target lookups (1 ms or more) per frame
without 1.97 503 ms 13.7 waits, 16.9 ms 7.6 lookups, 23.7 ms
with 1.97 503 ms 8.9 waits, 8.5 ms 6.1 lookups, 17.7 ms

The frames match within the difference between two runs of the same build. With this change a texture whose pending fills leave mixed keys logs the existing "has mixed DCC keys ... read as stored" line; main reads it as stored too, without the line.

  • Ready or Not (PPSA18605) on my bring-up build, same scene, each build alternated with the same baseline build, 30 s profiler windows. Slow lookups are color-target lookups of 1 ms or more, per frame:
build runs FPS (baseline in the same batch) slow lookups
baseline 16 4.46 28.7 ms
+ first commit and a fill-kernel change like #4603/#5380, not split 4 4.46 (4.38) 22.1 ms
+ the comp-to-single GPU upload, a separate change 4 4.61 (4.47) 15.8 ms
+ second commit 4 4.96 (4.51) 3.9 ms

Linux: not run.

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: PPSA18605 Ready or Not (PPSA18605) #4184
  • GPUs tested: AMD Radeon RX 7900 XTX, AMD Software Adrenalin 26.8.1 (driver 32.0.31041.1004), Windows 11 Pro 10.0.22631
  • AI-assisted: yes

@MarcZX10 MarcZX10 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.

Reviewed the newest-write range overlay and its fallback: later writes shadow earlier ranges, unknown stores fall back to synchronization when the pending values cannot be established, and inaccessible ranges do not get read speculatively. The added cases cover partial fills, mixed values, unknown writers and shadowed keys. The report provides Windows RX 7900 XTX test evidence; the current automated eligibility, conventions, intake and report checks pass, while Linux/full-build jobs are skipped and Linux was not run. I found no code-level blocker based on the submitted evidence.

@github-actions github-actions Bot added build agc libSceAgc* labels Oct 13, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@adriadam10 adriadam10 self-assigned this Oct 14, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Rebased onto current main (conflict in tests/Recorder.cpp: the two --*-only blocks in main() were kept, no logic changes). Checked on the rebased tree: libSceAgcDriver build + ctest green (agc_driver_tessellation segfaults on main too); agc_pending_key_stores, agc_shadowed_key_stores and agc_driver_dcc_keys_first_write fail with DccMetadata.cpp reverted. Merging once the Windows build is green.

@adriadam10
adriadam10 force-pushed the perf/agc-dcc-keys-from-pending-fills branch from 2a95722 to 838c1ca Compare October 14, 2026 10:48
@adriadam10
adriadam10 merged commit 23be5a0 into boykopovar:main Oct 14, 2026
8 checks passed
ee6aba54 added a commit to ee6aba54/AnyPS5 that referenced this pull request Oct 15, 2026
…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)
ee6aba54 added a commit to ee6aba54/AnyPS5 that referenced this pull request Oct 15, 2026
…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)
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants