Repository navigation
perf(shader): store multi-dword global writes with one BDA lookup - #2305
Merged
Merged
Conversation
This was referenced Oct 9, 2026
A global_store_dwordx2/x3/x4 was split into one StoreAddressU32 per dword, each with its own write-pointer lookup and its own 4-byte store. Across a wave those are strided partial writes, which are very slow to host memory: RADV's clear_htile_mask kernel (one dwordx4 load and store per thread over 640 KiB) took ~9 ms. Multi-dword stores are now one StoreAddressU32xN; the emitter probes the whole span once and, when it is mapped writable and 4-byte aligned, stores it as one vector (16- or 8-byte aligned) or as consecutive dwords, noting each written page. Anything else takes the per-dword path as before, so faults and range-spanning stores behave as they did. APS5_BDA_DWORD_STORES=1 restores per-dword stores. AI-assisted (Claude Code). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TheAggie
force-pushed
the
perf/shader-wide-bda-stores
branch
from
October 10, 2026 06:00
0db6558 to
b958425
Compare
Collaborator
|
Checked on Linux (RADV): scoped build and ctest of libSceAgc + libSceAgcDriver (326 tests) green, including |
9 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A multi-dword global or flat store (
global_store_dwordx2/x3/x4) was translated as oneStoreAddressU32per dword. Each dword got its own write-pointer lookup and its own 4-byte store. Across a wave those are strided partial writes, every lane writing one dword out of each 16 bytes per instruction, and partial writes to host memory are very slow.RADV's
clear_htile_maskkernel (17 instructions: oneglobal_load_dwordx4,v_and_or_b32×4, oneglobal_store_dwordx4per thread) took ~9 ms for 640 KiB on an RTX 5070 Ti. In vkQuake (PPSA99010) it runs three times per frame, which made it 4.6 s of every 10 s of GPU time. Loads already avoid this: a multi-dword load is oneLoadAddressU32xNthat resolves the span once (EmitBdaDwordReads).StoreAddressU32x2/x3/x4(Void, address resource,U32xNdata) for a multi-dword store outside scratch, with the same group memory metadata as the wide loads.APS5_BDA_DWORD_STORES=1keeps oneStoreAddressU32per dword.EmitBdaDwordWritesprobes the whole span once with a new non-faultingprobe_bda_write_pointer(write permission). When the span is in one writable range and both the guest and device addresses are 4-byte aligned, it stores the dwords from that one pointer: one vector store when the device address is 16-byte (x4) or 8-byte (x2) aligned, otherwise consecutive dword stores. It then notes the written page, and the last dword's page too when that differs.EmitBdaStorepath, so faults and their order, byte stores for unaligned addresses and range-spanning stores behave exactly as before.Tests:
RunBdaDwordWriteTests(agc_driver_bda_device), through the emitter: 16-byte-aligned x4, 4-byte-aligned x4, aligned and unaligned x2, x3, x4 and x2 across a 4 KiB written-page boundary, an unaligned x4, an x4 across two writable ranges (no fault), and an x4 whose last three dwords are read-only (first dword stored, Permission fault as before). Each checks the stored bytes, the neighbouring bytes, the fault state and the noted pages. Dropping the second page note, or storing the separate dwords one slot off, fails it.tests/execution/MaskedGlobalStore.cpp: RADV's 17-wordclear_htile_maskkernel, translated and dispatched (64 groups, wave64 and wave32), checks every dword of the buffer for the depth-clear and the expand masks. It passes with the wide path and withAPS5_BDA_DWORD_STORES=1.Tested
Windows 11 Pro (26200), MinGW-w64 GCC 15.2.0 (WinLibs r7), Release, NVIDIA GeForce RTX 5070 Ti (driver 610.88).
guest_sce_nettimed out (it times out locally on unrelated branches too, likely my network filtering). It was run from the generatedCTestTestfile.cmakecommands because antivirus blocksctest.exeon this machine.tools/check_conventions.py --base origin/mainpasses.clear_htile_maskkernel alone (640 groups over 640 KiB, a local timing harness): 9.1 ms per dispatch before, 0.54 ms after.APS5_PROFILE_GPU=1, on my local test branch (currentmainplus my open RADV PRs and local stubs): GPU time went from ~5,100 ms to ~290 ms per 10 s, GPU busy from 34 ms to 2.9 ms per frame, and ~19 to ~22 FPS (now CPU-bound). The RADV fill kernel also dropped from ~755 ms to ~40 ms per 10 s.Not tested on Linux or macOS.
#1265 (loops the BDA byte stores) and my #1280 (stacked on it; changes
note_bda_write) touch the same store helpers inSpirvBdaRead.cpp. I'll rebase onto whichever lands first.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code