Skip to content

fix(shader): key the device's capabilities and extensions by a digest - #10438

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/cache-key-target-digest
Oct 24, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
milescoviello:fix/cache-key-target-digest

Conversation

@milescoviello

Copy link
Copy Markdown
Contributor

What

RecompileCacheKey puts the whole SpirvTarget into every recompile cache key. Two of its fields are lists: the device's SPIR-V capabilities, and the SPIR-V extension names, which go in one byte per 64-bit word. On a device that enables a dozen extensions, that is about 350 words of the same device description in every key. The key is built and compared on every dispatch and draw, kept in memory by every prepared handle and cache entry, and written into every disk cache entry.

  • In Forspoken's (PPSA03984) disk cache on an RTX 4070 Ti, the 24,774 entries' keys have a median of 833 words. About 350 of them are the 12 extension names (SPV_EXT_demote_to_helper_invocation ... SPV_KHR_terminate_invocation), their lengths and the capability list.
  • In a jemalloc heap profile of Ghost of Tsushima (PPSA02225) at about 900 s, RecompileCacheKey::append holds about 380 MiB of live memory. That title is killed by its 20 GB memory cap in its opening, so this is memory it needs back.

How

append(key, SpirvTarget) now adds the two lists as one 128-bit digest instead of word by word. The digest mixes the capability count and values, then each extension's length and its bytes eight at a time, through two independent 64-bit multiply-xor chains. Every other SpirvTarget field is appended as before. The disk cache source version changes with the recompiler sources, so old entries aren't misread.

Tested

Ubuntu 26.04.1, GCC 15.2, Release, RTX 4070 Ti, NVIDIA 615.71.09. The commit was tested as 6fbdaa9d69 on main f3456a4 and is unchanged (git range-diff) on the current head d7d9747e7d, rebased onto main 3b23d18.

  • New verifyTargetFeatureKey in agc_shader_memory. Equal lists in other storage give the same key. A different last byte of an extension name, a byte moved between two names, or an added capability each give a different key. A key built with 40 extension names is no longer than one built with 2. With only the test on main, agc_shader_memory fails 3 of 3 with target feature key: the key grows with the device's extension names; with the change it passes 3 of 3.
  • The 38 tests matching ^agc_shader_memory$|^agc_spirv_module$|^agc_shader_|shader_disk_cache|^agc_driver_graphics$|pipeline_journal pass 3 of 3 on main 9d4fb4f and on 6fbdaa9d69.
  • Khronos validation layer (LunarG SDK 1.4.363): VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation ANYPS5_NO_SHADER_CACHE=1 ANYPS5_REQUIRE_VULKAN=1 on the 5 tests matching ^agc_shader_memory$|^agc_spirv_module$|^agc_shader_disk_cache$|^agc_driver_graphics$|^agc_driver_pipeline_journal$. main 9d4fb4f: 5 of 5 pass; 6fbdaa9d69: 5 of 5 pass. Neither log reports the layer missing, and neither has a VUID.
  • Windows 11 VM (GeForce GT 1030, driver 582.66, WinLibs GCC 15.2.0 r7, Release): the same 5 tests pass 3 of 3 on main at the merge base (f3456a4) and on 6fbdaa9d69.

Not checked by me: AMD, Intel, macOS, and a title run measuring the saving (Ghost of Tsushima needs more free host memory than this machine has right now).

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: none (it lowers the memory Ghost of Tsushima, PPSA02225, needs in its opening)
  • GPUs tested: NVIDIA GeForce RTX 4070 Ti, driver 615.71.09, Ubuntu 26.04.1; NVIDIA GeForce GT 1030, driver 582.66, Windows 11 VM
  • AI-assisted: yes (Claude Code)

🤖 Generated with Claude Code

Every recompile cache key appended the target's capability list and
each SPIR-V extension name one byte per 64-bit word, so on a device that
enables a few dozen extensions most of every key was the same device
description: built and compared on every dispatch and draw, and kept in
every in-memory key and disk cache entry. The two lists now enter the key
as a 128-bit digest over the capabilities and the length and bytes of
each extension name, eight bytes per step.

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

github-actions Bot commented Oct 24, 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 5371 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6235 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 6412 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 6488 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 7201 core/shader/recompiler/CacheKey.hpp
PR 7410 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 7484 core/shader/recompiler/CacheKey.hpp
PR 7642 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 7684 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 7942 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 8004 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 8077 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 9356 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 9387 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 9508 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 9748 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 9790 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 9889 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 9897 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
PR 10193 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp
PR 10348 core/libs/prx/libSceAgcDriver/tests/ShaderMemory.cpp
core/shader/recompiler/CacheKey.hpp

@github-actions github-actions Bot added shader core/shader agc libSceAgc* labels Oct 24, 2026
@adriadam10 adriadam10 self-assigned this Oct 24, 2026
@milescoviello

milescoviello commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor Author

A Ghost of Tsushima (PPSA02225) result, with this change and the release of unused specialized modules (#10473) together on the stack the title needs to reach its opening. Same seed pipeline cache, 20 GB cap, Linux, RTX 4070 Ti. Against the same stack without the two changes, the title was killed by the cap at 1,260 s instead of 633 s. RssAnon at 4 / 6 / 8 / 10 / 12 min: 4,577 / 5,533 / 5,833 / 6,266 / 6,745 MB against 4,892 / 6,152 / 6,990 / 7,763 / 8,095 MB. The two are measured together, so this doesn't split the saving between them. NVIDIA's own shader cache was warmer for the second run, which helps its progress, not its memory.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor Author

A caveat on the Ghost of Tsushima comparison above, from a third run. This one had both changes, plus a third that is inert on a fresh cache version, at a 19 GB cap instead of 20 GB. It was killed by the cap at 913 s. RssAnon at 4 / 6 / 8 / 10 / 12 min: 4,260 / 4,916 / 6,123 / 7,537 / 7,528 MB, against 4,577 / 5,533 / 5,833 / 6,266 / 6,745 MB in the earlier run with the changes and 4,892 / 6,152 / 6,990 / 7,763 / 8,095 MB without them.

So the run-to-run spread in this title's opening is about as large as the per-minute difference I reported, and those numbers shouldn't be read as the saving. The run lengths point the same way: 633 s without the changes, 1,260 s and 913 s with them, the last at the lower cap. The count of interned modules held only by the module caches (323 to 345 MiB at 10 to 12 min) is a direct count, not a comparison.

AI-assisted: yes (Claude Code)

@adriadam10
adriadam10 merged commit 8a85a5c into boykopovar:main Oct 24, 2026
11 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked that the key is never decoded (only compared), that every other SpirvTarget field is appended as before, that extension lengths enter the digest so moved bytes differ, and that verifyTargetFeatureKey fails on main (key grows with extension count) and passes with the change; merged.

@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 exact head d7d9747e7d9aae3375846c52f4814c3b80d2cb39.

The cache key now replaces the variable-length capability/extension payload with two fixed 64-bit digest words while including list counts, capability values, extension lengths, and extension bytes. Other target fields retain their existing key representation. The test checks storage-independent equality, changed extension bytes, byte movement between names, added capabilities, and bounded key size for 40 extensions.

Local current-main merge-tree is clean; conventions and diff-check pass. Hosted eligibility, intake, labels, report, and conventions pass; hosted build/product jobs are skipped. The author reports focused Vulkan/validation-layer and Windows VM runs; I did not reproduce GPU/title measurements locally. No blocking findings on this head.

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

Labels

agc libSceAgc* shader core/shader

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants