Skip to content

perf(agc): fewer heap allocations per recorded draw - #6566

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
TheAggie:perf/agc-draw-fewer-allocations
Oct 19, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
TheAggie:perf/agc-draw-fewer-allocations

Conversation

@TheAggie

Copy link
Copy Markdown
Contributor

What

On a title whose draws all hit the draw cache, the committer's time per draw is mostly small costs that repeat for every draw. Counting heap allocations with a hook on the driver's operator new imports showed about 135 per draw (with the relocation PRs' own share already pooled) on Ratchet & Clank under RetroArch's PCSX2 core, at roughly 0.1 µs each on two threads sharing one heap. This PR removes the ones in the committer's draw path that need no change of behaviour:

  • DrawResourceKey builds the key in place, reserving its size: ShaderResources::AppendContentKey writes a shader's content key into a caller's vector, and ContentKey keeps its by-value form on top of it.
  • GuestBufferMemory::InPlaceReads and DeviceReads get overloads that fill a caller's vector; the by-value forms stay. The committer's pass reads and PrepareDrawBindings' in-place reads come from the thread's scratch.
  • PrepareDrawBindings built two VkDescriptorSetLayoutBinding vectors a draw only to test them for emptiness, a std::map of descriptor counts a set, two pool-size vectors, and copies of the descriptor buffer and write lists. The emptiness is a flag, the counts are a small sorted vector in thread scratch, and the buffer and write copies and the snapshot index list reuse thread scratch (ShaderRecompiler::ThreadOwned, as the selected-slot list there already did). The copies are still copies: the writes are patched per draw before vkUpdateDescriptorSets.

Related: #6312 cuts other allocations of the same draw path (the decode's program copy, the validation key, the moved words, the decode reads, ShaderMemory's regions, and reserves in Driver::draw). This PR is the committer's resource key, read lists and descriptor bookkeeping, which #6312 leaves as they are; the two meet only textually, in neighbouring lines of PrepareDrawBindings, and whichever lands second rebases.

No pointer into the scratch outlives the call that fills it: the pass reads are consumed by StartDrawPass/LeaveRenderPassOpen (PassHazards copies what it keeps), and the descriptor writes by vkUpdateDescriptorSets.

Tested

Windows 11, NVIDIA GeForce RTX 5070 Ti, MinGW-w64 GCC 15.2.0, on main ce991f1ec.

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 in TechnicalDebt
  • 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
  • AI-assisted: yes. Written with Claude Code under my direction.

🤖 Generated with Claude Code

The committer built a recorded draw's resource key through two temporaries a shader, took the in-place and device read lists by value, and in PrepareDrawBindings built two layout-binding vectors only to test them for emptiness, a std::map of pool sizes a set, and copies of the descriptor buffer and write lists, all on every draw. The key is now built in place with its size reserved, the read lists fill a caller's vector, and the per-draw bookkeeping lives in the thread's scratch (ThreadOwned), as the selected-slot list already did. The queue worker's program list and memory snapshots reserve their size up front.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 6636 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp L331
PR 6661 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp L5239-5240, L5243-5252, L5255-5256, L5260-5261, L5265-5267

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 1191 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1324 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1368 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 2434 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 4448 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/Graphics/src/GuestBufferMemory.cpp
PR 5372 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5499 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6146 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6185 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6292 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6340 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6548 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6612 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6615 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6639 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6647 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6683 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6718 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6727 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6763 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6786 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6801 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6820 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6937 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6946 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6947 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6970 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6972 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7154 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7201 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7233 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7254 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7258 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7292 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7332 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7340 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7369 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7390 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7473 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7484 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7618 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7650 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7689 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp

@mrfelek

mrfelek commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Diablo II: Resurrected in gameplay: +6% with this PR stacked with #6312, #6617 and #6733 (Linux)

Setup:

Ryzen 9 5950X, RTX 3080 Ti (NVIDIA 615.71.09), Ubuntu 26.10 (kernel 7.3), GCC 15.3, Release
Diablo II: Resurrected (PPSA03912), character loaded, standing still, no input
base:  main 40255d774
stack: main 40255d774 + #6312 (ecda2b18c) + #6566 (4f8c8b127) + #6617 (74dad0097) + #6733 (92e5b971c)
env:   APS5_HOST_IMPORT_MIB=16384 APS5_THREAD_PRIORITY=high APS5_PROFILE_DRAW=1
each run: 60 s after the character loads, then the mean of 18 [present] windows (180 s)

Presents per 10 s, runs alternated:

run main + stack
1 46.2 49.8
2 46.9 48.8
mean 46.5 49.3 (+6.0%)

AI-assisted: yes (Claude Code)

EagleBearerYS added a commit to EagleBearerYS/AnyPS5 that referenced this pull request Oct 17, 2026
The scan tests' includes now sit before <array>, where boykopovar#6706 and boykopovar#5859 add theirs after it, and the pass counter's address flag is set after the read-only check instead of next to the pass reads boykopovar#6566 rewrites. No behaviour change.
@github-actions github-actions Bot added perf Performance change perf numbers missing perf pull request without a before and after summary line labels Oct 18, 2026
@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10
adriadam10 merged commit c1ca834 into boykopovar:main Oct 19, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* perf numbers missing perf pull request without a before and after summary line perf Performance change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants