Skip to content

perf(agc): copy small draw snapshots into a per-recorder upload chunk - #6082

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-draw-snapshot-upload-chunk
Oct 18, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
meh7an:perf/agc-draw-snapshot-upload-chunk

Conversation

@meh7an

@meh7an meh7an commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

What

ShaderResources::PrepareDrawBindings snapshots each guest buffer that a draw reads in place. Since #5906, a snapshot that nothing wrote since the last draw is reused from a per-recorder map (Recorder::UnwrittenDrawSnapshot). On a miss, the draw still collects the range's writes, looks for a kept copy (Recorder::ReusableDrawSnapshot), and otherwise creates a buffer for the copy and keeps it. Most of these ranges are small.

On the S2 page of Sonic Origins Plus's main menu, with #5906, PrepareDrawBindings costs the queue worker 5.22 samples per frame (APS5 sampler, 15 s). Of that, 0.78 goes to Buffer::Buffer, 0.56 to ReusableDrawSnapshot, 0.35 to KeepDrawSnapshot and 0.29 to CollectWrites.

A miss of at most 4 KiB is now copied into a per-recorder upload chunk (Recorder::DrawUpload) and bound at its offset. The chunk is 1 MiB, bump-allocated at the storage buffer offset alignment. The copy skips the collect, the lookup and a buffer of its own.

  • DrawBindings::Snapshot gains the offset and size of its bytes in buffer. The descriptor write and the capture inputs use them.
  • perf(agc): reuse draw snapshots across draws that nothing wrote between #5906's map keeps the offset with the buffer, so a later draw reuses the copied slice the same way.
  • The copy is noted in that map only within a collect epoch (CollectEpoch() != 0), where the queue worker's collects are memoized the same way. A thread without one copies again on every draw.
  • Larger snapshots and moved words take the existing paths.
  • APS5_DRAW_UPLOAD_MAX changes the limit, and 0 turns this off.

With the chunk, PrepareDrawBindings fell from 5.22 to 3.20 samples per frame:

  • Buffer::Buffer 0.78 to 0.31
  • ReusableDrawSnapshot 0.56 to 0.03
  • KeepDrawSnapshot 0.35 to 0.01
  • CollectWrites 0.29 to 0.11

Tested

Windows 11 (10.0.26300), WinLibs GCC 15.2.0 (UCRT), Release, NVIDIA GeForce RTX 2080 Ti, driver 617.14.

  • On main d92a8da with this change, the full ctest suite passes (1253 tests).
    • agc_draw_snapshot_cap now also runs drawSnapshotUploadTests. It checks that inputs up to the limit share the chunk at aligned offsets with their guest bytes, and that a larger one gets its own buffer. A copy made after a CPU store gets a new slice without touching the slice an earlier draw reads, and a full chunk is replaced.
    • unwrittenSnapshotTests checks that the map keeps the offset.
    • The snapshot tests of agc_driver_recorder_tests's unregistered default path read a snapshot through its offset now: resourceReadTests, misalignedRegionTests and misalignedSnapshotTests. drawSnapshotReuseTests covers the kept-copy path, so its input is now 8 KiB, above the limit. No ctest entry runs that path; run through a local flag, its snapshot tests pass on that main with this change. On Windows, drawSnapshotReuseTests, drawSnapshotPatchTests and the kept-indices part of drawInputInPlaceTests stop early: host imports are compared there, not watched.
  • Sonic Origins Plus, main menu, S2 page (the 3D background), 1233x694 window.
    • Captured with APS5_TRACE_SECONDS=200:15 on the same machine in one session, caches warm. Traces attached.
    • Both captures ran one build. The baseline turns the chunk off with APS5_DRAW_UPLOAD_MAX=0; this change uses the default limit:
Metric Baseline This PR Change
frame_ms.p50 142.300 136.092 -4.4%
frame_ms.p90 148.909 140.703 -5.5%
mean_frame_ms 143.817 137.142 -4.6%
gpu_busy_ms_per_present 83.726 84.797 +1.3%
Driver.Packet (ms per frame) 141.207 134.532 -4.7%
Graphics.Draw (ms per frame) 60.930 54.816 -10.0%

The FPS shown in the title went from 7.35 to 7.84 (median of six readings). The sampled runs agree: 7.28 to 7.72.

Note: measuring base. These numbers come from my fork's dev, on main 0a56aaa, the last main before #5596. On Windows, later mains compare direct imports on every use, which keeps this menu at 3-4 FPS and hides a change of this size. The build is measure/tape-2026-10-14 (b593e36; its summaries say a38ad5e, the same tree with a test-only fix folded in), plus #5906 ported and this change adapted to it. That patch is measuring-build.patch in the attached zip. The base therefore carries, in both captures:

The comparison tool marks two configuration differences: APS5_DRAW_UPLOAD_MAX, which is the change under test, and the window's first present (2593 vs 2471), because the window opens 200 s into each run. Both summaries set trace_dropped, because the worker filled its event buffer at about 2,700 draws per frame. The phase totals above stay complete. Both summaries also say dirty: the patch above was applied, not committed.

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: none
  • GPUs tested: NVIDIA GeForce RTX 2080 Ti, driver 617.14, Windows 11
  • AI-assisted: yes

Traces, summary lines and the measuring patch (one build; baseline APS5_DRAW_UPLOAD_MAX=0, this change the default):
snapshot-5906-traces.zip

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed agc libSceAgc* labels Oct 14, 2026
@meh7an
meh7an force-pushed the perf/agc-draw-snapshot-upload-chunk branch from 6ef1382 to e9bcecb Compare October 15, 2026 05:44
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 15, 2026
This was referenced Oct 15, 2026
@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 7484 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp L5085

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
PR 1368 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5021 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 5441 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5499 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 5609 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 5925 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6177 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6185 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6222 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6279 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6360 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6412 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6414 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6481 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6490 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6499 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6529 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 6539 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6658 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 6747 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6763 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6868 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6905 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 6937 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6971 core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7002 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
PR 7085 core/libs/prx/libSceAgcDriver/Graphics/src/Draw.cpp
PR 7332 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/Recorder.cpp
docs/dev/ENVIRONMENT.md
PR 7390 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7464 core/libs/prx/libSceAgcDriver/Graphics/include/Recorder.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/Recorder.cpp
PR 7515 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the diff against main: upload slices are bump-allocated and never rewritten (a full chunk is replaced and the old one stays alive through the snapshots that reference it), KeepBytes counts the chunk once per batch, the #5906 stamp is still checked after the copy, and the capture inputs and descriptor writes use offset + size. Linux build and the libSceAgcDriver ctest scope are green on RADV and lavapipe (only agc_driver_tessellation segfaults, as on main); agc_draw_snapshot_cap runs drawSnapshotUploadTests here. The measured gain is the author's Windows/NVIDIA run, not reproduced here; merging through the full Build.

@adriadam10
adriadam10 force-pushed the perf/agc-draw-snapshot-upload-chunk branch from e9bcecb to 3518eb8 Compare October 18, 2026 16:38
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@adriadam10
adriadam10 merged commit 218aa8f into boykopovar:main Oct 18, 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*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants