Repository navigation
Conversation
The hardware hands out an ordered-append counter in wavefront launch order. Compute waves now wait for a turn dword kept past the 64 KiB GDS to reach their launch index (flattened workgroup ID times waves per workgroup plus the wave index), perform the add or swap, and pass the turn on when the wave-done bit is set; the last wave of a dispatch resets it. The wait is bounded so a wave that never issues a done operation cannot hang the device. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@ZSWolt thanks, this is a good approach (the radeonsi-style turn past the GDS range, per-chunk reset for split dispatches, graphics left unordered, and a bounded wait so nothing can hang). One problem in the timeout path needs fixing before it can land: A wave that gives up waiting still moves the turn. The wait loop leaves on Please:
The debt entry already says that in-order launch and progress are assumed and that Vulkan doesn't guarantee them, which is right; please add what happens on a timeout after the fix. We'll run it on an RTX 4090 when it's updated (the |
|
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.
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.
|
A wave now passes the turn on with a compare-exchange from its launch index, so a wave that gave up waiting adds unordered and leaves the turn alone. The driver zeroes the turn in the buffer each dispatch binds, before the dispatch and each chunk of a split one, instead of relying on the last wave. Waves that give up are counted in a dword after the turn. The wait, the add and the release now run inside the loop, one lane per guest wave, so guest waves sharing a host subgroup no longer wait on each other until the timeout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@oneandonlydean thanks, all five points are addressed in the new commit on top (no force-push).
A second bug the multi-wave test found. When the host subgroup is wider than the guest wave (wave32 code in a 64-lane subgroup on RADV), two guest waves shared one wait loop. The first could not leave the loop to release until the second stopped waiting, so the second always timed out (29 timeouts in that test). The wait, the add and the release now run inside the loop, done by one lane per guest wave, so guest waves in one host subgroup no longer wait on each other. Checks (RX 9060 XT, RADV):
A run on the RTX 4090 would be welcome. The delayed and multi-wave cases are the ones that depend on the host's subgroup layout. 🤖 Addressed by Claude Code |
CnRJay
left a comment
There was a problem hiding this comment.
The ordering fix is sound, and oneandonlydean's timeout points are addressed. One cost in recordDispatch is not covered yet and applies to every dispatch that binds the GDS, not just ordered ones.
The reset is gated on bindsGds, not on orderedAppend. bindsGds is true for any shader with a DescriptorRole::Gds binding, which includes plain append/consume and any other GDS user. Those shaders never read the turn dword, but they now get:
vkCmdPipelineBarrierALL_COMMANDS→TRANSFERvkCmdFillBufferof 4 bytesvkCmdPipelineBarrierTRANSFER→COMPUTE_SHADER
ALL_COMMANDS as the source stage drains everything recorded before it: preceding draws, other dispatches and copies. Each such dispatch also becomes a hard sync point, so it can't overlap the work before it. The same is added before each chunk of a split dispatch. A title that issues many small GDS dispatches per frame (particle and culling passes are the typical case) pays a GPU drain for each one.
Carry the orderedAppend requirement into the compiled program, or the binding info, and reset only for programs that contain DataOrderedCount or DataOrderedSwap in a compute stage. Shaders that don't order then get exactly what main gives them.
The first barrier is wider than it needs to be. The only prior writer of the turn dword is an earlier ordered dispatch. A COMPUTE_SHADER → TRANSFER barrier with SHADER_WRITE|SHADER_READ → TRANSFER_WRITE covers that. ALL_COMMANDS / TRANSFER_WRITE also orders graphics work against the fill, which nothing needs.
Alternative that avoids the fill and both barriers. Have the shader own the reset. The wave holding the last launch index already compare-exchanges the turn to 0. With a launch-epoch dword that the host bumps once per dispatch through push constants, the compare-exchange targets epoch * stride + launch and no dispatch ever needs a zeroed turn. A timed-out dispatch then can't poison the next one either, and the fill and barriers go away.
CPU-copy path (zeroGuestBytes returning nullopt). The memset runs at record time, while the GPU may still be executing a previously submitted dispatch that uses the same CPU-made GDS copy. Two dispatches recorded back to back into one command buffer also both zero the turn before either runs. Please confirm that case can't happen, or say what guarantees it can't.
Wait loop. Each waiting wave does up to 2^20 device-scope acquire loads with no backoff. If one wave never issues the done operation (a divergent path where a whole guest wave skips it), every later wave in that dispatch spends the full budget. The test counts the timeouts (2 here), but nothing records how long a timeout costs on hardware that doesn't schedule groups strictly in order. On a 4090, include the time of the skipped-group case in the numbers; it matters for Windows TDR.
Measurement. The title numbers are the corrupted-frame counts and the present counts (851–857 against about 790). Please add tools/trace_digest.py summaries of main and of this change from the same machine and scene, with the frame time and the gpu_busy_ms_per_present of the GoW fireplace scene. Presents going up while a drain is added before every GDS dispatch is surprising, and the digest will show which phase moved.
The compiled program now records whether it orders GDS appends, and the driver resets the turn only for those, behind a compute-to-transfer barrier instead of draining all prior work. A GDS copy the CPU made is no longer zeroed at record time. The first wave that gives up waiting marks the turn abandoned, so the rest of the dispatch runs unordered at once instead of each later wave waiting a full budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ NVIDIA GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (5, not counted against this PR)Validation IDs already present on main (4 IDs in 397 tests)Skipped (40)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
|
@CnRJay thanks. All points are addressed in a new commit on top (no force-push). Reset only for ordering programs. The compiled program now carries Narrower barrier. The reset is now:
Epoch alternative. I kept the reset. An epoch needs a push word in every ordering program, bumped per dispatch, including dispatches replayed from recipes. A 32-bit turn of CPU-copy path. You're right, the record-time store was not safe to rely on, and it is removed. The reset is recorded only when the turn lives in an import or a GPU copy ( Wait loop cost. On an RX 9060 XT, 2^20 reads take about 130 ms. Your concern was right. I timed a dispatch where group 1 never takes its turn (a local timing build):
Before this commit, waves that launched after earlier ones had given up each waited a full budget again. Now the first wave that gives up marks the turn abandoned ( Measurement. A correction first: the earlier numbers in the description (851–857 presents against about 790, "on Plain
Where the time moved, per frame (
GPU busy per present drops by about 20 ms. My guess, not verified, is that the drop comes from the corrupted particle records: without the fix they are drawn as long streaks across the screen, which is far more raster work than correct particles. The traces dropped events after about 10 s on the busiest worker ( Checks on this commit:
TechLevelZero's NVIDIA run (RTX 2000 Ada) passed on the previous head, af3c0c1. 🤖 Addressed by Claude Code |
✅ NVIDIA GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (5, not counted against this PR)Validation IDs already present on main (5 IDs in 400 tests)Skipped (40)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
…d-append Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Windows data point to go with the RADV RX 9060 XT run: AMD Radeon RX 9070 XT (RDNA 4) on AMD's Windows driver 32.0.32015.7029, Windows 11 Pro 22631, MSYS2 UCRT64 GCC 16.1, Release, Tree:
I could not run the PR's test against AI-assisted: yes (Claude Code) |
✅ NVIDIA GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (4, not counted against this PR)Passed on retry (1, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)Validation IDs already present on main (3 IDs in 390 tests)Skipped (48)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
|
Windows GPU run of head Windows 11 Enterprise 10.0.22621, Ryzen 9 5950X, Radeon RX 6700 XT with AMD proprietary driver 26.10.1 (Vulkan 1.4.315), WinLibs GCC 15.2.0 UCRT r7, Ninja, Release,
AI-assisted: yes (Claude Code). |
|
NVIDIA on Windows, for head GPU: NVIDIA GeForce GTX 1650 (Turing,
Only this test target was built, not the full suite, and no title was run. AI-assisted. |
CnRJay
left a comment
There was a problem hiding this comment.
Thanks for the gate, the narrower barrier, the timing table and the correction of the present counts. One consequence of the CPU-copy change is not covered in your reply.
An abandoned mark is never cleared when the GDS binding is a CPU-made copy. The first wave that gives up stores 0xffffffff in the turn, and "the next ordering dispatch's reset clears the mark". For a CPU-made copy you no longer record a reset (FillTarget returns nothing), and you rely on the previous dispatch leaving 0. After a timeout it leaves 0xffffffff. The holder's compare-exchange cannot replace the mark, so every later ordering dispatch on that copy sees the mark at its first wait and runs unordered, with every wave counted as a timeout. That is main's behaviour, but it is permanent, and nothing in the log distinguishes it from a first timeout.
Please say which binding the GDS gets by default on the three platforms (import, GPU copy or CPU copy), since that decides how often this path is the one titles take. Then either:
- clear the mark from the CPU side when a CPU copy is bound and the timeout count has moved, before the next dispatch is recorded and with the previous submission retired; or
- refuse ordering programs on a CPU-made copy with a throw, so the gap is visible rather than a silent fallback.
A test that times out once and then runs a normal dispatch on a CPU-made binding would pin it. The existing "dispatch after a timeout" case runs on an import or GPU copy, where the reset covers it.
The frame-time table is what I asked for; gpu_busy_ms_per_present going from about 150 to about 129 ms with the change is a large move for a GDS-only fix, so it is worth a line saying which phase it comes from.
main moved the shader disk cache to format 56; this branch's ordered-append field moves it to 57. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ NVIDIA GPU test: passedPR head
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validation IDs already present on main (13 IDs in 543 tests)Skipped (49)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ NVIDIA GPU test: passedPR head
Unstable on main (4, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validation IDs already present on main (13 IDs in 549 tests)Skipped (49)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
✅ AMD GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (8, not counted against this PR)Validation IDs already present on main (8 IDs in 549 tests)Skipped (60)ReproduceAutomated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ NVIDIA GPU test: passedPR head
Unstable on main (3, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Passed on retry (1, failed in the parallel run, passed when re-run with a 360 s timeout; not counted against this PR)Validation IDs already present on main (9 IDs in 551 tests)Skipped (55)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
|
@XairRrR thanks for both re-checks and the approvals. One correction to my earlier reply: you're right that BunnyFl's failing run didn't log its driver, so I shouldn't have named Since then I've merged
For each merge, the build, the agc, shader and recompiler tests (1342 of 1342 for the latest), and @TechLevelZero thanks for the NVIDIA and AMD runs on each new head. The NVIDIA run on On CI: the macOS relinker failure on 🤖 Addressed by Claude Code |
|
Windows and NVIDIA Blackwell run, for head
The 3 failures fail on
The other 12 skips also skip on No title was run. AI-assisted: yes. Claude Code ran the builds and tests and drafted this comment; the numbers are from the runs on this machine. |
✅ AMD GPU test: passedPR head
Unstable on main (4, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (6, not counted against this PR)Validated but not compared (2, not in the main baseline's validation pass)Validation IDs already present on main (4 IDs in 593 tests)Skipped (62)ReproduceAutomated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@ZSWolt you're right about the driver, and sorry for the slow reply: your offer to reword the On the driver. My failing run did not log its driver. Naming On rewording the entry. I would not name Re-run at the current head, which is what I owed you. Head
One note on my own tooling rather than on this PR: in my first attempt What this does and does not settle. This machine is on the same driver as my 11-03 rerun, |
✅ NVIDIA GPU test: passedPR head
Failing on main too (3, not counted against this PR)Validation IDs already present on main (9 IDs in 595 tests)Skipped (56)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
BunnyFl
left a comment
There was a problem hiding this comment.
@ZSWolt approving at c95587e63b. My only formal review here is the 11-02 comment on 5332c91593 about the late row 0. The split-dispatch case now reports that case instead of failing, and my 11-06 rerun at this head passed. This adds the gated run with a negative control that I hadn't done.
What I ran. This head merged onto main 1ff0fe98aa (merge 98ea5d2326, clean), Windows 11 Pro, WinLibs GCC, Release, AMD Radeon RX 9070 XT (vulkaninfo: driverInfo 26.10.2 (LLPC), driverVersion 2.0.416), with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation and ctest -V:
agc_atomic_gds_size,agc_driver_gds_append_consume,agc_driver_gds_append_consume_copied,agc_driver_gds_dma_fill,agc_driver_gds_dma_fill_private,agc_driver_pm4andagc_guarded_memory_loads: 7 of 7 pass, none unbuilt or skipped. Both append-consume tests print the plaingds append consume tests passed, the empty-note branch atGdsAppendConsume.cpp:533-534; neither skip note fired.- No missing-layer line, no
VUID-and noSYNC-HAZARDids. - Negative control: the same merge with only
core/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpptaken frommainfails both append-consume tests, withgroup 0 lane 0 returned 1032, expected 1000 (the counter in launch order)andreturned 1012for the copied registration. The other five still pass.
Overlap, checked with tools/pr_overlap.py --branch at this head:
core/shader/recompiler/ShaderDiskCache.hppL16 (the cache format number) is shared with 13 open pull requests; whichever lands later takes the next number, as with your earlier merges.- #6146 changes
GuestBufferMemory.hppL607 onmain, which this branch also changes. Both are in the review queue; one of you will need to merge after the other lands. - #12840 shares
VulkanDevice.cppL5904 andShaderResources.hppL265, and #14247 sharesdocs/dev/debt/shader.mdL210-211. - 94 more pull requests touch the same files but conflict with
mainand could not be compared.
Approving.
AI-assisted: yes (Claude Code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
✅ NVIDIA GPU test: passedPR head
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)Failing on main too (3, not counted against this PR)Validation IDs already present on main (9 IDs in 599 tests)Skipped (55)ReproduceAutomated build and test on a contributor's NVIDIA machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs. |
|
@BunnyFl thanks for the rerun, the approval and the negative control. Taking only
@adam25136 thanks for the Windows run on the RTX 5080. It's the first result for a Windows head with a subgroup-32 NVIDIA driver, and it covers the @TechLevelZero thanks for the NVIDIA and AMD runs on every head, including On the hosted CI for 🤖 Addressed by Claude Code |
BunnyFl
left a comment
There was a problem hiding this comment.
@ZSWolt re-checked at 3f6d916dd5, and my approval stands.
3f6d916dd5 merges main (cefc546c86) onto c95587e63b, the head I approved. The PR's own +/- lines are identical at both heads in every file it changes.
What I ran
Windows 11 Pro 10.0.26300, WinLibs GCC 15.2.0, Release, this head merged onto current main (merge cefe4daece). The GPU is an AMD Radeon RX 9070 XT (0x1002:0x7550, Vulkan API 0x404167, as the test logs report it). Windows reports driver 32.0.32015.12012, read right after the runs; the logs don't print it. ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ctest -V, with the same seven tests as at my approval:
- PR:
agc_atomic_gds_size,agc_driver_gds_append_consume,agc_driver_gds_append_consume_copied,agc_driver_gds_dma_fill,agc_driver_gds_dma_fill_private,agc_driver_pm4andagc_guarded_memory_loads: 7 of 7 pass. - Negative control: the same tree with
main'score/shader/recompiler/SpirvBackend/src/SpirvMemory/SpirvMemoryInstructions.cpp.agc_driver_gds_append_consumeandagc_driver_gds_append_consume_copiedfail; 5 of 7 pass. - Neither log reports
was not found but was requested by env var VK_INSTANCE_LAYERS. Both have noVUID-and noSYNC-HAZARDIDs. tools/check_conventions.py --base upstream/main --headon this head: all checks pass.
Overlap
tools/pr_overlap.py --branch on this head:
- #6146 still conflicts at
Graphics/include/GuestBufferMemory.hppL607, as at my approval. - New since then: #12840 conflicts at
Execution/src/VulkanDevice.cppL5904 andGraphics/include/ShaderResources.hppL265. - 14 PRs change the same line of
core/shader/recompiler/ShaderDiskCache.hpp(L16), the shader cache format number.
AI-assisted: yes (Claude Code)
What
Background. On AMD GCN/RDNA GPUs, GDS (global data share) is a small on-chip memory shared by all waves of a dispatch.
ds_ordered_countis a GDS instruction that adds to, or swaps, a counter in GDS and returns the old value. Unlike an ordinary atomic, the hardware serves the waves in wavefront launch order: the first-launched wave gets the first value, the next wave the next, and so on. Shaders use it to give each wave a contiguous, ordered slice of an output buffer (stream compaction, particle lists, culling output). Because the order is guaranteed, the result is deterministic and the slices never overlap.The bug.
ds_ordered_count(ordered append on GDS) ran as a plain device atomic, so the waves of a dispatch added in whatever order the host ran them. The hardware hands the counter out in wavefront launch order. radeonsi'ssi_compute_prim_discard.c(mesa-20.3.0) describes it as "an atomic counter that is incremented in the wavefront launch order", withORDER_MODE 0launching in order. A title that turns the returned values into output offsets therefore got overlapping or shifted ranges, intermittently.In compute shaders the ordered add and swap now run in launch order:
RuntimeAbi::GdsMetadataDwords), the turn and a timeout count (Pm4::GdsBindingBytes). Ordinary GDS accesses stay bounded at 64 KiB; only the ordering code reaches the two dwords. The wait, the add and the release run inside one loop, so guest waves that share a host subgroup (wave32 code in a 64-lane subgroup) do not wait on each other.offset1bit 1 (wave done) is set, compare-exchanges the turn from its own index to the next (0 after the dispatch's last wave). Only the wave that holds the turn moves it.orderedAppend, disk cache format 57). For those programs only, the driver zeroes the turn in the buffer the dispatch binds, before the dispatch and before each chunk of a split one. It uses aCOMPUTE_SHADER→TRANSFERbarrier, a 4-bytevkCmdFillBuffer, thenTRANSFER→COMPUTE_SHADER. A GDS copy the CPU made is created fillable, so it is reset the same way. Each chunk counts its own waves.main), marks the turn abandoned so the rest of the dispatch runs unordered at once, and adds 1 to the timeout count, which the test checks. With one wave that never takes its turn, a 65536-group dispatch takes about 350 ms; without the mark it lost the device after 2 s.The wait relies on waves being launched in workgroup order and on earlier waves running while later ones spin. AMD hardware does this, but Vulkan does not guarantee it. This is recorded in
docs/dev/debt/shader.md, which now describes the new behaviour in place of "not modeled".Tested
Ubuntu 26.04.1 (Linux 7.0.0-38), GCC 15.2.0, Release, RX 9060 XT (RADV GFX1200, Mesa 26.0.8-1ubuntu0.3). Based on
main6d56eb8 (merged into the branch on Oct 30).agc_driver_gds_append_consume, each checking every lane's value, the counter and a timeout count of 0:ds_ordered_count: group 0 gets the start value, groups 2–3 time out and get the remaining values, and exactly 2 timeouts are counted.mainbb04a4f (with only this test file added) it fails: "64 single-wave groups, dispatch 1, ds_ordered_count: group 0 lane 0 returned 1025, expected 1000 (the counter in launch order)".ds_ordered_count), inagc_driver_gds_append_consumeand_copied. The RX 9060 XT on RADV reportsmaxComputeWorkGroupCount[1] = 65535, so the case takes the split path here: 2 chunks, row 0 gets the start value, 65533 waves of the first chunk run unordered, and the second chunk and the dispatch after it are ordered. It passes 3 of 3 in both registrations, with 0VUID-messages.WorkgroupIdorder. For a row 0 served that late, the case skips only the row 0 value and the unordered count, and names the skip in its success line; the skipped row, the second chunk's order after its reset and the final counter are still checked. A row 0 served early but not first still fails. The debt entry names the assumption.ctest -R '^agc_|^shader_|recompiler' -j4on this branch: 1130 of 1132 pass. The 2 failures,agc_idle_publish_waitandagc_driver_native_multisample_depth, also fail onmainon this machine (the second because a host import getsvkAllocateMemory-13 here).ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ctest -V -R gds_appendon the same machine and GPU, onmainbb04a4f and on this branch.VUID-messages.mainthe test fails only on the new case, as intended.mainstops at startup in this title (sceHttp2SetResolveRetry not implemented), so this ran on my local integration build (mainplus local branches) with and without this PR.0x1038fb8200) intermittently produced overlapping particle records, drawn as long streaks. That was 1–9 corrupted frames per 8-minute run; with the change, 0 in 3 runs (Oct 23, first version of this PR).tools/trace_digest.py,APS5_TRACE_SECONDS=200:60, order without, with, with, without:gpu_busy_ms_per_present148.5 / 128.9 / 128.6 / 151.9. This metric spans each batch from its first to its last command, idle gaps included, so it is not shader time. I have not attributed the change to a phase.main. That was wrong: those were runs of the integration build against a baseline from another day.python3 tools/check_conventions.py --base origin/main: all conventions checks passed.tools/pr_overlap.py --branch fix/recompiler-ordered-append: no open PR changesds_ordered_count. The overlaps are on shared files only:Graphics/src/ShaderResources.cpp,SpirvMemoryInstructions.cpp,SpirvEmitterHelpers.cpp,Execution/src/Pm4.cppanddocs/dev/debt/shader.md(e.g. feat(agc): serve lane-keyed, pointer and runtime image-table columns #10193, feat(agc): test the depth bounds in the pixel program when the device lacks the depthBounds feature #11551, fix(agc): span table-reading wave64 programs by default on Intel drivers that share handles across fused threads #10846).Progress
PPSA08329 on this machine (RX 9060 XT, RADV), on
mainwith this change and other local, unrelated fixes; this PR depends on none of them. Bring-up thread: #12128.0x1038fb8200writes throughds_ordered_countslots, and serving those slots in launch order removed every streak.gpu_busy_ms_per_present: 148.5 / 151.9 without, 128.9 / 128.6 with.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code