vk: cache sampler_for's samplers until a sampler registration changes #901

Merged
MMajor87 merged 1 commit from sampler-cache into main 2026-11-09 08:47:09 +00:00
MMajor87 commented 2026-11-09 00:43:47 +00:00 (Migrated from github.com)

What

sampler_for (vk_draw.cpp) runs for every texture slot of every descriptor build. Each call took reg_mu in sampler_of, copied the sampler registration, hashed it word by word and looked the hash up in a thread map: ~48,000 times a frame at ~3,000 draws.

It now keeps a thread table indexed by [compare][id] (ids are 12 bits), stamped with a new sampler registration generation (vk_bank.cpp). register_sampler_copy bumps that generation only when the registration's contents change, so rewrites of the same sampler don't empty the cache. The generation is read before the lookup, so a registration that lands during a miss makes the next call miss again. Samplers are never destroyed (as the existing per-thread map already assumes), so a cached VkSampler stays valid.

RX_VK_SAMPLER_CACHE=0 turns it off. 24 lines in two files; no shader stamp change (neither file is translator input).

Tested

  • Builds on current main (b234b43) with the release builder's llvm-mingw toolchain (nx2/build.py --standalone, RX_VK_ONLY=1).
  • Played on an RTX 4080 16 GB, i9-14900KF, 32 GB, Windows 11, on a v2.0.5 build with PR #761, the write-back limit from the #384 comment and an experimental stage texture reuse. Busy outdoor spot, ~3,155 draws: the changes together took the frame from 55.5 fps to 59-60 (the 60 cap), replay 15.2 -> 13.8 ms, the RX_VK_PROF_FINE "textures" section 1.76 -> 1.17 ms a frame. No visual issues, no device errors, an area load recovered to 60 quickly.
  • Not measured on its own: the sampler cache and the texture reuse were in the same run. It does the same work as before on a miss, so its effect should be strictly a saving.

Context and the full profile: #384.

🤖 Generated with Claude Code

## What `sampler_for` (vk_draw.cpp) runs for every texture slot of every descriptor build. Each call took `reg_mu` in `sampler_of`, copied the sampler registration, hashed it word by word and looked the hash up in a thread map: ~48,000 times a frame at ~3,000 draws. It now keeps a thread table indexed by `[compare][id]` (ids are 12 bits), stamped with a new sampler registration generation (`vk_bank.cpp`). `register_sampler_copy` bumps that generation only when the registration's contents change, so rewrites of the same sampler don't empty the cache. The generation is read before the lookup, so a registration that lands during a miss makes the next call miss again. Samplers are never destroyed (as the existing per-thread map already assumes), so a cached `VkSampler` stays valid. `RX_VK_SAMPLER_CACHE=0` turns it off. 24 lines in two files; no shader stamp change (neither file is translator input). ## Tested - Builds on current `main` (`b234b43`) with the release builder's llvm-mingw toolchain (`nx2/build.py --standalone`, `RX_VK_ONLY=1`). - Played on an RTX 4080 16 GB, i9-14900KF, 32 GB, Windows 11, on a v2.0.5 build with PR #761, the write-back limit from the #384 comment and an experimental stage texture reuse. Busy outdoor spot, ~3,155 draws: the changes together took the frame from 55.5 fps to 59-60 (the 60 cap), replay 15.2 -> 13.8 ms, the `RX_VK_PROF_FINE` "textures" section 1.76 -> 1.17 ms a frame. No visual issues, no device errors, an area load recovered to 60 quickly. - Not measured on its own: the sampler cache and the texture reuse were in the same run. It does the same work as before on a miss, so its effect should be strictly a saving. Context and the full profile: #384. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Commenting is not possible because the repository is archived.
No description provided.