Skip to content

fix(agc): save pending storage images before a partly watched import unwatches them - #7687

Closed
HamSyria wants to merge 2 commits into
boykopovar:mainfrom
HamSyria:fix/unwatch-partly-watched-import
Closed

HamSyria wants to merge 2 commits into
boykopovar:mainfrom
HamSyria:fix/unwatch-partly-watched-import

Conversation

@HamSyria

Copy link
Copy Markdown

What

GuestMemory::ImportWatched ran the unwatch hook (StorageTexture::SaveBeforeUnwatch) only for imports that leave the write watch. An import that stays watched over memory the watch covers only in part fails its write walk and unwatches the whole range, without the hook. Storage images with results pending in that range then had no saved guest bytes, and their store threw storing storage image results pending over memory outside the write watch without the guest bytes saved before them is not implemented.

The hook now also runs, before the import, when a stays-watched import is not fully covered by the watch. The debt entry for pending results outside the write watch names this case among the ones that save the bytes.

Tested

Windows 11 (10.0.26300), GCC 15.2.0 UCRT Release.

  • New CheckPartlyWatchedImportSavesFirst in agc_write_tracking: unwatches the middle block of three, then imports all three with staysWatched. Without the change the unwatch hook sees none of the watched blocks (0 calls) and the test fails; with it, it passes.
  • ctest -R '^agc_' on this branch (rebased on main 8b8edc5): 737 of 737 passed.
  • Marvel's Wolverine (PPSA03671) on main a0f3dc4 with APS5_TEXTURE_CACHE_MIB=7168-11264: it stopped on the error above after about 60 s, after a 0x18b74000-byte import at 0x11e128c000 with staysWatched and covered=0. With the change it ran on past that point (180 s and more) without the error. Not yet repeated on this branch's main.

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: none
  • Unblocks: PPSA03671 PS4 vs PS5 executables: the SELF container is the same format (measured) #2433
  • GPUs tested: NVIDIA GeForce RTX 5070 Ti, driver 616.92, Windows 11 10.0.26300
  • AI-assisted: yes

🤖 Generated with Claude Code

…unwatches them

ImportWatched with staysWatched ran the unwatch hook only for imports that
leave the watch. An import that stays watched over memory the watch covers
only in part fails its write walk and unwatches the whole range without the
hook, so storage images with results pending there lost their saved guest
bytes and their store threw "storing storage image results pending over
memory outside the write watch without the guest bytes saved before them is
not implemented".

The hook now also runs when a stays-watched import is not fully covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added unblocks title Names a title ID on the Unblocks line needs rebase Conflicts with main, rebase needed docs agc libSceAgc* labels Oct 18, 2026
…unwatch-partly-watched-import

# Conflicts:
#	docs/dev/debt/libSceAgcDriver.md
@github-actions

github-actions Bot commented Oct 18, 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 6926 docs/dev/debt/libSceAgcDriver.md L95-96
PR 7432 docs/dev/debt/libSceAgcDriver.md L96
PR 7579 docs/dev/debt/libSceAgcDriver.md L96

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/GuestMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 5021 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 5058 docs/dev/debt/libSceAgcDriver.md
PR 5499 docs/dev/debt/libSceAgcDriver.md
PR 5925 docs/dev/debt/libSceAgcDriver.md
PR 6146 docs/dev/debt/libSceAgcDriver.md
PR 6185 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6186 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6187 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6188 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6192 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6194 docs/dev/debt/libSceAgcDriver.md
PR 6209 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6223 docs/dev/debt/libSceAgcDriver.md
PR 6252 docs/dev/debt/libSceAgcDriver.md
PR 6280 docs/dev/debt/libSceAgcDriver.md
PR 6292 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6300 docs/dev/debt/libSceAgcDriver.md
PR 6457 docs/dev/debt/libSceAgcDriver.md
PR 6479 docs/dev/debt/libSceAgcDriver.md
PR 6548 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/src/GuestMemory.cpp
PR 6636 docs/dev/debt/libSceAgcDriver.md
PR 6683 docs/dev/debt/libSceAgcDriver.md
PR 6718 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6727 docs/dev/debt/libSceAgcDriver.md
PR 6730 docs/dev/debt/libSceAgcDriver.md
PR 6808 docs/dev/debt/libSceAgcDriver.md
PR 6820 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
PR 6867 docs/dev/debt/libSceAgcDriver.md
PR 6868 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6946 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6947 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 6960 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
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 7201 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
PR 7233 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
PR 7256 docs/dev/debt/libSceAgcDriver.md
PR 7332 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7446 docs/dev/debt/libSceAgcDriver.md
PR 7449 docs/dev/debt/libSceAgcDriver.md
PR 7505 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7604 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
core/libs/prx/libSceAgcDriver/tests/WriteTracking.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7642 core/libs/prx/libSceAgcDriver/Execution/src/GuestMemory.cpp
docs/dev/debt/libSceAgcDriver.md
PR 7659 docs/dev/debt/libSceAgcDriver.md
PR 7800 docs/dev/debt/libSceAgcDriver.md
PR 7965 docs/dev/debt/libSceAgcDriver.md

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

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

Apple GPU / MoltenVK run. On macOS, agc_write_tracking stops at an earlier check, so CheckPartlyWatchedImportSavesFirst never runs there. Run on its own, it fails without the fix and passes with it.

Machine: Apple M2 Max, macOS 27.2, x86-64 build under Rosetta. Head 3724e31, PR diff applied cleanly. Drivers: MoltenVK 1.4.2 (Vulkan SDK 1.4.363.0) and MoltenVK main + SPIRV-Cross #2704.

Tested: the tree is main a373e85 + mugurc's macOS series (ci/macos-series-2) + the PRs needed to build on macOS (#6667, #6668, #7524, #6969, and two files of #7332), not plain main (it doesn't build on macOS yet). Also in the same build: #7707, #7698, #7687, #7691 and #7705 (they touch different files and applied cleanly together), plus a test-only patch that lets nine AGC fixtures load the Vulkan loader on macOS (branch jotitadev:fix/agc-tests-vulkan-loader-macos). Base on that tree: 40 ^agc failures with MoltenVK 1.4.2 and 26 with MoltenVK main + #2704.

  • agc_write_tracking already fails on that tree before reaching the new check. It stops in CheckImportWindow with a block the import window did not touch reads as written. The cause is how the macOS series' ImportWatched opens the range on Apple, not this PR. The failure is the same with and without the PR, on both drivers.

  • To reach the new check I patched the test locally to run only CheckPartlyWatchedImportSavesFirst:

    • with the PR: passes 3 of 3;
    • with GuestMemory.cpp back to the base: fails 3 of 3 with the watched blocks of a partly watched import left the watch without the unwatch hook seeing them (0 calls).

    So the fix also holds on the macOS path of ImportWatched. Here the write watch reports host imports resolve write protection: no, so imports stay watched.

  • Full ^agc suite with the stack: the base failures on each driver, plus agc_driver_pooled_buffer_range and agc_performance_overlay, which only run because of the loader patch. Nothing from this PR.

GPUs tested: Apple M2 Max (MoltenVK 1.4.2; MoltenVK main + SPIRV-Cross #2704)

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

@savvaniss

Copy link
Copy Markdown
Contributor

Intel and AMD Windows data: with this PR's test changes, agc_write_tracking fails on main and passes with the PR, on an Intel UHD 770 and an AMD RX 9070 XT.

Windows 11 Pro 26300, WinLibs GCC 15.2.0 r7, Release, every execution test built, ANYPS5_NO_SHADER_CACHE=1, serial CTest. Intel UHD Graphics 770 (8086:a780), driver 32.0.101.7088. AMD Radeon RX 9070 XT (1002:7550), driver 32.0.31041.1004, with VkCache emptied first. This head 3724e31d6 merged into main 6b8228b2b. "Without" means only this PR's diff to tests/WriteTracking.cpp, applied to main 6b8228b2b.

Tests, ×3 UHD 770 RX 9070 XT
This head: agc_write_tracking pass pass
Without fails: the watched blocks of a partly watched import left the watch without the unwatch hook seeing them (0 calls) same

AI-assisted: yes (Claude Code)

@HamSyria

Copy link
Copy Markdown
Author

Closing as a duplicate of #6308, which fixes the same stop and covers more: it runs the unwatch hook whenever the write walk fails before the range is unwatched, while this PR only covered a stays-watched import over partly watched memory. #7505 takes a similar approach. I missed both when checking for overlap, sorry for the noise. For #6308: Marvel's Wolverine (PPSA03671) hits this stop on Windows with an RTX 5070 Ti, at a 0x18b74000-byte import at 0x11e128c000 with staysWatched and covered=0.

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.

3 participants