Skip to content

perf(agc): refresh pure data words of a cached draw stage instead of recapturing it - #6093

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
adriadam10:perf/draw-cache-data-hits
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
adriadam10:perf/draw-cache-data-hits

Conversation

@adriadam10

Copy link
Copy Markdown
Collaborator

What

A draw stage whose captured words differ from a cached variant only at pure data positions is now a draw-cache hit: the live words are patched into the cached compiled result instead of capturing and materializing the stage again. This is the dispatch cache's EqualData hit (DispatchLookup.cpp) ported to draws.

  • Insert (cacheDrawStages): each stage records its pure data positions from its resource capture (DataWordPositions on the flattened SRT binding), minus the words the draw decode reads (decodeReads), so a word that drives the decode, an address or a descriptor is never refreshed.
  • Lookup (validateVariant): a stage that differs only at those positions returns EqualData; lookupDraw builds the stage's live words and patches them with patchDataWords, now shared with the dispatch path (moved out of DispatchLookup.cpp, same behaviour).
  • A patched draw takes no draw recipe (the recipe holds the unpatched build).
  • APS5_NO_DRAW_STAGE_DATA_HITS=1 turns it off (also off under stamp validation). APS5_VERIFY_DRAW_DATA_HITS=1 (the existing switch of the data-only hits) builds the stage anyway and throws if runs, words, variant, push constants or bindings differ from the patched result.
  • APS5_PROFILE_DRAW=1 gets a line [draw-cache] stage data hits (10 s): ... (stages hit, words refreshed, verified, inserts with data positions).

Why: on titles whose draw keys repeat but whose constants change every draw, the stage misses on its data and the whole capture runs again. Reports in #1201 (front end ~110 ms/frame vs ~32 ms in Graphics::Draw), #4943 (Besiege, Diablo II, Minecraft Dungeons II, Hades II) and #494 (Hades II) name this step: refresh the constants in a cached stage instead of comparing them. #494 covers changed user words, #4943 equal contents behind moved pointers, #5609 bound buffer bases; this covers the data words themselves. Pure data words only: V# bases are not refreshed here.

Template resources: with movable buffers (the default) a template hit already refreshes data-role bindings through MovedReadOnlyBuffers, which compares their words with the (patched) descriptor, so a refreshed constant reaches the GPU without a new template.

Tested

Linux, AMD Radeon 660M (RADV, Mesa 26.2.4).

  • New case StageDataHitsRefreshTheirWords in agc_driver_draw_cache_reuse (and its _off/_verify runs): a pixel shader reads a constant through its user words; three draws at 0.25 insert once and hit once (colour 64), then the constant becomes 1.0 and one draw is a hit with 1 stage data hit / 1 word refreshed, no insert, colour 255. With APS5_NO_DRAW_STAGE_DATA_HITS=1 it misses on the fragment stage and still draws 255; with verify the hit is checked once. The colour check needed a triangle that covers pixels and GuestMemory::FlushGpuWrites before reading the target, so the case has its own vertex shader.
  • Mutations, each failing the test: drawing with the unpatched compiled result (colour stays 64); not accepting EqualData (counters); not copying the live words (verify throws differs ... in its words).
  • Full ctest -R '^agc' before and after rebasing on main: everything passes except agc_driver_tessellation (fails on main too) and agc_driver_preparation_scope_settle under -j4 (passes 15/15 alone; also red in an unrelated train run 38623010537).
  • No in-game numbers: this machine can't run titles. Profile lines (APS5_PROFILE_DRAW=1, the new stage data hits line) and one APS5_VERIFY_DRAW_DATA_HITS=1 run with no throw on Astro's Playroom / Besiege / Diablo II would be welcome.

Checklist

…recapturing it

A draw stage whose captured words differ from a cached variant only at pure
data positions (read by the shader as data, never as an address, descriptor
or decode input) is now a hit: the live words are patched into the cached
compiled result, as the dispatch cache's EqualData hits do. The positions are
recorded at insert from the stage's resource capture, minus the words the
draw decode reads. Patched draws take no draw recipe.

APS5_NO_DRAW_STAGE_DATA_HITS=1 turns it off; APS5_VERIFY_DRAW_DATA_HITS=1
builds the stage anyway and throws on any difference. The draw-cache profile
line counts stage data hits and refreshed words.

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

github-actions Bot commented Oct 14, 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
#5631 core/libs/prx/libSceAgcDriver/tests/execution/DrawCacheReuse.cpp L127, L151
#5897 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Draw/DrawCapture.cpp L76

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant