Skip to content

fix(agc): track CPU writes in partly watched depth planes - #11692

Merged
adriadam10 merged 9 commits into
boykopovar:mainfrom
JJenkx:fix/agc-partly-watched-depth-planes
Oct 28, 2026
Merged

adriadam10 merged 9 commits into
boykopovar:mainfrom
JJenkx:fix/agc-partly-watched-depth-planes

Conversation

@JJenkx

@JJenkx JJenkx commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

What

A depth plane can contain fully watched units, partly watched units and pages excluded from write tracking. A failed whole-plane scan previously left CPU-repurposed bytes vulnerable to a stale depth store. WrittenUnits now retries whole units first, then page-aligned fragments inside partly watched units. Writes in covered pages invalidate that depth unit; genuinely unwatched pages keep the existing behavior. Initial covered pages are collected before recording their generation, including for single-unit surfaces.

Regressions cover both a wholly unwatched neighboring unit and a 4 KiB hole inside the descriptor's own 64 KiB unit. They write CPU descriptors after a depth draw and check descriptor preservation plus GPU depth retained in an untouched unit. On Windows, where Unwatch excludes whole 64 KiB blocks, the within-unit case instead unwatches the unit and returns only the descriptor page with the page-granular Rewatch, so the unit is partly watched there too (c581723557, after maskym's Windows run).

Built on #11690; merge it first. Shared-fixture overlap with #11685 is the same argument/include addition discussed there; retain its --buffer-copy mode alongside all CPU-write modes. No dependency on its direct-copy implementation.

Tested

Current-main refresh, 2026-10-27 10:18 UTC pass: exact head 1646ca2842119411060c4db6304e47dd18a21fd8 on main 3fea2a937ba9fbab2f06c51691fe0c5763659aa3. Five child topic commits remain stacked on refreshed #11690. The existing within-unit page-coverage correction and its regression are preserved exactly; no genuinely unwatched page is falsely marked written. All submodule pointers match that main.

Linux Release, RX 6650 XT/RADV Mesa 26.2.4, required Vulkan and shader caches disabled. Matched main passes all three existing controls three times (9 passes). Candidate passes six groups × three repetitions (18 passes), then 18 after restoration. The exact within-unit page-hole case additionally passes three times with APS5_NO_DIRECT_DEPTH_COPY=1. Replacing only production with its pre-page-correction parent fails exactly that page-hole case; the other five controls pass. That negative control uses normal mode; the forced-buffer variant is a positive qualification, not a separate negative control. The within-unit regression places a 4 KiB unwatched hole and CPU descriptors in an adjacent watched page of the same 64 KiB unit, checking descriptor preservation and retained GPU depth.

Every individual physical execution proves RX 6650 XT selection and actual Khronos instance/device-layer insertion; zero skips, VUIDs or missing-layer failures. Restored production source matches the candidate, and the rebuilt AGC driver is byte-identical to its initial candidate. The forced-buffer setting is recorded in the executed harness/process environment and linked to the startup flag; CTest does not print every inherited variable. Conventions and whitespace pass. This is synthetic GPU regression evidence, without a new title, console, Windows or performance run. Earlier contributor results retain their original exact pins.

Exact source/dependency pins, initial/negative/restored raw logs and JUnit, forced-buffer receipt, independent reviews, hashes and service-owned FIFO/PTY receipts. SHA-256: 4787a341e92b9f1764de6e6bc11f7ae5af8d8e21ff5c75f8f71483c60742d798; downloaded copy verified.

Independent validation by jotitadev of the earlier head 949306303c on main b986c11a34: RTX 3070 / NVIDIA 595.99.02 and lavapipe / Mesa 26.0.3. The four-test main/test-only arm passes 2/4, adding #11690 passes 3/4, and the full earlier head passes 4/4 on both devices. This confirms the original per-unit fallback; it does not validate the subsequent within-unit page-hole revision f3e7f47391c, whose author-run RADV evidence is reported above.

Latest reviewer follow-up: exact final head f3e7f47391c passes all five depth-plane tests on Linux / Radeon RX6650XT / RADV Mesa26.2.4 with real Khronos validation in every process, zero VUIDs, no missing layer and no skips. Before the fix, the new within-unit page-hole regression failed while the four existing controls passed; that baseline's production DepthSurface.cpp is identical to reviewed head 949306303cd. Paired logs, full commit IDs and follow-up patch. Native follow-up: main fe2b52c7e43 plus this page fix and the published Bendy prerequisites (#11690, #11704, #6782, #6913), private head d53a4b60cc1, passes16 focused gates and reloads the standing room with camera input into the doorway view; ordinary native exit0, no VUIDs, all writable state restored. Native evidence and reproducible composition. No FPS gain, later-gameplay or audio claim.

Earlier qualification:

Arch Linux; AMD Radeon RX 6650 XT, Mesa RADV 26.2.4-1. Four identical focused GPU tests on the same GPU/build setup, with ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation and ctest -V:

  • Main abed0354680 plus the two new regressions (e96256dade0): existing default/unimported controls pass; memo and partial-watch regressions fail (2/4 pass).
  • fix(agc): collect fresh CPU writes before depth plane stores #11690 plus the regressions (5325ea8e726): memo and existing controls pass; partial-watch regression still fails (3/4 pass).
  • This branch (949306303cd): all4 pass, including preservation of untouched GPU depth.

Every arm has four actual Khronos insertions, zero VUIDs, no missing layer and no skipped tests. Selection:

ctest --test-dir build -R '^(agc_driver_depth_plane_partial_store|agc_driver_depth_plane_partial_store_unimported|agc_driver_depth_plane_cpu_write_after_memo|agc_driver_depth_plane_cpu_write_after_partial_unwatch)$' -V

tools/check_conventions.py --base origin/main --head codex/depth-partial-watch-20261027 passes; tools/pr_overlap.py --branch codex/depth-partial-watch-20261027 was run and shared depth-source changes were checked for duplicates. Windows/other GPU vendors not tested. No FPS or loading-speed claim.

Bendy and the Dark Revival PPSA27624 v01.000.003: the frozen diagnostic integration at 6e6be0d8c4d still exited134 after a fresh whole-plane collect returned0 and a watched unit was overwritten. With this fallback, the same integration becomes e40e6a67284: the probe confirms planeWatch=0 and rangeWatch=1, observes a newer stamp after the per-unit scan, drops that unit from stale depth stores, and preserves its bytes unchanged. The game reaches the rendered opening desk cutscene (screenshot at140s), then closes normally at150s with native exit0; native Khronos active, zero VUIDs, all saves/config/kernel state restored, no remaining processes. Four GPU prerequisite tests also pass with no skips/VUIDs. This native comparison uses the earlier e2d457be345 base, #6782, #6913 and bounded private diagnostics on both arms; the focused four-test comparison above uses current fetched main abed0354680. Gameplay, audio and console-reference graphics equivalence are unverified.

Paired GPU logs, patch, native source pins and cutscene screenshot, SHA256 933e6f14ac3d3249ca96c96187e3a3c0c0d3d3ff2a628af243238938900e764f. Raw memory, game requests, shaders and saves excluded.

Latest-main native qualification: main abed0354680 plus #11690/#11692/#6782/#6913 (26cde7116e2), with no private source diagnostics and fresh eboot/seven-module conversion, passes8/8 GPU checks (five actual Khronos insertions, no skips/VUIDs). The native game renders the intro, shows the Square Stand prompt, accepts Square and reaches the standing first-person view. A later camera/movement input reaches a different guard, AGC graphics: multisampled DCC fast clear has no exact host value, and exits134 at459.73s. This is not a complete gameplay pass; displacement after that input was not visually verified. Native validation remains clean and all state is restored with no leftover processes.

Current-main native pins, GPU log, input actions and standing screenshot, SHA256 55c85a1ae1769d7337ac0210e085218bb97d01d51f3c0baf683ac4f4108bbc8c. No FPS/audio/console-reference graphics claim.

Independent current-head Windows/NVIDIA verification from maskym: 771dbdfec2 plus #11948 merged onto main a13ee2ddd1, Windows 11 26300, RTX 2070 SUPER (NVIDIA 621.01), WinLibs GCC 15.2/UCRT Release. All 11 depth-plane tests passed twice, including page/partial-unwatch and memoized-collect cases; the loader confirmed Khronos validation on every run, with no missing-layer message or VUID. This is contributor-reported evidence for that composition, not a new local or PS5 run.

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 (fix(agc): collect fresh CPU writes before depth plane stores #11690 merged at a00e826a277a; included in main snapshot 2227f136618)
  • Fixes: none
  • Unblocks: PPSA27624 Bendy and the Dark Revival (PPSA27624) #10154
  • GPUs tested: AMD Radeon RX 6650 XT, Mesa RADV 26.2.4-1, Arch Linux
  • AI-assisted: yes

@github-actions github-actions Bot added the unblocks title Names a title ID on the Unblocks line label Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 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 1368 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 4449 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6182 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6185 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6186 core/libs/prx/libSceAgcDriver/CMakeLists.txt
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 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 6977 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7256 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 7275 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7449 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8223 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 8484 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8542 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8592 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9020 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9335 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9432 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9508 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9565 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9672 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9673 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9674 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9675 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9676 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9700 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9712 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9748 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9842 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9852 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9875 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9891 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9892 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9893 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9895 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 9897 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9898 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 9950 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 10193 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10194 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 10233 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10249 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 10333 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10351 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10359 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10435 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 10442 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10581 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10757 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10846 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 10920 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 11351 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 11554 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 11557 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 11920 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
PR 11998 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp
core/libs/prx/libSceAgcDriver/tests/execution/DepthPlanePartialStore.cpp
PR 12051 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 12238 core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp

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

Linux run on NVIDIA and lavapipe, since the description covers RADV only. Head 949306303c on main b986c11a34 (patch applies cleanly). Ubuntu 26.04, GCC 15.2, Release. ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1, -j1. lavapipe selected with VK_ICD_FILENAMES=.../lvp_icd.json.

The four tests from the description, in the same three arms:

RTX 3070 (NVIDIA 595.99.02) lavapipe (Mesa 26.0.3)
main + the two new tests only 2/4: cpu_write_after_memo and cpu_write_after_partial_unwatch fail (a depth flush overwrote CPU descriptors written after a memoized collect) 2/4, same two
+ #11690's DepthSurface.cpp line 3/4: cpu_write_after_partial_unwatch still fails 3/4, same
this head 4/4 4/4

This matches the RADV result: the per-unit fallback is what fixes the partial-watch case, and #11690 alone does not.

Full ^agc suite (without agc_display_buffer_dcc, agc_driver_flip, agc_driver_lds_atomics64, --timeout 30) with #11692 and #11691 applied together on main: 1041/1042 on both devices. The one failure on each also fails on unmodified main on this machine, with the same message: agc_driver_pipeline_journal on the 3070 (the oversized record was not counted as a write failure; it passes when only the NVIDIA ICD is visible), and agc_driver_multisample_retirement on lavapipe (MSAA storage promotion did not retain its source image).

GPUs tested: NVIDIA GeForce RTX 3070 (proprietary 595.99.02, Linux), lavapipe (Mesa 26.0.3, LLVM 21).

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

@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 949306303cd7b7ed30e1ff62678d552dea941e4a. Changes requested for one remaining partial-coverage case.

[P2] Preserve writes in the watched pages of a partly watched unit — DepthSurface.cpp, DepthSurface::WrittenUnits. The fallback retries each unitBytes region as one collection. Write-watch coverage is page-granular: GuestMemory::Unwatch accepts page-sized ranges, and GuestWriteWatch::Watch::Collect rejects a range unless its entire span is covered (takeFresh(..., whole=true))). If a 4 KiB page is unwatched inside a 64 KiB depth unit, the plane scan fails and the retry for that unit also returns 0, even when the CPU-written descriptor is in an adjacent page that remains watched. Because the fallback only calls WrittenSince` when the retry returns nonzero, that CPU write is not marked changed and a subsequent stale depth store can overwrite it.

Please scan the covered page/runs within each unit (preserving the existing behavior for genuinely unwatched ranges) and add a regression that unwatches one page within a unit, writes CPU descriptors into a still-watched page in that same unit, then verifies both descriptor preservation and retained GPU depth. The current test excludes a whole unit, so it does not exercise this case.

This finding is based on the current write-watch coverage/collection implementation and the reviewed fallback path; I did not independently run the GPU reproduction in this environment.

@JJenkx

JJenkx commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed the partial-page coverage case in f415222 and f3e7f47, appended to the reviewed head without rebasing or merge commits.

WrittenUnits retains the whole-plane and per-unit fast paths. When a unit is only partly watched, it now collects page-aligned fragments and checks writes in the covered pages. It collects initial pages before establishing their generation, and partly watched single-unit surfaces take the same fallback. Excluded pages remain unwatched.

The new --cpu-write-after-page-unwatch regression unwatches a 4 KiB page inside the descriptor's 64 KiB unit, writes descriptors into the adjacent watched page after a depth draw, and checks descriptor preservation plus retained GPU depth in an untouched unit.

  • Before: new regression fails with descriptor corruption; the four existing controls pass. This was run at 5f9eecf801c on the private Bendy prerequisite integration; its production DepthSurface.cpp is byte-identical to reviewed head949306303cd.
  • Exact final PR head f3e7f47: 5/5 pass on Linux / Radeon RX6650XT / RADV Mesa26.2.4, with ANYPS5_REQUIRE_VULKAN=1, ANYPS5_NO_SHADER_CACHE=1, actual Khronos validation active in all five processes, zero VUIDs, no missing layer and no skips. Convention checks pass.

Selection: ctest --test-dir build -R '^agc_driver_depth_plane_(cpu_write_after_(page_unwatch|partial_unwatch|memo)|partial_store(_unimported)?)$' -V

Paired logs, results and follow-up patch, SHA256 622b6b0499e846f60603dc4f4650b1155ca4542159f0e235e7b538559b6efc39. Native follow-up completed: latest-main fe2b52c7e43 plus the published Bendy prerequisite stack, including this page fix, at private head d53a4b60cc1. All 16 focused gates pass (12 actual Khronos processes, zero VUIDs/no skips). Fresh executable and seven module conversions reload the standing-room save and accept camera input into the Archgate doorway view. Ordinary close at210s returns native0; saves, memory saves, configuration and kernel limit restore, with no game processes left. Native Khronos insertion1, zeroVUIDs. No FPS gain or later-gameplay/audio claim. Native summary, screenshot, conversion hashes, test log and reproducible source composition, SHA256 e218ec07155ad00ad0fef3dad1251fb4c9359128725d4d6563b08e379628ad48.

Latest upstream refresh (2026-10-27): private integration 444d40a7f9897affec660ef2aab16e9bca85d67d applies the same twelve prerequisite/fix commits to main f9b2db1d4143ae247e5c3d0c0ced875c0aed906f. This includes #11704, #11690, #11692 with its within-unit page-hole revision, and peer #6782/#6913. All 16 focused checks passed with 12 Khronos validation-layer insertions, no VUIDs, no missing layer, and no skips. Eight converted outputs were regenerated from this exact integration. The normal pipelined native run loaded the ordinary manual office save, showed the doorway without camera input, and closed normally at 240 seconds with exit 0; saves, memory saves, config bytes and kernel setting were restored, with no remaining native process. Native validation was off; the focused GPU checks above used KHR validation. This is composition evidence on newer upstream, not an unmodified-main benchmark or a source speed claim.

Fresh-main source composition, focused results, trace/digest and reviewed X11 screenshot, SHA-256 111e04dc947b9feb3ef75762f103a2d753fdc882ffef98e963510a9fdf9bd013. XComposite retained old loading-screen pixels in these experiments; the included scene proof uses the active-window X11 readback. Initial office only; audio and later gameplay remain unverified.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 27, 2026
@JJenkx
JJenkx force-pushed the fix/agc-partly-watched-depth-planes branch from f3e7f47 to 1646ca2 Compare October 27, 2026 10:37
@JJenkx

JJenkx commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

@MarcZX10 The page-coverage follow-up is retained on the synchronized branch and now has the qualification below. Please re-review the updated head and clear the earlier request if this satisfies it.

Current-main refresh, 2026-10-27 10:18 UTC pass: exact head 1646ca2842119411060c4db6304e47dd18a21fd8 on main 3fea2a937ba9fbab2f06c51691fe0c5763659aa3. Five child topic commits remain stacked on refreshed #11690. The existing within-unit page-coverage correction and its regression are preserved exactly; no genuinely unwatched page is falsely marked written. All submodule pointers match that main.

Linux Release, RX 6650 XT/RADV Mesa 26.2.4, required Vulkan and shader caches disabled. Matched main passes all three existing controls three times (9 passes). Candidate passes six groups × three repetitions (18 passes), then 18 after restoration. The exact within-unit page-hole case additionally passes three times with APS5_NO_DIRECT_DEPTH_COPY=1. Replacing only production with its pre-page-correction parent fails exactly that page-hole case; the other five controls pass. That negative control uses normal mode; the forced-buffer variant is a positive qualification, not a separate negative control. The within-unit regression places a 4 KiB unwatched hole and CPU descriptors in an adjacent watched page of the same 64 KiB unit, checking descriptor preservation and retained GPU depth.

Every individual physical execution proves RX 6650 XT selection and actual Khronos instance/device-layer insertion; zero skips, VUIDs or missing-layer failures. Restored production source matches the candidate, and the rebuilt AGC driver is byte-identical to its initial candidate. The forced-buffer setting is recorded in the executed harness/process environment and linked to the startup flag; CTest does not print every inherited variable. Conventions and whitespace pass. This is synthetic GPU regression evidence, without a new title, console, Windows or performance run. Earlier contributor results retain their original exact pins.

Exact source/dependency pins, initial/negative/restored raw logs and JUnit, forced-buffer receipt, independent reviews, hashes and service-owned FIFO/PTY receipts. SHA-256: 4787a341e92b9f1764de6e6bc11f7ae5af8d8e21ff5c75f8f71483c60742d798; downloaded copy verified.

AI-assisted: yes.

@github-actions github-actions Bot added build agc libSceAgc* and removed needs rebase Conflicts with main, rebase needed labels Oct 27, 2026
@ycbuzi

ycbuzi commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Windows run of 1646ca2842 merged onto main 9af563f33d (ae009f8463, clean), since Tested has no Windows run. Windows 11 Home 10.0.26200, WinLibs GCC 15.2.0 r7 (MinGW-w64 UCRT), Release. One GPU at a time with ANYPS5_GPU, plus ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1, ctest -V --repeat until-fail:2. Each log's Selected GPU line names its device.

device 6 depth-plane tests
GeForce RTX 4070 SUPER, NVIDIA 616.92 5 pass; agc_driver_depth_plane_cpu_write_after_page_unwatch fails
GeForce GTX 1650 SUPER, NVIDIA 616.92 same
AMD Radeon(TM) Graphics (iGPU), AMD 32.0.21030.2001 same

The five that pass are cpu_write_after_memo, cpu_write_after_partial_unwatch, partial_store, partial_store_unimported and partial_store_buffer_copy. The build has no errors or warnings.

cpu_write_after_page_unwatch fails in its setup on Windows, at tests/execution/DepthPlanePartialStore.cpp:152, the descriptor page lost write watching, before the depth draw. The test unwatches one page, Unwatch(base + 4u * Block + 8192u, 4096u), and then requires the page at + 4096 to still be watched. On Windows, Unwatch goes through WriteWatchCoverage::Exclude (Execution/include/WriteWatchCoverage.hpp:41). That sets excluded[block] = pageMask(0, pages) for every 64 KiB block the range touches, so the whole descriptor unit becomes unwatched. The non-Windows path unregisters only the requested range (GuestWriteWatchUnregister_nid_postfix). This PR doesn't change that file, so main behaves the same, and a 4 KiB hole can't be made with Unwatch on Windows.

An untested idea, if the case should run here: make the hole by unwatching the whole unit and rewatching the pages around it with GuestMemory::Rewatch, which restores page-aligned ranges on Windows. Or skip that mode on Windows when the setup check can't hold.

Negative control: with main's Graphics/src/DepthSurface.cpp and this head's test, on the RTX 4070 SUPER, cpu_write_after_memo fails with a depth flush overwrote CPU descriptors written after a memoized collect, cpu_write_after_partial_unwatch fails, and cpu_write_after_page_unwatch fails at the same line 152.

AI-assisted: yes (Claude Code)

@maskym

maskym commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Windows + NVIDIA result for head 1646ca2842, merged into main f759e165d9: the new agc_driver_depth_plane_cpu_write_after_page_unwatch fails on this host; the other two new tests and the three existing agc_driver_depth_plane_partial_store* pass.

Host: Windows 11 26300, Intel i7-12700K, NVIDIA GeForce RTX 2070 SUPER (vendor 0x10de, device 0x1e84; Vulkan loader 1.4.357 from the NVIDIA driver), Khronos Validation Layers nightly 1.4.366 through VK_ADD_LAYER_PATH, WinLibs GCC 15.2.0 (x86_64-ucrt-posix-seh, r6), Release, BUILD_TESTING=ON, Ninja. Build clean.

agc_driver_depth_plane_cpu_write_after_page_unwatch ***Failed    0.41 sec   (3 of 3 runs alone, same message)
AGC graphics: the descriptor page lost write watching
agc_driver_depth_plane_cpu_write_after_partial_unwatch   Passed  0.66 sec
agc_driver_depth_plane_cpu_write_after_memo              Passed  0.46 sec

The check is DepthPlanePartialStore.cpp line 152: after GuestMemory::Unwatch(base + 4 * Block + 8192, 4096) the test expects Watched(base + 4 * Block + 4096, 4096) to hold. On Windows Unwatch goes through WriteWatchCoverage::Exclude (Execution/include/WriteWatchCoverage.hpp lines 41-55), which excludes every page of each 64 KiB block the range touches; that is its documented contract, since it models host imports, which are whole blocks there (tests/WriteWatchCoverage.cpp: Exclude(base + block + 4096, 1) then "the imported block is still watched" must fail). Only Restore is page-granular. The Linux path unregisters pages (GuestWriteWatchUnregister), so the 4 KiB expectation holds there and on your RADV runs, but not on Windows, where the whole descriptor block becomes unwatched and the next check at line 153 (!Watched(base + 4 * Block, Block)) would still pass. The --cpu-write-after-partial-unwatch mode unwatches a whole Block, which is why it passes here.

So this is the test's assumption rather than the library change: on Windows the page-unwatch mode should either skip (as the modes already do when WriteWatched() is false) or expect block granularity under _WIN32. DepthSurface.cpp itself is not implicated by this run.

Validation: same focused run on main and this tree (VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1, ctest -R '^(agc|guest_video_out|video_out)' --parallel 4 -V), layer inserted in every test, no was not found but was requested line; both logs report only the pre-existing VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (18x, #11990 / #6782), so this PR adds no new VUID- error. The tree also carried the open PRs #11951, #11711, #11704, #11691, #11690, #11794, #11949, all merged cleanly. Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

…larity

On Windows, GuestMemory::Unwatch excludes every page of each 64 KiB
block it touches, so unwatching one page of the descriptor unit left the
whole unit unwatched and the "descriptor page lost write watching" check
failed. Unwatch the unit and return only its descriptor page with
Rewatch there, which is page-granular, so the unit is partly watched on
every platform. Linux keeps the single-page Unwatch.

Diagnosed by maskym on Windows 11 26300 with an RTX 2070 SUPER.

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

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the diagnosis, it's right. On Windows Unwatch goes through WriteWatchCoverage::Exclude, which drops whole 64 KiB blocks, so the single-page unwatch left the entire descriptor unit unwatched.

c581723557 changes only the test. In --cpu-write-after-page-unwatch mode on Windows, it now unwatches the whole unit and then returns just the descriptor page with Rewatch. Rewatch is page-granular there (WriteWatchCoverage::Restore), so the unit ends up partly watched, the state the mode is meant to test. Linux keeps the single-page Unwatch; Rewatch is a no-op there. The library change is untouched.

Checked here (Windows 11 Enterprise 10.0.22621, WinLibs GCC 15.2.0 UCRT r7, Release, BUILD_TESTING=ON):

  • agc_driver_depth_plane_partial_store_tests builds.
  • The CPU-only agc_write_tracking* tests pass 3 of 3 (4 tests). They include CheckRewatch, which verifies on Windows that unwatching a block and then re-watching part of it leaves exactly those pages watched.

Not run here: the depth-plane Vulkan tests. Their GPU runs on this machine are paused by our shared GPU queue. Could you rerun agc_driver_depth_plane_cpu_write_after_page_unwatch and the other five depth-plane tests on your RTX 2070 SUPER at the new head?

AI-assisted: yes (Claude Code).

@ycbuzi

ycbuzi commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Windows rerun of the new head c581723557 (the Unwatch + Rewatch test setup), merged onto main b4b0c220a9 (ce91c18ad4, clean), on the same three GPUs as my first run. Windows 11 Home 10.0.26200, WinLibs GCC 15.2.0 r7 (MinGW-w64 UCRT), Release, one GPU at a time with ANYPS5_GPU, ANYPS5_REQUIRE_VULKAN=1 and ANYPS5_NO_SHADER_CACHE=1, ctest -V --repeat until-fail:2.

device 6 depth-plane tests
GeForce RTX 4070 SUPER (0x2783), NVIDIA 616.92 all pass, both runs
GeForce GTX 1650 SUPER (0x2187), NVIDIA 616.92 all pass, both runs
AMD Radeon(TM) Graphics (1002:164e), AMD 32.0.21030.2001 all pass, both runs

agc_driver_depth_plane_cpu_write_after_page_unwatch now gets past its setup and passes on all three, so the Rewatch setup gives the partly watched unit on Windows.

Negative control, now a real red: with main's Graphics/src/DepthSurface.cpp (which has #11690) and this head's test, on the RTX 4070 SUPER, cpu_write_after_page_unwatch and cpu_write_after_partial_unwatch both fail with AGC graphics: a depth flush overwrote CPU descriptors written after a memoized collect.

AI-assisted: yes (Claude Code)

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

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

New head 771dbdfec2 only deletes the test comment I added in c581723557, which failed the conventions check (comments are for technical debt only). No code changed, so ycbuzi's three-GPU run and negative control on c581723557 still apply.

AI-assisted: yes (Claude Code).

@maskym

maskym commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Retested head 771dbdfec2 on Windows + NVIDIA, merged into main a13ee2ddd1 together with #11948 (both merged cleanly): the reworked page-unwatch test passes here now.

Host: Windows 11 26300, Intel i7-12700K, NVIDIA GeForce RTX 2070 SUPER (vendor 0x10de, device 0x1e84; Vulkan loader 1.4.357 from the NVIDIA driver 621.01), Khronos Validation Layers nightly 1.4.366 through VK_ADD_LAYER_PATH, WinLibs GCC 15.2.0 (x86_64-ucrt-posix-seh, r6), Release, BUILD_TESTING=ON, Ninja. Build clean.

ctest --test-dir build -R '^agc_driver_depth_plane' with VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, ANYPS5_NO_SHADER_CACHE=1, ANYPS5_REQUIRE_VULKAN=1, VK_LOADER_DEBUG=error,warn,layer, --repeat until-fail:2: all 11 depth-plane tests pass, 2 runs each, including agc_driver_depth_plane_cpu_write_after_page_unwatch (0.35 s), _after_partial_unwatch and _after_memo; the loader inserted the validation layer in every run, no was not found but was requested line and no VUID- from these tests. Not run on a PS5.

AI-assisted: yes (Claude Code), the runs and the numbers above are from this machine.

@adriadam10 adriadam10 self-assigned this Oct 28, 2026
@adriadam10
adriadam10 dismissed MarcZX10’s stale review October 28, 2026 08:51

Dismissing a stale review: the requested changes were addressed after it (new head) and the merge queue blocks on it. Please request changes again if anything is still open.

@JJenkx

JJenkx commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Linux run at this PR's exact head 771dbdfec2 (771dbdfec22d74aa178afff4e042946ddc4a3073), not merged onto anything else; its base on main is 7486617958.

Arch Linux, kernel 7.2.9, Ryzen 9 7950X, AMD Radeon RX 6650 XT (RADV NAVI23, Mesa 26.2.4), g++ (GCC) 16.2.1, Release, BUILD_TESTING=ON, private worktree. The tests ran through the host's exclusive GPU slot.

  • ANYPS5_REQUIRE_VULKAN=1 ctest -V -R '^agc_driver_depth_plane_(cpu_write_after|partial_store)': all 6 tests pass in each of 3 runs (18 passes, none skipped). They are agc_driver_depth_plane_partial_store, _cpu_write_after_page_unwatch, _cpu_write_after_partial_unwatch, _cpu_write_after_memo, _partial_store_unimported and _partial_store_buffer_copy.
  • Each log shows the RX 6650 XT selected (not llvmpipe).

I didn't run the new test against the base to show it failing there.

@adriadam10
adriadam10 merged commit bf969db into boykopovar:main Oct 28, 2026
13 of 14 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked WrittenUnits against the diff: whole-plane scan, then per-unit, then page-aligned fragments inside partly watched units; unwatched pages keep the old behaviour. Both new tests are registered in ctest and fail without the change (author's negative control on RADV, jotitadev on NVIDIA/lavapipe); the Windows block-granularity setup passes on ycbuzi's and maskym's runs; conventions green. The earlier page-coverage request is met by this head; merged.

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

Labels

agc libSceAgc* build 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