Skip to content

perf(agc): take a dword fill of any inline constant as a buffer fill - #5380

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
AlxcBTW:perf/agc-constant-dword-fill
Oct 14, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
AlxcBTW:perf/agc-constant-dword-fill

Conversation

@AlxcBTW

@AlxcBTW AlxcBTW commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

What

A dword fill whose source is an inline integer constant other than zero is stored as a buffer fill, like the zero fill already is.

MatchZeroDwordFill (v_mov_b32 v1, 0; buffer_store_format_x) becomes MatchConstantDwordFill: the same 6-word kernel with any inline integer constant as the source (0 to 64 and -1 to -16). Float inline constants and vector registers are not matched. The fill then takes the existing dwordFill path with the constant as its pattern. Run as compute dispatches, these writes are pending writes of unknown value, so a later read of DCC keys over their range waits for the dispatch (#3505). Sword of the Sea clears DCC keys with this kernel.

Rebased onto current main after #4603 merged; the diff is this one commit (b83755ac9). Fork CI for this head: run 38499865909: Linux and Windows green.

ZeroDwordFill is renamed ConstantDwordFill and gains match and execution cases for 1, 64, -1 and -16, a float constant and a vector register; the one-bit mutation check now flips a bit outside the source operand.

Measured

Indication only, from our lab line (RTX 5070 laptop, Windows, Sword of the Sea, APS5_PROFILE_DRAW=1, 10 s windows). These are two lab rows that differ in other levers, not a controlled A/B, and this PR is not what they measured on its own:

  • m3-reckless1 (cutscene, t360-t895): draw readTarget 4.3 s per 10 s, 2.30 FPS.
  • m3-reckless4 (same scene, t240-t480, with the DCC-key fills of this PR and perf(agc): take the memory-value dword fill kernel as a buffer fill #4603): readTarget 235 ms per 10 s, 2.88 FPS (reckless1 over the same frames: 2.2).
  • Menu: key-writer waits about 970 (2.4 s) per 10 s before the fills, about 90 after.

Motivation, measured by @parl0v on current main (box 2, APS5_PROFILE_DRAW=1): cutscene readTarget 997.5 ms per 10 s (15,560 lookups walking 3.74 M pages) and main menu readTarget 1,877-1,902 ms per 10 s, 86 % of draw time (AlxcBTW#44 (comment), AlxcBTW#44 (comment)).

I have not run the game on this branch.

Tested

CI only, no local build and no local GPU run. Fork CI (Linux and Windows jobs: configure, test registration check, build, libs, ctest) on ci/lab/constfill = this branch plus three lab workflow commits: all green (run 38444188620). tools/check_conventions.py passes locally.

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 (recognises a compiler-emitted fill kernel wherever it occurs; first seen in Sword of the Sea)
  • Depends on: none (perf(agc): take the memory-value dword fill kernel as a buffer fill #4603 is merged)
  • Unblocks: none
  • GPUs tested: n/a locally; the CI GPU tests skip without a Vulkan device
  • AI-assisted: yes

🤖 Generated with Claude Code

@parl0v

parl0v commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Ran this branch in the game. PPSA25344 (Sword of the Sea) title screen, RTX 3060 12 GB / i5-12400F / 32 GB, Windows 10, NVIDIA 617.42. This branch (8f2637543, so #4603 + this commit) against its base 18c438b10, same relinked executable, APS5_PROFILE_DRAW=1, 300 s runs, mean of the last twelve 10 s windows:

run FPS GPU busy / present draw readTarget per 10 s pages walked per 10 s
main 7.32 94.4 ms 1,034 ms 6.95 M
this PR 7.80 93.7 ms 535 ms 7.26 M
main, again 7.42 94.3 ms 1,027 ms 6.95 M
this PR, again 7.69 93.6 ms 528 ms 7.16 M
  • readTarget halves and the title screen gains ~5 % (7.37 → 7.75 FPS). Pages walked don't drop, so the saving is the waits on the DCC-key fill dispatches, as described, not the walk.
  • Frame dumps: mean difference 0.16 (of 255) against this PR's main, vs 0.13 between two runs of this PR. No visible change.

@MarcZX10

Copy link
Copy Markdown
Contributor

I checked the hosted check state: the only run of conventions is red, while intake, eligibility and report pass; the build matrix was skipped for this path. I could not retrieve the conventions job log because GitHub returned HTTP 502 for the run details, so I cannot identify the failed rule. Please inspect that log and rerun after addressing it. The overlap check also flags the shared BufferFill.cpp hunk with #5313; please verify merge ordering when either change lands.

@MarcZX10

Copy link
Copy Markdown
Contributor

I was able to retrieve the conventions log now. Its only finding is the unchecked generic-behavior checklist item. The implementation description appears title-agnostic: it recognizes the same compiler-emitted buffer-fill pattern wherever it occurs, with Sword of the Sea as the first observed case. If that is accurate, please state that clearly and check the item; otherwise explain the title-specific scope without making a false checklist claim, then coordinate with the maintainers on the repo rule and rerun conventions.

@AlxcBTW

AlxcBTW commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

@MarcZX100 thanks for digging out the log. Ticked: the change matches the compiler-emitted dword-fill kernel wherever it occurs, and Sword of the Sea is just where it was first seen.

The zero fill kernel (v_mov_b32 v1, 0; buffer_store_format_x) is also emitted with other inline
integer constants as its source. Run as compute dispatches, those writes are pending writes of
unknown value, so a later read of DCC keys over their range waits for the dispatch. A constant of
0 to 64 or -1 to -16 is now matched like the zero fill and stored as a buffer fill of that value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the kernel encoding (SRC0 0x80 = 0, 0x81..0xc0 = 1..64, 0xc1..0xd0 = -1..-16; float inline constants and VGPR sources are rejected), the match tests with a bit flipped outside the source operand, and the execution cases for 1, 64, -1 and -16 against the Vulkan device (agc_driver_constant_dword_fill passes). Also confirmed by @parl0v on PPSA25344 (readTarget 1,034 → 535 ms per 10 s). Merging once the full Build is green.

@adriadam10
adriadam10 merged commit 3b1ea78 into boykopovar:main Oct 14, 2026
10 checks passed
bubblegg added a commit to bubblegg/AnyPS5 that referenced this pull request Oct 14, 2026
Conflicts kept our shared stage results in the draw path (upstream's boykopovar#5687 is
the same change), our clean-range skip beside upstream's collectable-range memo
and ordered view lookup in WindowsMappings, and our single-sample MSAA mode,
under which upstream's dithered alpha-to-coverage emulation stays off.

Nonzero constant dword fills (boykopovar#5380) do not mark the images over their keys as
filled, as for the source fill kernel: they were dispatches before. Our SSL
connect, read and write keep returning the network error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agc libSceAgc* docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants