Skip to content

fix(agc): read a frame capture's memory delta once the accepted submissions completed - #11197

Merged
oneandonlydean merged 2 commits into
boykopovar:mainfrom
LeandroLP23:fix/agc-frame-recorder-settle-before-delta
Oct 26, 2026
Merged

oneandonlydean merged 2 commits into
boykopovar:mainfrom
LeandroLP23:fix/agc-frame-recorder-settle-before-delta

Conversation

@LeandroLP23

@LeandroLP23 LeandroLP23 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

A frame capture could store a memory delta from before an earlier recorded DMA copy had landed. FrameRecorder::writeDelta read the delta's blocks with ReadCommittedUnsynced while GPU work accepted before the call could still write them. At replay the stale bytes were written back over the copy's result. That is the intermittent "the replay did not reproduce the second copy" of agc_driver_frame_replay in #10711 (root cause in #8740 (comment)).

  • Wait before the read. A delta that has blocks to read (new ranges or written blocks) first waits up to 10 s for the submissions already accepted (WaitIdleFor), when any are still in flight. It records the accepted and completed serials after the wait. This is option 1 of that comment. A delta with nothing to read does not wait, so those calls keep their submissions overlapped.
  • Acceptance under the recorder lock. Submit, SubmitFlip and SuspendPoint hand the driver call to the recorder. It runs the call under its lock right after recording it, so every call recorded before a delta has been accepted when the delta waits. Without this, another thread's submission recorded before the delta could be accepted during the wait or after the read, and the replay would submit it before applying stale bytes over its result.
  • Timeout. When the work does not finish, the capture stops with a warning and its writer is finished, like a capture on a full volume. Nothing is thrown: writeDelta runs inside Submit and SubmitFlip, which catch only ProcessShutdown, so an exception would end the title. abandonIfDiskLow and the timeout share stop(reason).
  • Quarantine. The Windows quarantine of agc_driver_frame_replay from test(agc): quarantine agc_driver_frame_replay on Windows until the recorder fix (#10711) #10715 is removed, with its debt entry. BUILD.md describes the wait, and the Frame capture debt entry gains the new way a capture can stop.

@Sumaiter opened the same fix as #11185 (an unconditional wait that throws on timeout). The bot closed it at once for the open-PR limit, so I'm opening this one so the fix isn't blocked. Credit for the independent analysis goes to them. #11157 (janzezno) touches the same quarantine lines; the agreed order in #10711 is the fix first, then #11157 registers the test on Linux without its quarantine changes.

Tested

Windows 11 (10.0.26300), AMD Radeon 860M (AMD 24.30.58.08, LLPC), WinLibs GCC 15.2, Release with BUILD_TESTING=ON, on main 07da04f947.

  • The 10 frame_replay|frame_capture tests pass with ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1: agc_frame_capture, agc_driver_frame_capture_eop, agc_driver_frame_replay, the new agc_driver_frame_replay_concurrent and the six agc_driver_frame_replay_* state tests. agc_driver_frame_replay_concurrent submits 64 DMA copies from a second thread during the capture. It checks that every memory delta was read once the submissions recorded before it had completed, and that the replay reproduces all 64 copies.
  • agc_driver_frame_replay under contention. ctest is pinned to two cores with three busy-loop processes on them and ANYPS5_GPU=no-such-device, as on the runner; this is the setup that reproduced the CI failure.
Recorder Passed
main 159 of 200 (41 fail with "the replay did not reproduce the second copy")
this PR (two series, before and after rebasing onto 07da04f947) 200 of 200, 200 of 200
#11185 head b709c0fe3d 200 of 200
  • agc_driver_frame_replay_concurrent under the same contention: 100 of 100 on this head. With only the old Submit order put back (record, release the lock, then driver.Submit) it passes 66 of 100; the failures say a delta was read with a submission recorded before it unfinished.
  • Validation layer (Vulkan SDK 1.4.363.0, same machine): ctest -V with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1 and ANYPS5_REQUIRE_VULKAN=1 on this head and on its base main 07da04f947. The frame_replay|frame_capture tests pass 10/10 against 9/9 on main. They never load the Vulkan loader, so the layer has nothing to check there. The 22 agc_driver_* GPU tests matching flip|suspend|submit|eop|label give 20 passed and 2 skipped on both. There are 0 VUID- lines in any log, and no was not found but was requested by env var VK_INSTANCE_LAYERS. A direct run with VK_LOADER_DEBUG=all shows the layer inserted.
  • The timeout path is not exercised: that needs GPU work that never completes.
  • check_conventions.py --base origin/main passes. pr_overlap.py finds feat(agc): capture and replay frames on Linux #11157 (above), and fix(agc): keep capture trace output nonfatal #10760, which adds an unrelated debt entry (capture trace output) next to the Frame capture one, so whichever lands second resolves a text conflict in that list.

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
  • Depends on: none
  • Fixes: Fixes agc_driver_frame_replay fails intermittently on Windows CI #10711
  • Unblocks: none
  • GPUs tested: AMD Radeon 860M (integrated), AMD 24.30.58.08 (LLPC), Windows 11 10.0.26300
  • AI-assisted: yes (Claude Code)

…ssions completed

A delta read its blocks with ReadCommittedUnsynced while GPU work
accepted before the call could still write them, so a capture could
hold a block from before a DMA copy that the replay then wrote back over
the copy's result. A delta with blocks to read now waits up to 10 s for
the accepted submissions and records the serials after the wait; the
capture stops with a warning when the work does not finish. The Windows
quarantine of agc_driver_frame_replay is removed.

Fixes boykopovar#10711

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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.

I found a race that can leave the original stale-delta bug possible. Driver::WaitIdleFor snapshots accepted on entry and returns once completed reaches that snapshot (Driver/Lifecycle.cpp:253-255); it does not prevent later submissions from being accepted. The public submit wrapper calls recorder->Submit and then driver.Submit separately (Driver/EntryPoints.cpp:22-24), and the recorder lock is released before the driver submission. A second thread can therefore accept a submission while this wait is in progress. This code rereads serial progress at line 376 but proceeds to ReadCommittedUnsynced even if the new accepted is greater than completed, so that write can still land after the delta read. Please serialize acceptance against the wait/read or otherwise establish a stable idle point, and add a regression that accepts another write during the wait. The report also omits the required VK_LAYER_KHRONOS_validation run and VUID comparison for an AGC-driver change; CONTRIBUTING.md requires those on the same GPU for main and change.

@github-actions

github-actions Bot commented Oct 25, 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
PR 10760 docs/dev/debt/libSceAgcDriver.md L74-76
PR 11157 core/libs/prx/libSceAgcDriver/CMakeLists.txt L3489-3490, L3501-3502
docs/dev/BUILD.md L198
docs/dev/debt/libSceAgcDriver.md L75-76

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 674 docs/dev/BUILD.md
PR 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 1835 docs/dev/BUILD.md
PR 1896 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 4040 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
PR 4448 docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/BUILD.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6187 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6188 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6194 docs/dev/debt/libSceAgcDriver.md
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6273 docs/dev/debt/libSceAgcDriver.md
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6548 docs/dev/debt/libSceAgcDriver.md
PR 6549 docs/dev/debt/libSceAgcDriver.md
PR 6642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 6977 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7256 docs/dev/debt/libSceAgcDriver.md
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7449 docs/dev/debt/libSceAgcDriver.md
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 7910 docs/dev/debt/libSceAgcDriver.md
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8161 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8246 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8319 docs/dev/debt/libSceAgcDriver.md
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8520 docs/dev/debt/libSceAgcDriver.md
PR 8542 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 9176 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9248 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9287 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9289 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9356 docs/dev/debt/libSceAgcDriver.md
PR 9387 docs/dev/debt/libSceAgcDriver.md
PR 9393 docs/dev/debt/libSceAgcDriver.md
PR 9402 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 9431 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9432 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 9592 docs/dev/debt/libSceAgcDriver.md
PR 9672 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9673 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9674 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9675 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9676 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9748 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 9842 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 9852 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9904 docs/dev/debt/libSceAgcDriver.md
PR 9905 docs/dev/debt/libSceAgcDriver.md
PR 9906 docs/dev/debt/libSceAgcDriver.md
PR 9950 docs/dev/debt/libSceAgcDriver.md
PR 10193 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 10351 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/debt/libSceAgcDriver.md
PR 10435 core/libs/prx/libSceAgcDriver/Execution/src/Driver/EntryPoints.cpp
docs/dev/debt/libSceAgcDriver.md
PR 10442 core/libs/prx/libSceAgcDriver/CMakeLists.txt

…r takes its next call

The recorder released its lock between recording a submission, flip or
suspend point and the driver accepting it. Another thread's delta could
then wait for the accepted work, read its blocks, and record itself
after a call whose work the driver had not accepted yet, so the replay
submitted that work before applying stale bytes over its result. The
entry points now pass the driver call to the recorder, which runs it
under the same lock right after recording the call.

agc_driver_frame_replay_concurrent submits copies from a second thread
during the capture and checks that every memory delta was read after
the submissions recorded before it had completed.

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

Copy link
Copy Markdown
Contributor Author

@MarcZX10 thanks, the race was real. Fixed in a69872e516.

Acceptance is now ordered with recording. Submit, SubmitFlip and SuspendPoint hand the driver call to the recorder. It runs the call under the same lock, right after recording it. So by the time a delta takes the lock, every call recorded before it has been accepted, and the wait in writeDelta covers all of them. No other path accepts work while the delta waits and reads. A second wait after the read would not be enough: a submission recorded before the delta but accepted after it is still replayed before the delta.

Regression. agc_driver_frame_replay_concurrent is the same executable with a concurrent argument and its own capture directory, 8 frames. A second thread submits 64 DMA copies, each into its own 4 KiB target with its own command buffer. Meanwhile the main thread writes with the CPU, submits a copy and flips each frame. The test checks every Memory call in the capture: the completed serial recorded with it must be at least the capture start's plus the number of Submit calls recorded before it. It also checks that the replay reproduces all 64 targets. To show it catches this race, I put back only the old order in Submit (record, release the lock, then driver.Submit):

Runs with ctest pinned to two cores with three busy-loop processes on them and ANYPS5_GPU=no-such-device; Radeon 860M, Windows 11:

Build agc_driver_frame_replay_concurrent agc_driver_frame_replay
this head 100/100 100/100
this head with the old Submit order 66/100, e.g. "a memory delta was read with 1 of the 2 submissions recorded before it unfinished"

Validation layer. Vulkan SDK 1.4.363.0, same machine and GPU (Radeon 860M, AMD 24.30.58.08, Windows 11 10.0.26300). ctest -V with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1 and ANYPS5_REQUIRE_VULKAN=1, on this head and on its base main 07da04f947:

Test set main this head
frame_replay|frame_capture 9/9 passed, 0 VUID- 10/10 passed, 0 VUID-
the 22 agc_driver_* tests matching flip|suspend|submit|eop|label 20 passed, 2 skipped, 0 VUID- 20 passed, 2 skipped, 0 VUID-

Neither log has was not found but was requested by env var VK_INSTANCE_LAYERS. One caveat on the first row: the frame capture and replay tests never load the Vulkan loader. With VK_LOADER_DEBUG=all, a direct run of agc_driver_frame_replay_tests prints no loader line, and its copies run without a device. So the layer has nothing to check there, on main as on this head. I added the second row for that reason: those tests create the device and go through the entry points this PR changes. With VK_LOADER_DEBUG=all, a direct run of one of them shows Insert instance layer "VK_LAYER_KHRONOS_validation". The two skipped tests are agc_driver_copied_writer_label_order and its _drain variant, skipped on both.

AI-assisted: yes (Claude Code)

@ycbuzi

ycbuzi commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

A Windows check of this head against #10711's reproduction, plus a run on three GPUs.

Windows 11 Home 10.0.26200, WinLibs GCC 15.2.0 r7 (MinGW-w64 UCRT), Release. a69872e516 merged onto main d31f372e33 with no conflicts.

Under contention, as in LeandroLP23's reproduction on #8740. ANYPS5_GPU=no-such-device, so no device is picked, like on the runner. ctest is started with start /affinity 3, confining it and the test to two cores, and three busy-loop processes are pinned to the same two cores. Each arm runs agc_driver_frame_replay 40 times, one ctest call per run:

tree failed runs message
main 504ea3b53b, quarantine overridden (ANYPS5_RUN_QUARANTINED_FRAME_REPLAY=ON) 22 of 40 replay did not reproduce the second copy, all 22
this PR (593fd36932) 0 of 40

On three GPUs. One GPU at a time, with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1 and ctest --repeat until-fail:2: agc_driver_frame_replay and the new agc_driver_frame_replay_concurrent pass both runs on the GeForce RTX 4070 SUPER, the GeForce GTX 1650 SUPER (NVIDIA 616.92) and the Radeon iGPU (1002:164e, AMD 32.0.21030.2001).

Negative control. FrameRecorder.hpp, FrameRecorder.cpp and Driver/EntryPoints.cpp taken from main, with the tests unchanged. agc_driver_frame_replay_concurrent then fails.

So on this machine the PR removes the Windows failure #10711 quarantined, and the test can come out of quarantine.

AI-assisted: yes (Claude Code)

@oneandonlydean oneandonlydean self-assigned this Oct 26, 2026
@oneandonlydean
oneandonlydean merged commit 204c674 into boykopovar:main Oct 26, 2026
11 of 12 checks passed
@LeandroLP23
LeandroLP23 deleted the fix/agc-frame-recorder-settle-before-delta branch October 26, 2026 08:05
@Sam-mon7

Copy link
Copy Markdown
Contributor

@LeandroLP23 Thank you for picking this up.

@Dextroid17

Dextroid17 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Edit: I missed that this is already covered on #11157. janzezno notes the "Frame capture" debt entry lists this case, and JJenkx has a game-independent two-queue reproducer. The data below is a second title for the same mechanism: the label is written by a RELEASE_MEM on queue 0x0, which matches the later-submission case in JJenkx's reproducer.

@LeandroLP23 with this merged, a Ghost of Yōtei frame capture on Linux hits the 10 s timeout at call 78 in all 3 runs, after 3 memory groups. Before it, the same tree captured 10 frames.

The description says the timeout path isn't exercised because it needs GPU work that never completes. Here it fires on every run, and the GPU work looks like it's waiting on the submitting thread that the wait holds.

Setup: RTX 3080 Ti, Linux, my local GoY tree (main plus unmerged local commits) with ada20294a6 and a69872e516 cherry-picked, and #11157's head c867473002 for the Linux capture path. Execution/src/FrameRecorder.cpp, Execution/include/FrameRecorder.hpp, Execution/src/FrameCapture.cpp and tools/FrameReplay.cpp are identical to c867473002. The "before" capture used the same tree with #11157's earlier head, and its Execution/ diff against the runs below is exactly this PR's diff. I can only test on Linux.

capture started at frame boundary calls frames memory groups result
before this PR, same tree 385 810 10 61 complete
with this PR, run 1 374 78 0 3 stopped
run 2 24 78 0 3 stopped
run 3 193 78 0 3 stopped

Each stopped run logs [frame-capture] stopped: the GPU work submitted before a memory delta did not finish within 10 s. Before that, the GPU log shows a queue timing out:

[gpu] queue 0x30 WAIT_REG_MEM at 0x201181b850 timed out after 1000ms (function 3 ref 0x1 mask 0xffffffff value 0x0)
[gpu]   earlier write by queue 0x0 opcode 0x49 at 0x201181b850+0x4
[gpu]   recorder: table miss (refusal 0), open batch writes it 0, snapshot write overlaps 0, pending completion labels 0, write-back completions 0, ...

The address was 0x201181b850 in runs 1 and 2 and 0x201471b850 in run 3. Every earlier write the report lists for it is a RELEASE_MEM on queue 0x0, and nothing pending writes it.

A fourth run under gdb (boundary 26) hit the same timeout at the same address. I took two samples of all 94 threads, 3 s apart, starting about 1 s after the queue's timeout line. In both:

thread 1:  sceAgcDriverSubmitAcb -> AgcDriver::Submit -> FrameRecorder::Submit -> record -> recordLocked
           -> emitDelta -> writeDelta -> Driver::WaitIdleFor   (pthread_cond_clockwait)
thread 84: Driver::run -> execute -> waitMemory -> PollSleep

Thread 84 is the only thread in waitMemory, so I take it to be queue 0x30. No thread was in a mutex lock. In the first sample the rest were in condition waits, sleeps or poll; in the second, two game threads were running game code.

My guess, not verified: the label is written by a later queue 0x0 submission that the game makes only after this submit returns. While writeDelta holds the submitting thread inside sceAgcDriverSubmitAcb, that submission never comes, so the wait can only time out.

I'm not proposing a fix. I can test a change on this setup, or share the full gdb log.

AI-assisted: yes

chitters2004 added a commit to chitters2004/AnyPS5 that referenced this pull request Oct 28, 2026
…e title

A memory delta was read only once every accepted submission completed,
so a capture stopped after 10 s whenever a queue waited on a REWIND
control word or a label a later call stores, as in the two-queue
reproducer on boykopovar#11157 and the Ghost of Yotei capture on boykopovar#11197.

The driver gains a settled hold: AgcDriverHoldSettled succeeds once
every queue has finished or is parked on a REWIND or WAIT_REG_MEM value
the title has not stored, with no queued draw, unrecorded label or
pending label write, and keeps submissions and parked queues where they
are until AgcDriverReleaseSettled. The recorder reads each delta under
that hold through the coherent path.

The replay restores each delta under the same hold. Its breaker, built
on boykopovar#12318, releases a parked REWIND by applying the first later memory
group that sets its control word, only under a settled probe, one wait
per pass, and no longer writes a value from a later delta for any
other wait, which applied a later CPU store early. Pacing counts a
running queue as progress and gives up after --pace-timeout-ms only
once no queue runs, or after the busy timeout. The drain also ends
after 10 s without a completion once no queue runs, and the busy
timeout, ten minutes, is shared by pacing, the settled hold and the
drain.

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* build docs fix error Closes an issue (Fixes #N)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agc_driver_frame_replay fails intermittently on Windows CI

6 participants