Skip to content

fix(agc): wait for address-based writers before reading indirect dispatch arguments - #6786

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
fdfawef324:claude/agc-indirect-args-stale
Oct 19, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
fdfawef324:claude/agc-indirect-args-stale

Conversation

@fdfawef324

@fdfawef324 fdfawef324 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

What

Execution-time CPU reads of indirect dispatch arguments could see stale counts while an earlier address-based producer still held a registry lease. Those writes need not appear in the pending-write ranges used by the guest-memory flush hook. Finish work through the newest leased batch before each execution-time CPU argument read, including the VulkanDevice fallback. Re-read counts before adopting speculative read-ahead work, and discard a capture when its counts differ.

The wait is conservative: it covers every batch through the newest leased batch without knowing which allocation a producer writes. It can submit and wait for currently recorded work. Other uncovered CPU reads remain documented in technical debt.

The sixth regression case now holds an actual earlier argument-label batch behind a host Vulkan event and leaves its address-based producer in a later open batch. Before the argument decision it requires a deferred producer lease, an unsubmitted producer, and a pending real label. It then requires cpuReason == 2, fresh arguments and the expected final counter. The event releases after the producer batch is submitted; a five-second watchdog releases it for cleanup but fails the test. Small valid stale counts keep the removal control bounded on drivers that accept the stale dispatch. No production test switch was added. Cases 1–5 retain their workloads and checks; their shared failure text no longer assumes case 6's old stale tuple.

The production implementation is unchanged by this coverage update. The final delta from prefinal 01d3bc1e changes only the pending-producer fixture: finite case-6 counts and explicit path/watchdog diagnostics. GTA V PPSA04264 previously passed its stale-count stop in composed runs with the original fix, then encountered a later BVH device loss. Story did not load. This update claims no new title milestone, memory reduction or speed improvement.

Root's first managed GPU run at 3133913f passed the first five cases and reached case 6's reason-2 path, then aborted because the fixture called the shared singleton wait after shutting that singleton down. The repaired candidate skips that common wait only for the direct-device case, which already waits through its own device before setting completion. The fallback, submission, arguments and counter assertions remain. That failed run is preserved and is not reported as a green.

Tested

Candidate bc88a5d2a6e1726724ae49dae562b464e266a882, based on pinned main 84c1a4d9a26429cb483ec963195cff8ef25d128b:

  • Seven affected executables and their runtime libraries build in Release with -O3. The final restored-green build took 26.195 s and the selective removal build 15.561 s, using the corrected nj admission PATH, a 4 GiB whole-job limit, affinity 0xF, final -j2 and nested -j1.
  • CPU/mock agc_driver_graphics and agc_driver_pm4 pass 2/2 in 10.553 s. Conventions pass against the pinned base in 1.657 s.
  • The frozen selective red removes only Graphics::FinishLeaseWork() immediately before GuestMemory::Read in VulkanDevice::decideIndirect. Red and restored green have separate source/runtime pins and natural dirty trace identities. The original 143 READY pins were independently rehashed before the lifecycle edit, including all 22 selective-red pins. Their live inputs were preserved before the new build; the repaired candidate has a separate READY manifest.
  • Fresh required-Vulkan managed-slot checks: all six CTest registrations listed below pass in 7.74 s, with no skipped case or reported skipped subcase. The pending-producer executable passes all six internal cases, including the explicit reason-2 path; five unique executables ran. Hardware tests: agc_driver_indirect_arguments_pending_producer, agc_driver_indirect_arguments_written_ahead, agc_driver_gpu_indirect_arguments_written_ahead, agc_driver_gated_dispatch_capture, agc_driver_prepared_shaders, agc_driver_prepared_shaders_indirect. Actual binaries and libraries were hash-checked before and after.
  • Fresh selective removal control: frozen case index 5 exits 1 in 5.98 s, with the actual RTX 3060/Vulkan-ready markers, cpuReason 2, producer batch 2 still unsubmitted at the watchdog, successful vkSetEvent 0, and the exact missing-submission assertion. The frozen variant was built at pre-lifecycle head 3133913f, natural dirty 1; its failure occurs inside the unchanged gate before the repaired common postlude. This is the intended regression failure, separate from the passing clean candidate. A prior dispatch was refused before GPU execution when its source-head pin changed; it is not counted as a test.
  • Conventions also pass against fetched main 676d423968a1a8fcc79c6247020ce22090a8e0d4; the candidate merges cleanly into it. Source review found no material interaction with merged fix(agc): store pending image results after the range's writers finish #6364: that wait applies to pending storage-image flushes, while the buffer-only argument fixture has no such image. These are source composition checks; execution above remains on the exact candidate based on 84c1a4d9.

Historical and external results remain separate from this candidate:

  • Earlier local NVIDIA GeForce RTX 3060 results in the original PR body: the original six-case regression passed 8/8 CTest runs, based on main 65d56a297; the detailed removal runs used main aff725bf6 and each selective condition failed 3/3 runs. These are earlier trees and the original fixture, not eight neighboring tests or current-candidate measurements. The old case 6 relied on timing and did not prove fallback selection on every driver.
  • Dextroid17's lavapipe report, Linux, Mesa 26.2.4, original 3977f3c2 composed with main 93e54cedd: case 6 often passed after removal because the fallback was not taken. Their instrumented green runs reported reason 0 in 10/10 runs; their whole original suite passed 3/3. This motivated the explicit pending-label and fallback checks. Their observations are not a new local lavapipe run or evidence of a reproduced production-fix defect.
  • LeandroLP23's Radeon 860M report, Windows 11 build 26300, driver 32.0.13058.8001, WinLibs GCC 15.2 Release, main 17cfb1f4c plus original 3977f3c2: case 6 failed 10/10 without the production changes and passed 10/10 with them. The whole suite failed 20/20 without the changes and passed 20/20 with them. These are their measurements on that older composition.

The new fixture has not been tested locally on Linux or AMD. Neighboring #6360 addresses GPU-side argument counts; #5058's held prechecks and #6951's import-run memoization are outside this change. Existing overlap captures are not a fresh guarantee about every open PR or landing order.

Checklist

  • Based on main; targeted current-main/indirect-argument overlap review completed (tested base and separate composition check qualified above)
  • 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
  • Fixes: none
  • Unblocks: none demonstrated on this candidate; related bring-up PPSA04264 Grand Theft Auto V (PPSA04264) #1203 remains incomplete
  • GPUs tested: NVIDIA GeForce RTX 3060 12 GB, driver 591.86 (32.0.15.9186), Vulkan 1.4.325, Windows Server 2025 10.0.26100 (six current-head real Vulkan registrations above; external Radeon results remain attributed)
  • AI-assisted: yes

Generated with Claude Code; coverage recovery and verification assisted by Codex.

Co-Authored-By: Codex noreply@openai.com

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the indirect-argument read paths and lease-wait placement. Both CPU read sites hold GuestMemory::GpuMutex before FinishLeaseWork; the helper submits only when the target lease batch is still open and waits only through the newest batch recorded with a lease. Read-ahead remains speculative and the execution-time counts are re-read before a capture is adopted, with mismatches dropped. The new GPU regression covers address-based producers and the CPU fallback, and the PR reports repeated red/green runs plus neighboring tests. The GTA V result is carefully scoped: it passes the bad-count stop but still encounters a later device loss. I found no blocking issue.

@github-actions

github-actions Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

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/GuestBufferMemory.cpp
PR 1324 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 1395 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4072 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 4448 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4449 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4472 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 5058 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/IndirectDispatch.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5404 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 5441 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 5499 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5609 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 5925 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6146 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6177 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6185 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6194 docs/dev/debt/libSceAgcDriver.md
PR 6197 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6249 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6252 docs/dev/debt/libSceAgcDriver.md
PR 6290 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6292 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/IndirectDispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6501 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 6539 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 6548 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6612 docs/dev/debt/libSceAgcDriver.md
PR 6615 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/IndirectDispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6636 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6683 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6727 docs/dev/debt/libSceAgcDriver.md
PR 6741 docs/dev/debt/libSceAgcDriver.md
PR 6788 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6808 docs/dev/debt/libSceAgcDriver.md
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 docs/dev/debt/libSceAgcDriver.md
PR 6941 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6955 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 6958 docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 6963 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
PR 6966 docs/dev/debt/libSceAgcDriver.md
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7008 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7201 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7233 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7254 docs/dev/debt/libSceAgcDriver.md
PR 7256 docs/dev/debt/libSceAgcDriver.md
PR 7258 docs/dev/debt/libSceAgcDriver.md
PR 7292 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7332 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7340 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7369 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7390 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7426 docs/dev/debt/libSceAgcDriver.md
PR 7432 docs/dev/debt/libSceAgcDriver.md
PR 7446 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7449 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7473 core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7484 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7505 docs/dev/debt/libSceAgcDriver.md
PR 7514 core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7604 docs/dev/debt/libSceAgcDriver.md
PR 7622 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
PR 7642 core/libs/prx/libSceAgcDriver/Execution/include/Driver/Driver.hpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/Dispatch.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7647 core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
core/libs/prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/GuestBufferMemory.cpp
PR 7659 docs/dev/debt/libSceAgcDriver.md
PR 7683 docs/dev/debt/libSceAgcDriver.md
PR 7729 docs/dev/debt/libSceAgcDriver.md
PR 7800 docs/dev/debt/libSceAgcDriver.md
PR 7803 docs/dev/debt/libSceAgcDriver.md

@github-actions github-actions Bot added docs agc libSceAgc* labels Oct 16, 2026
@Dextroid17

Copy link
Copy Markdown
Contributor

@fdfawef324 thanks for the test. One problem on lavapipe (the CI device): case 6, "group counts read on the CPU behind an argument label of an earlier graphics batch", passes without the fix most of the time there, so on lavapipe it does not reliably guard the FinishLeaseWork() call in VulkanDevice::decideIndirect. Your runs were on an RTX 3060 on Windows, and I can't run that, so I'm not saying the case is wrong on your hardware.

With all the production changes reverted to main (test kept), case 6 passes:

group counts read on the CPU behind an argument label of an earlier graphics batch: passed

The PR body says case 6 fails on main "with 3x289x4294967295 (the label landed, the producer had not). This held in 3 of 3 runs." On lavapipe it passed in 4 of 4 runs. The body also says "Without FinishLeaseWork in decideIndirect: case 6 fails". Removing only Graphics::FinishLeaseWork(); from decideIndirect (VulkanDevice.cpp:4340) on the PR tree gave 5 passes in 5 runs.

To see why, I added a temporary print of outcome.cpuReason right before if (outcome.cpuReason == 0) return; in decideIndirect:

  • PR tree: cpuReason 0 in 10 of 10 runs. No label was pending on the argument dwords, so the CPU fallback (the code the case covers) never ran.
  • PR tree without FinishLeaseWork in decideIndirect: cpuReason 0 and a pass in 4 of 6 runs. In the other 2 runs it was cpuReason 2, and the case hung with "the consumer's completion label did not land".

So on lavapipe the case only goes red when the timing happens to keep the label pending. I did not check why the label is usually no longer pending when decideIndirect runs. One option might be for the case to check that the fallback was actually taken (cpuReason 2), so a run that skips it can't pass silently. I have not tried that.

The rest checks out here. Cases 1-4 go red without the fix, but on lavapipe they hang with "completion label did not land" (ctest hits its timeout) rather than failing with the workgroup count error the body quotes. Case 5 passes as a control. The whole test passes with the PR, 3 of 3, in 3.47 s on a run with an empty shader cache.

tree result
PR merged onto main, ctest 3/3 passed (3.47 s cold, 1.60 / 1.61 s warm)
production reverted to main, ctest --timeout 120 3/3 timed out (cases 1-4 hang)
production reverted, case 6 alone 4/4 passed
PR without FinishLeaseWork in decideIndirect, case 6 alone 5/5 passed
PR + cpuReason print, case 6 alone 10/10 cpuReason 0 (fallback not taken), passed
PR without FinishLeaseWork + cpuReason print, case 6 alone 4/6 cpuReason 0 and passed, 2/6 cpuReason 2 and hung

Setup: Linux, lavapipe Mesa 26.2.4, default CMake build (CMAKE_BUILD_TYPE empty), ctest -V --no-tests=error -R '^agc_driver_indirect_arguments_pending_producer$', and the test binary with a case index for single cases. I tested head 3977f3c merged onto main at 93e54ce, because the head alone fails to build on the PipelineJournal.cpp static_asserts, which main has since fixed. The PR doesn't touch that file. The merge is clean, and the head still merges cleanly onto main at 16a0f50.

AI-assisted: yes

@LeandroLP23

Copy link
Copy Markdown
Contributor

AMD hardware run, since the description lists AMD as untested, with each case on its own to answer the lavapipe question about case 6.

Windows 11 (26300), Radeon 860M (RDNA 3.5, driver 32.0.13058.8001), WinLibs GCC 15.2.0, Release. main 17cfb1f4c with this head 3977f3c24 merged cleanly; "main" below is the same tree with the seven production files reverted to main and the new test kept. agc_driver_indirect_arguments_pending_producer_tests <index>, 10 runs per case:

Case main passes this PR passes
1. thread dimensions, separate submissions 0 of 10 10 of 10
2. thread dimensions, one submission 0 of 10 10 of 10
3. label wait in one submission 0 of 10 10 of 10
4. label wait between submissions 0 of 10 10 of 10
5. label wait across compute queues 2 of 10 10 of 10
6. group counts read on the CPU behind an argument label of an earlier graphics batch 0 of 10 10 of 10

So on this device case 6 does guard the FinishLeaseWork() path: it fails every run without the fix. Under ctest, the whole test passes 20 of 20 with this PR and fails 20 of 20 without it (first at case 1: the consumer's completion label did not land).

AI-assisted: yes (Claude Code).

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed unblocks title Names a title ID on the Unblocks line labels Oct 17, 2026
@fdfawef324
fdfawef324 force-pushed the claude/agc-indirect-args-stale branch from 3977f3c to bc88a5d Compare October 19, 2026 04:43
@fdfawef324

Copy link
Copy Markdown
Contributor Author

@Dextroid17 the sixth case now requires the pending-label CPU fallback (cpuReason == 2) instead of relying on timing. It records an actual earlier argument-label batch behind a host Vulkan event and leaves its leased producer in the later open batch. Before the CPU decision it requires the deferred lease, unsubmitted producer and pending real label; afterward it checks fresh arguments and the final counter. The cleanup watchdog can only fail the test.

Published candidate bc88a5d2a6e1726724ae49dae562b464e266a882 passes all six internal cases and all six required-Vulkan CTest registrations on RTX 3060 in 7.74 s. Removing only the fallback's FinishLeaseWork() gives the exact reason-2/unsubmitted-producer assertion in 5.98 s, exit 1. That frozen pre-lifecycle variant fails inside the unchanged gate. The initial 3133913f green attempt exposed a fixture singleton-wait error after its direct device had drained; the one-line postlude guard is corrected, with production unchanged. Failed and refused attempts are excluded from the passing result.

CPU/mock graphics and PM4 pass 2/2. Conventions and a clean merge-tree against 676d42396 pass separately; runtime tests belong to the exact candidate based on 84c1a4d9. No new lavapipe or title result is claimed. @LeandroLP23's original Radeon 860M case-6 and whole-test removal/passing measurements remain attributed in the body, rather than presented as results of this new fixture. The later GTA Story-load stop remains unresolved.

GPUs tested: NVIDIA GeForce RTX 3060 12 GB, driver 591.86 (32.0.15.9186), Vulkan 1.4.325, Windows Server 2025 10.0.26100.

AI-assisted: yes (Claude Code and Codex)

Co-Authored-By: Codex noreply@openai.com

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed and removed needs rebase Conflicts with main, rebase needed labels Oct 19, 2026
@Amoenus

Amoenus commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

While qualifying Sonic I found a separate LDS refusal-order defect, reported in #7794, with the tested two-file proposal on our fork. The current record path can allocate scratch before rejecting a split it already knows is unsupported. The original fixture accepts the earlier allocation/range exception; our stricter test fails 3/3 on each GPU with unchanged production code and passes after moving the existing refusal earlier.

Your PR predates this finding and edits the same LDS diagnostic line. I propose keeping #6786 first, then carrying its cpuArguments / cpuReason annotation into the relocated guard. Does that landing order work for you? I have not opened a competing upstream PR while we coordinate; the fix does not reimplement your writer synchronization. Current proposal: 18 exact-head NVIDIA/AMD/llvmpipe passes after the main refresh, plus the separately pinned 36-run matrix in the issue.

AI-assisted: yes, Codex.

fdfawef324 and others added 2 commits October 19, 2026 10:18
…atch arguments

A CPU read of DISPATCH_INDIRECT arguments waited only through the flush
hook, which waits for the ranges recorded work noted as pending writes.
An address-based store (FLAT/GLOBAL, or through a descriptor the
recompiler cannot resolve to a static buffer) is not recorded as a
pending write: its batch leases the registered allocations, and only the
guest pin waiter finished that batch. So the thread-dimension,
misaligned and disabled paths, the fill-kernel path and the device's CPU
fallback read the arguments from before an address-based producer ran.
GTA V (PPSA04264) dies loading Story on such a read: a 64-thread clear
kernel read {160, 288, 0xffffffff} as thread dimensions
(3x288x4294967295 groups), bytes its 1-thread setup kernel had not yet
overwritten with {n, 1, 1}, and threw "workgroup count
3x288x4294967295 exceeds device limits".

Every CPU read of dispatch arguments at execution now first finishes the
recorder up to the newest batch recorded with a lease
(Graphics::FinishLeaseWork). The group read-ahead still reads without
waiting; a dispatch it resolved is adopted only when the execution-time
read gives the same counts, and one that differs is dropped and counted
in the [groupcap] line. The device limit error names the argument
address and cpuReason, and the driver adds the queue, path and
read-ahead outcome. The [indirect] read time includes the lease wait,
and the [recorder] sync-site table records the offset of
FinishLeaseWork's caller. The CPU reads that still miss address-based
writes (indirect draw arguments and count, the copy kernel's count
record, the awaits-title checks) are listed in the technical debt.

IndirectArgumentsPendingProducer covers the execution-time CPU argument
reads on compute queues and the pending-label CPU fallback in the Vulkan
device. Its sixth case records a real argument label behind a host Vulkan
event in an earlier batch and an address-based producer in the later open
batch. The event releases only after that producer batch is submitted;
a bounded watchdog releases for cleanup but fails the case. It requires
a deferred producer lease, an unsubmitted producer at the argument
decision, cpuReason 2 and the fresh arguments and counter result. Small
valid stale counts keep a broken-wait control finite on every driver.
Exact CPU-reason and watchdog diagnostics identify the failing path. This
replaces a spinning workload whose earlier label could retire before
the fallback decision on lavapipe, allowing a false green with cpuReason 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
The direct-device case already drains its own work before returning. Skip the shared singleton wait after its explicit shutdown so the full suite can retain the fallback and counter assertions without throwing ProcessShutdown.

Co-Authored-By: Codex <noreply@openai.com>
@adriadam10
adriadam10 force-pushed the claude/agc-indirect-args-stale branch from bc88a5d to 652f86e Compare October 19, 2026 08:49
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 19, 2026
@adriadam10
adriadam10 merged commit f6eeca4 into boykopovar:main Oct 19, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the lease wait before both CPU argument reads (driver and VulkanDevice::decideIndirect), the read-ahead re-read, the debt entry and the new test. Rebased onto current main: the only conflict was the workgroup-limit message in VulkanDevice.cpp (main replaced the NVIDIA check with the "no workgroup offset" one); kept main's check and added the CPU-read diagnostic to it. Local ctest passes on the rebased branch; the merge queue's full Build is the gate.

@Amoenus

Amoenus commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

@fdfawef324 @adriadam10 while validating the post-merge main, I confirmed a separate test-gate problem: #7868. The fixture passes three times per RTX 5080 and Radeon Graphics and reaches cpuReason 2, but Khronos 1.4.363 reports 01158 and 09543 once each per process. The report links the official event rules and exact source/control pins. This is a fixture validation finding, not evidence against the production lease-wait fix. AI-assisted: yes, Codex.

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

Labels

agc libSceAgc* docs unblocks title Names a title ID on the Unblocks line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants