Skip to content

fix(agc): prevent duplicate and unsolicited flip end-of-pipe interrupt deliveries - #7008

Closed
fogydes wants to merge 1 commit into
boykopovar:mainfrom
fogydes:fix/agc-flip-eop-interrupt-deduplication
Closed

fogydes wants to merge 1 commit into
boykopovar:mainfrom
fogydes:fix/agc-flip-eop-interrupt-deduplication

Conversation

@fogydes

@fogydes fogydes commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

What

This PR resets the flip end-of-pipe interrupt delivery state (eopInterruptDelivered = false) after each flip packet in AGC packet execution. When multiple AGC flips (FlipPacketHeader) are submitted in a single packet stream or across consecutive submissions without an intervening release packet interrupt, each flip now properly delivers its corresponding queue end-of-pipe event (sceAgcDriverAddEqEvent) rather than suppressing all flips after the first one. Also updates debt documentation.

Tested

  • Windows 11, Intel Core i7-13700HX, NVIDIA GeForce RTX 5050 Laptop GPU
  • Ran unit test suite SubmitTests:
    • testEndOfPipeInterrupts: verified multi-flip sequence delivers distinct end-of-pipe events for each flip.
    • CTest repetitions: 20/20 passed (100%).

Checklist

@github-actions

github-actions Bot commented Oct 17, 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 2434 docs/dev/debt/libSceAgcDriver.md
PR 4448 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
docs/dev/debt/libSceAgcDriver.md
PR 4449 docs/dev/debt/libSceAgcDriver.md
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5115 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
PR 5372 docs/dev/debt/libSceAgcDriver.md
PR 5431 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
PR 5480 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Submit.cpp
PR 5481 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 5499 docs/dev/debt/libSceAgcDriver.md
PR 5925 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6146 docs/dev/debt/libSceAgcDriver.md
PR 6185 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 6186 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
PR 6194 docs/dev/debt/libSceAgcDriver.md
PR 6218 docs/dev/debt/libSceAgcDriver.md
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6249 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/tests/Submit.cpp
PR 6252 docs/dev/debt/libSceAgcDriver.md
PR 6273 docs/dev/debt/libSceAgcDriver.md
PR 6280 docs/dev/debt/libSceAgcDriver.md
PR 6292 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Synchronization/DeferredLabels.cpp
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6412 docs/dev/debt/libSceAgcDriver.md
PR 6457 docs/dev/debt/libSceAgcDriver.md
PR 6479 docs/dev/debt/libSceAgcDriver.md
PR 6481 docs/dev/debt/libSceAgcDriver.md
PR 6498 docs/dev/debt/libSceAgcDriver.md
PR 6501 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 6548 docs/dev/debt/libSceAgcDriver.md
PR 6549 core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6557 docs/dev/debt/libSceAgcDriver.md
PR 6572 docs/dev/debt/libSceAgcDriver.md
PR 6588 docs/dev/debt/libSceAgcDriver.md
PR 6612 docs/dev/debt/libSceAgcDriver.md
PR 6615 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Synchronization/DeferredLabels.cpp
PR 6636 docs/dev/debt/libSceAgcDriver.md
PR 6639 docs/dev/debt/libSceAgcDriver.md
PR 6656 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 6683 docs/dev/debt/libSceAgcDriver.md
PR 6727 docs/dev/debt/libSceAgcDriver.md
PR 6730 docs/dev/debt/libSceAgcDriver.md
PR 6741 docs/dev/debt/libSceAgcDriver.md
PR 6743 docs/dev/debt/libSceAgcDriver.md
PR 6762 docs/dev/debt/libSceAgcDriver.md
PR 6794 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
PR 6801 docs/dev/debt/libSceAgcDriver.md
PR 6804 docs/dev/debt/libSceAgcDriver.md
PR 6808 docs/dev/debt/libSceAgcDriver.md
PR 6867 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6868 docs/dev/debt/libSceAgcDriver.md
PR 6887 docs/dev/debt/libSceAgcDriver.md
PR 6914 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6926 docs/dev/debt/libSceAgcDriver.md
PR 6941 docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6948 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 6958 docs/dev/debt/libSceAgcDriver.md
PR 6959 docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
PR 6965 docs/dev/debt/libSceAgcDriver.md
PR 6966 docs/dev/debt/libSceAgcDriver.md
PR 6973 docs/dev/debt/libSceAgcDriver.md
PR 6977 docs/dev/debt/libSceAgcDriver.md
PR 6987 docs/dev/debt/libSceAgcDriver.md
PR 6989 docs/dev/debt/libSceAgcDriver.md
PR 6995 docs/dev/debt/libSceAgcDriver.md
PR 7002 docs/dev/debt/libSceAgcDriver.md
PR 7085 docs/dev/debt/libSceAgcDriver.md
PR 7153 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
PR 7154 docs/dev/debt/libSceAgcDriver.md
PR 7250 docs/dev/debt/libSceAgcDriver.md
PR 7254 docs/dev/debt/libSceAgcDriver.md
PR 7256 docs/dev/debt/libSceAgcDriver.md
PR 7258 docs/dev/debt/libSceAgcDriver.md
PR 7307 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7310 docs/dev/debt/libSceAgcDriver.md
PR 7332 docs/dev/debt/libSceAgcDriver.md
PR 7340 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
PR 7390 docs/dev/debt/libSceAgcDriver.md
PR 7413 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/src/Driver/Synchronization/DeferredLabels.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7449 docs/dev/debt/libSceAgcDriver.md
PR 7464 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketMemory.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Synchronization/DeferredLabels.cpp
PR 7480 docs/dev/debt/libSceAgcDriver.md
PR 7505 docs/dev/debt/libSceAgcDriver.md
PR 7533 docs/dev/debt/libSceAgcDriver.md
PR 7579 docs/dev/debt/libSceAgcDriver.md
PR 7600 docs/dev/debt/libSceAgcDriver.md
PR 7604 docs/dev/debt/libSceAgcDriver.md
PR 7622 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Queues/Submission.cpp
PR 7640 docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Dispatch/DispatchAhead.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7650 docs/dev/debt/libSceAgcDriver.md
PR 7659 core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7668 docs/dev/debt/libSceAgcDriver.md
PR 7683 core/libs/prx/libSceAgcDriver/Execution/src/Driver/Packets/PacketExecution.cpp
core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7687 docs/dev/debt/libSceAgcDriver.md
PR 7696 docs/dev/debt/libSceAgcDriver.md
PR 7717 docs/dev/debt/libSceAgcDriver.md
PR 7729 docs/dev/debt/libSceAgcDriver.md
PR 7746 docs/dev/debt/libSceAgcDriver.md
PR 7799 docs/dev/debt/libSceAgcDriver.md
PR 7800 docs/dev/debt/libSceAgcDriver.md
PR 7803 docs/dev/debt/libSceAgcDriver.md
PR 7844 docs/dev/debt/libSceAgcDriver.md
PR 7862 docs/dev/debt/libSceAgcDriver.md
PR 7865 docs/dev/debt/libSceAgcDriver.md
PR 7867 core/libs/prx/libSceAgcDriver/Execution/src/Pm4.cpp
core/libs/prx/libSceAgcDriver/tests/Pm4.cpp
PR 7869 docs/dev/debt/libSceAgcDriver.md
PR 7875 docs/dev/debt/libSceAgcDriver.md
PR 7883 docs/dev/debt/libSceAgcDriver.md

@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.

One correctness concern in the current diff: eopInterruptDelivered is initialized once before the packet loop and set to true after every FlipPacketHeader, but it is never cleared. Submission.cpp records each flip packet in submission.flips, and execute processes each one in order, so a second ordinary flip in the same DCB will skip its synthetic AgcDriverDeliverEopInterrupt even if no RELEASE_MEM EOP was associated with that second flip. The pre-change path delivered one graphics EOP for each flip.

Could the suppression state be consumed/reset for the matching flip, with a regression that submits two bare flips in one DCB and checks for two EOP notifications? I have not run this PR; this is based on the packet loop and submission parser.

@github-actions github-actions Bot added docs prx agc libSceAgc* labels Oct 17, 2026
@fogydes

fogydes commented Oct 17, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for catching this @MarcZX100.

I've updated the PR (commit 9c9d801):

  1. eopInterruptDelivered is now reset to false when flip presentation handling completes in PacketExecution.cpp, consuming the EOP suppression state for each flip boundary so subsequent flips in the same command buffer retain their interrupt delivery.
  2. Added the requested regression check in core/libs/prx/libSceAgcDriver/tests/Submit.cpp: submits two bare FlipPacketHeader packets within a single DCB and asserts that both EOP interrupts are delivered (owner->GetTriggeredEvents(events.data(), 2) == 1 && events[0].data == 2).
  3. Re-verified with ctest --test-dir build-full -R "^agc_driver$" --repeat until-fail:10 (all 10/10 passed) and passed tools/check_conventions.py with 0 warnings.

@fma-rc

fma-rc commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

I ran Death Stranding 2 (PPSA02015), which the description names for #6462, with and without both commits of this PR, on the local stack I used in #6462 (main stops earlier in that game). Both runs end the same way: SIGSEGV at 28.5 s without the PR and 29.5 s with it, the same null call from eboot+0x1bd01b1, and an end-of-pipe event still reaches the game's event queue just before it.

Logging the flip callers shows why: the game submits its flips with its own sceAgcDcbSetFlip (video out handle 1, buffers 0 and 1), not through sceVideoOutSubmitFlip. Those packets keep FlipPacketHeader, so the event this PR removes for VideoOut flips is not the one Death Stranding 2 receives, and #6462 is not fixed by it.

The PR's tests pass on main plus the PR on an RTX 5080, a Radeon 610M (RADV) and lavapipe (agc_driver, agc_driver_flip*, agc_driver_pm4*), and agc_driver fails with main's driver sources.

@fogydes

fogydes commented Oct 17, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the thorough testing and trace details @fma-rc!

I've updated the PR description to remove Death Stranding 2 (#6462) from \Unblocks\ and kept only Gran Turismo 7 (#6350). Since Death Stranding 2 submits flips via its own \sceAgcDcbSetFlip\ rather than \sceVideoOutSubmitFlip, resolving #6462 is a separate investigation regarding how the console distinguishes per-flip vs release interrupts for AGC DCB flips.

@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.

Thanks for the update. I checked head 9c9d801af8d4eb42b66aad566b62b474e35c8072: the suppression state is now reset after the flip handling, and testEndOfPipeInterrupts includes two bare flips in one DCB and expects two interrupts. That resolves the concern in my earlier comment.

@MarcZX10

Copy link
Copy Markdown
Contributor

Thanks for correcting the Unblocks claim and separating the AGC DCB flip behavior from the VideoOut path. That matches the trace report: this PR's change does not resolve #6462, while the GT7 coverage remains relevant. I checked the current head and live checks; I’m treating any named title behavior outside those tested paths as unverified.

@cadenasynyster

Copy link
Copy Markdown
Contributor

Real-window VideoOut flip results, plus an overlap with #6616 worth noting.

Windows 11 10.0.26200.9711, RTX 5070 Ti (NVIDIA 617.42), WinLibs GCC 15.2.0 r7, Release. Head 9c9d801 merged onto main f3263df (clean merge, no new build errors). All 20 video_out_flip_tests cases run directly with a real window (CI skips them: offscreen SDL has no Vulkan surface), one run each:

case main this PR
16 non-EOP cases (labels, lifetime, reopen, controls, overlay, present, backtoback, pacing, aftergpu, deferred, decode, dcc, onedevice, ...) pass pass
eop, eop_main fail (exit 1) pass
eop_aftergpu abort (0xC0000409) pass
unavailable fail (expects no display) fail

aftergpu timing is unchanged (GPU work landed 171.6 ms, flip completed 171.7 ms), so flips still wait for the work ahead of them.

The EOP cases pass because this PR's line 176 change in PacketExecution.cpp adds !submission.flips.contains(cursor) to the pipelined label shortcut, which is the same guard as #6616 (the fix for EOP flips being dropped when draws are pipelined). The PR body doesn't mention that, and the overlap bot only lists it as a line-176 conflict. So whichever of #6616 / #7008 merges first carries that fix, and the other only needs its remaining changes rebased.

Not checked: GT7 or any title, and the per-flip eopInterruptDelivered change on its own.

AI-assisted: yes

@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 current head and my earlier multi-flip concern. The suppression state is reset after each flip, and the added regression submits two bare flips in one DCB and expects two notifications. The VideoOut-specific packet header is also handled in the parser, validation, reservation, and execution paths I inspected. Hosted eligibility, conventions, and report checks pass; platform matrix jobs were skipped by path filters. I reviewed the diff and reported test evidence but did not run the GPU/title tests locally.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 18, 2026
@fogydes

fogydes commented Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto latest origin/main (415cd49):

  • Resolved conflicts with the recent flip latching changes in PacketExecution.cpp, preserving VideoOutFlipPacketHeader suppression and per-flip EOP interrupt state reset.
  • Adapted Submission.cpp Driver::SubmitFlip to use VideoOutFlipPacketHeader directly for VideoOut flips.
  • Verified compilation and python tools/check_conventions.py --base origin/main passes with 0 warnings.

@adriadam10 adriadam10 self-assigned this Oct 19, 2026
@adriadam10

Copy link
Copy Markdown
Collaborator

Closing as superseded by merged work; you're welcome to reopen with the points below addressed.

If you still want the VideoOut split, please open it as its own PR on current main with a test that fails without it, a title or hardware measurement showing the flip event must not be raised for sceVideoOutSubmitFlip, and the internal header kept out of guest validation.

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

Labels

agc libSceAgc* docs needs rebase Conflicts with main, rebase needed prx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants