Skip to content

fix(agc): fail a template's proof on a released texture and audit it with the full walk - #8047

Merged
oneandonlydean merged 4 commits into
boykopovar:mainfrom
fisherjoey:fix/template-texture-audit
Oct 20, 2026
Merged

oneandonlydean merged 4 commits into
boykopovar:mainfrom
fisherjoey:fix/template-texture-audit

Conversation

@fisherjoey

@fisherjoey fisherjoey commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

What

A cached ShaderResources (a dispatch or draw template) is reused when Revalidate proves it current. The fast proof checks each bound sampled texture's memory, keys and pending writes, but not whether the sampled lookup would still return the bound Texture. A template over an unchanged surface can therefore keep an object the lookup no longer returns (#8040). This PR makes two changes.

  • Released textures: fastRevalidate and fastRevalidateEach fail, with the new reason replaced texture, when a bound texture is Released(). That is the flag fix(agc): drop resource-cache entries that hold released sampled textures #6492 sets when the sampled cache drops a texture something still holds. fix(agc): drop resource-cache entries that hold released sampled textures #6492 drops such templates at the next ResourceCache::Insert. Until that Insert, Find still served them and their fast proof passed. With this change the full walk runs, its lookup returns the new entry, the proof fails, and the template is rebuilt. Cost: one atomic load per bound texture per proof.
  • Audit: a template whose last full walk is more than APS5_TEMPLATE_AUDIT_MS old (default 1000 ms, 0 turns it off) takes the full walk in place of the fast proof, with the new reason audit. This covers the case nothing marks: the lookup would now return something else for an unchanged surface, but no lookup has run, so no entry was replaced. For example, a snapshot's surface becomes host-imported and the lookup would view its storage image instead. The walk repeats the real lookups, a different answer fails the proof, the template is rebuilt, and the entry that lookup replaced is released, which then fails every other template binding it. An unchanged template passes the walk and goes back to the fast proof. The interval is a variable so the tests can use 250 ms, and it has a row in docs/dev/ENVIRONMENT.md.

Fixes #8040

Tested

Related

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); this change adds no stubs
  • 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; none added
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: agc: a cached template keeps a sampled texture the lookup no longer returns, so Demon's Souls level lighting goes dark at twice the draws #8040
  • Unblocks: none
  • GPUs tested: lavapipe (Mesa llvmpipe), Linux, for the tests; NVIDIA GeForce RTX 5070 Ti, driver 595.91.07, Linux (Nobara, kernel 7.2), for the tests and the game runs
  • AI-assisted: yes

AI-assisted: yes

@github-actions github-actions Bot added the fix error Closes an issue (Fixes #N) label Oct 19, 2026
@github-actions

github-actions Bot commented Oct 19, 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
PR 1395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 2434 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5021 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/tests/execution/SampledCacheBudget.cpp
PR 5371 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5426 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5431 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/ENVIRONMENT.md
PR 5499 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 5925 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6044 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6146 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6177 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
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
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6192 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6194 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6202 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6209 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6223 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6280 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6300 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6412 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6481 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6498 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 6501 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6636 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 6658 docs/dev/ENVIRONMENT.md
PR 6682 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6683 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6747 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6788 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6808 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6868 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 6946 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 6947 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 6951 docs/dev/ENVIRONMENT.md
PR 6959 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7002 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7048 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7085 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7154 core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7201 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7395 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7446 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7457 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/ENVIRONMENT.md
PR 7464 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/ENVIRONMENT.md
PR 7484 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 7505 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7514 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7604 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/ENVIRONMENT.md
PR 7642 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
docs/dev/ENVIRONMENT.md
PR 7644 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7647 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 7689 core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
PR 7800 core/libs/prx/libSceAgcDriver/CMakeLists.txt
core/libs/prx/libSceAgcDriver/Graphics/include/ShaderResources.hpp
core/libs/prx/libSceAgcDriver/Graphics/src/ShaderResources.cpp
core/libs/prx/libSceAgcDriver/tests/execution/SampledCacheBudget.cpp
PR 7922 docs/dev/ENVIRONMENT.md
PR 8004 docs/dev/ENVIRONMENT.md
PR 8014 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8077 docs/dev/ENVIRONMENT.md
PR 8134 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8206 core/libs/prx/libSceAgcDriver/CMakeLists.txt
docs/dev/ENVIRONMENT.md
PR 8267 core/libs/prx/libSceAgcDriver/CMakeLists.txt
PR 8489 core/libs/prx/libSceAgcDriver/CMakeLists.txt

@fisherjoey

Copy link
Copy Markdown
Contributor Author

Results on a current-main base, with this PR's driver swapped in and nothing else changed.

Base: main 6762694 plus #6280, #6926 and #7844, and a local stencil-export workaround that Demon's Souls needs on this NVIDIA box (not part of any PR). Demon's Souls (PPSA01341 v1.07), RTX 5070 Ti, NVIDIA 595.91.07, default texture cache budget, 900 s per run. The crawl measure is indexed indirect draws per (indirect + multi-indirect) draw per 10 s window: about 210 normally, about 410-440 in the crawl.

Build Run Ratio (median) Presents per 10 s
base 229 ~415 (crawl) 5.92
base 230 438 (crawl) 5.55
base + this PR 231 213 8.84
base + this PR 232 214 9.21
base + this PR 233 213-214 9.38

No crashes in the three runs with the PR, and no storage cache evictions in any of the five, so none of them was rescued by an eviction. Small sample, but the base crawled in both runs that reached the level, and the PR runs were normal from the first level window.

AI-assisted: yes

@MarcZX10

Copy link
Copy Markdown
Contributor

Thanks for the current-main comparison. Two base runs crawled while the three PR runs were normal from the first level window, and none of the five had storage-cache evictions; that is useful evidence for the audit change, with the small sample size clearly stated. The description still says more current-main runs are queued. Please fold this table and its limitation into the Tested section so the PR summary reflects the new result.

@fisherjoey

Copy link
Copy Markdown
Contributor Author

Done, the Tested section now has the five-run table result and the small-sample note.

AI-assisted: yes

…with the full walk

The fast proof of a cached ShaderResources proves each sampled texture
from write stamps, keys and the pending registry. It never asks whether
the sampled lookup would still return the bound Texture, so a template
whose surface memory is unchanged keeps binding an old object:

- After the sampled cache drops or replaces the entry (boykopovar#6492 marks the
  texture released), Find keeps serving the template until the next
  Insert, and its fast proof passes.
- When the lookup's answer changes without any lookup running (a
  snapshot whose surface became host-imported is viewed through its
  storage image from then on), nothing replaces the entry and the
  template keeps the snapshot until it leaves the resource cache.

The fast proof now fails with 'replaced texture' when a bound texture
is released. A template whose last full walk is older than
APS5_TEMPLATE_AUDIT_MS (default 1000, 0 turns it off) takes the full
walk instead of the fast proof ('audit'), so a different lookup answer
fails the proof and the template is rebuilt.
…ebuild

agc_driver_resource_cache_replaced_texture clears the sampled cache
under a template that takes the fast proof and requires the next proof
to fail. agc_driver_resource_cache_lookup_changed checks that a proof
past the audit interval takes the full walk and keeps an unchanged
template, then host-imports the surface (no lookup runs) and requires
the template to stop proving current. Both run over a write-watched
surface so the template takes the fast proof.
@fisherjoey
fisherjoey force-pushed the fix/template-texture-audit branch from b34b670 to 3c43ce3 Compare October 19, 2026 22:17
@oneandonlydean oneandonlydean self-assigned this Oct 20, 2026
@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks for this. One small change to the new test, please.

resource-lookup-changed exits 77 with "skipped, the lookup-changed test requires host imports" and "skipped, the host import of the watched surface was refused". Neither text matches the device-limitation pattern in tools/check_skips.py, so on any runner without host imports the job would fail instead of recording a skip. Linux CI's llvmpipe has host imports, so it doesn't show up today. Could you use the existing phrase "skipped, host imports are unavailable" for both? That one matches.

Separately, the time-based audit (part 2) changes behaviour for every title, so it is going to the maintainer for a design call. The Released check (part 1) looks good.

@wachi35676

Copy link
Copy Markdown
Contributor

Windows runs of the tests (the PR ran them on Linux only), on NVIDIA and on an AMD iGPU.

Setup: Windows 11 26300, MinGW GCC 15.2 Release, main eb75006 + this PR (3c43ce3, merges cleanly). GPUs: RTX 5070 Ti (NVIDIA 617.42) and Ryzen 5 9600X Radeon iGPU (ANYPS5_GPU=AMD, 32.0.21042.62), both with ANYPS5_REQUIRE_VULKAN=1.

  • agc_driver_resource_cache_replaced_texture and agc_driver_resource_cache_lookup_changed passed 5 of 5 on each GPU. Neither skipped: host imports are available on both drivers.
  • Negative control: I put ShaderResources.cpp and ShaderResources.hpp back to main and kept the tests. Both tests fail on both GPUs, with the messages the PR gives: a template binding a texture whose cache entry left still proved current and a proof past the audit interval did not take the full walk.
  • ctest -R "agc|shader|spirv|recomp" (825 tests, which include the sampled-cache-budget, recorder, image-table and draw-cache-reuse groups): on NVIDIA 2 failed (msaa_dcc_clear_4, pass_input_hazard); on AMD 5 failed (agc_trimmed_import, msaa_dcc_clear_4, layered_volume_vertex_no_gpl, draw_cache_reuse_off, stencil_replay_no_gpl). All of these also fail on main on this machine. No new failures.
  • check_conventions.py --base origin/main passes.

No title runs here, so the Demon's Souls result and the 2-3% audit cost are not re-measured. One small point from reading the code: APS5_TEMPLATE_AUDIT_MS goes through strtoull, so a value that is not a number reads as 0 and turns the audit off without a message.

AI-assisted: yes (Claude Code); results above were run on this machine.

@MarcZX10

Copy link
Copy Markdown
Contributor

I checked exact head 3c43ce33a074c1c6df0579e458a777f6c0224426: resource-lookup-changed still prints “skipped, the lookup-changed test requires host imports” and “skipped, the host import of the watched surface was refused.” Neither matches DEVICE_LIMITATION in tools/check_skips.py; the existing “skipped, host imports are unavailable” prefix does. Could you update both skip messages as requested so a host without import support is classified as a device skip?

oneandonlydean and others added 2 commits October 21, 2026 03:35
Co-authored-by: Joey Fisher <fisherjoey@ymail.com>
… skip

resource-lookup-changed skipped with its own texts when the device has no
host imports or refuses the import of the watched surface. Neither matches
DEVICE_LIMITATION in tools/check_skips.py, so a runner without host imports
would fail the job instead of recording a device skip. Both now print the
existing "skipped, host imports are unavailable".
@fisherjoey

Copy link
Copy Markdown
Contributor Author

Both skip messages in resource-lookup-changed now print the existing "skipped, host imports are unavailable", so a runner without host imports records a device skip (56ddbbb).

I meant to rebase onto main, but the branch already had main merged in (1cb6482), so I added the commit on top of that merge instead of force-pushing over it. The branch merges cleanly with current main 286908f.

On this head, agc_driver_resource_cache_replaced_texture and agc_driver_resource_cache_lookup_changed passed 3 of 3 each on lavapipe (llvmpipe) and on an RTX 5070 Ti (NVIDIA 595.91.07), both with ANYPS5_REQUIRE_VULKAN=1. Neither skipped. check_skips.py on the ctest junit and check_conventions.py --base origin/main both pass.

Thanks @wachi35676 for the Windows runs on NVIDIA and AMD, and for the negative control.

AI-assisted: yes

@oneandonlydean
oneandonlydean merged commit 10abe7d into boykopovar:main Oct 20, 2026
10 checks passed
@fisherjoey
fisherjoey deleted the fix/template-texture-audit branch October 20, 2026 16:00
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: a cached template keeps a sampled texture the lookup no longer returns, so Demon's Souls level lighting goes dark at twice the draws

4 participants