Repository navigation
fix(agc): sample resident depth surfaces when a stage-A texture record hits - #1957
Conversation
…d hits fastTexture took the Textures() cache entry of a stage-A image record without asking whether a depth surface is resident at the address. The full lookup in cachedTexture returns DepthSurfaceTexture first; the fast path skipped it, so once a guest-memory entry existed for a depth target's descriptor, every later sampled read got that entry and saw the guest memory under the target, which a depth target never writes. The fast path now returns nothing while a depth surface is resident there, and the lookup falls back to cachedTexture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed the full diff and the surrounding lookup paths. The regular cachedTexture path asks DepthSurfaceTexture before the guest-memory cache; this guard makes a stage-A cache hit take that same full lookup whenever the address belongs to a resident depth/stencil surface. DepthSurfaceAt is synchronized and checks both depth and stencil addresses. Current-main ancestry is exact. Upstream Build passed on Linux and Windows, along with Conventions; the PR also reports targeted AGC suites and a before/after Astro reproduction. No targeted automated regression test was added, so future coverage of this fast-path fallback would be useful, but the reported GPU reproduction and full CI provide good evidence for this focused change.
Dextroid17
left a comment
There was a problem hiding this comment.
Verified on Linux, which checks the claim in code and re-runs the suites on a second device.
The claim, in code — confirmed. cachedTexture asks DepthSurfaceTexture before it looks at the cache (ShaderResources.cpp:288), the diff adds exactly the one line to the fast path (if (DepthSurfaceAt(address)) return nullptr;), and DepthSurfaceAt is the same depth/stencil predicate already used for the storage-image refusal at line 567. So the fast path was the only route to a guest-memory texture that skipped the resident-surface question, as the body says.
Your suites, on lavapipe (the author's run was Windows/NVIDIA):
agc_driver_tests ............ exit 0
agc_driver_graphics_tests ... exit 0
agc_driver_recorder_tests ... exit 1
That third one is not this change: with the guard reverted to main, everything else identical, it fails the same way — AGC graphics: the partial publish did not copy exactly the partly covered unit, exit 1. Pre-existing and lavapipe-only (it is the same assertion I ran into verifying #1046), so it should not hold this up.
Not verified here: the effect. There is no Astro's Playroom dump on this machine, so the title evidence — the tile classifier counting ~2900 tiles, the lit objects, the GDS counters — stands on the author's setup. Worth saying plainly, because for a one-line change with no test that evidence is the whole proof. A test that asserts "the stage-A fast path refuses while a depth surface is resident at the address" would make it self-protecting.
Related-PR check: no changed-line overlap. #1430 touches DepthSurfaceTexture call sites but not fastTexture; #425 and #454 touch DepthSurfaceAt call sites (storage images, RetireDepthSurfaces) but not this guard. They do share the predicate, which is the same source of truth, so they should compose rather than conflict.
Written with AI assistance.
|
Linux results, since this was tested on Windows only. Everything passes here. Nobara 44 (Linux 7.2), GCC 16.2.1, Release,
The CPU failure is |
|
A side effect I found running Astro's Playroom further in, after opening this PR:
I kept this PR to the fast-path check. The shape rule is #1495's topic. |
|
The reachability half checks out in the code, and it is worth putting on the record because it is what makes this a known gap rather than a regression from your PR. The throw you quote is at Two things I would keep as they are. Reporting that your change exposes an existing throw rather than causing one, with the Written with AI assistance. |
…epth-surface fix(agc): sample resident depth surfaces when a stage-A texture record hits
What
ShaderResources::fastTexture(the stage-B check for a stage-A image record) reused theTextures()cache entry for the descriptor without asking whether a depth surface is resident at the address.cachedTexturereturnsDepthSurfaceTexturebefore it looks at that cache; the fast path skipped that step.So once a guest-memory entry exists for a depth target's descriptor (made while no surface was resident there, or while it was retired), every later sampled read of the target takes the fast path and gets the guest-memory texture. The memory under a depth target is never written (the depth lives only in the Vulkan depth image), and
UnchangedSincekeeps proving that entry current, so the reads stay on it for good.fastTexturenow returnsnullptrwhileDepthSurfaceAt(address)finds a resident depth or stencil plane there. The lookup then falls back tocachedTexture, which asksDepthSurfaceTexturefirst.Found in Astro's Playroom (PPSA01325):
0x5002a8500, 240x135 groups over the 3840x2160 D32S8 target0x517370000) reduces each 16x16 tile's depth in LDS. It skips a tile when the max depth is <= 0 or the min depth is >= 1.APS5_NO_STAGE_A_IMAGES=1, or with this change, the classifier counts about 2900 tiles on the title screen and those objects are lit.DepthSurfaceTexturewas never reached for those dispatches before the change. After it, the lookup picks the same image the G-buffer pass draws into.0x50028e000, which feeds the game's AO and particle soft fade, read the same zeros.Related open PRs, no overlap in the changed lines: #1430 changes
fastRevalidate, the reuse proof of a whole set; this is the per-image record path. #425 and #454 changeDepthSurfaceTextureand depth surface retirement.Tested
Windows 11, WinLibs GCC 15.2, RTX 3060 Laptop:
agc_driver_tests,agc_driver_graphics_testsandagc_driver_recorder_testsbuilt on this branch; all pass.tools/check_conventions.py --base upstream/mainpasses.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt.mdfiles or images added to the repository (attach them to this PR)🤖 Generated with Claude Code
https://claude.ai/code/session_01UTjpbMX7BUFMZZaxJE98zV