Repository navigation
Hot Path Vulkan Shader Caching
Reviewed: November 1, 2026 · Source: main
b7140848. Release availability: Exact-source SPIR-V #70, family history/prewarm #143/#144 and driver pipeline persistence #147 are included in v0.8.136-0-g458730bf5373 (September 30, 2026). The #335/#336 scheduling refinements are reviewed-main only.
Lifecycle: Performance — Implemented · Type: Cache State: Present in reviewed main; benefit depends on the cache layer, workload and cache condition.
“Shader cache” covers different objects. A cached recipe is not executable code, SPIR-V is not a VkShaderModule, and a module is not a complete graphics pipeline.
| Layer | Retains | Work still required / limits |
|---|---|---|
| Exact-source SPIR-V, #70 | Compiled stage bytes keyed by exact generated source, stage, generator ABI, target and compiler policy | Source generation, validation/reflection, module creation and possibly pipeline construction remain. Invalid/missing records compile normally. |
| Learned fallback history, #143 / #144 | Recipes for previously useful fallback families | Recipes must be decoded, admitted and turned into live stages/bindings/pipelines. Bounded to 1,024 records / 8 MiB; at most 32 launch candidates and a prewarm inflight ceiling of four. |
| Vulkan driver pipeline data, #147 | Device-compatible VkPipelineCache bytes |
Does not guarantee every pipeline hits or avoid every driver construction cost. Restore is capped at 64 MiB and checks vendor, device and pipeline-cache UUID. |
OpenGL program-binary caching is a separate backend mechanism. Deleting one Vulkan file does not reset the other two layers or an ambient driver cache. Compare cold/warm runs using explicit identities for every layer.
The current binding, stage-module caches, pipeline LRU and retained hybrid results are process-owned reuse layers. An already-live module or pipeline can bypass the persistent store entirely. Zero persistent lookups in a warm process do not prove that persistence failed.
flowchart TD
A[Stage requested] --> B{Process module hit?}
B -->|Yes| H[Reuse live module]
B -->|No| C[Generate exact GLSL]
C --> D{Eligible valid SPIR-V artifact?}
D -->|Yes| E[Validate and create runtime module]
D -->|No| F[Compile and validate; retain eligible artifact]
E -->|Construction rejected| F
E --> H
F --> H
H --> I[Complete pipeline lookup or construction]
J[Compatible driver cache loaded at init] --> I
I --> K[Draw]
L[Family recipes loaded at launch] --> M[Bounded async stage and fallback-pipeline preparation]
M --> I
The normal source/compiler route remains required for new, rejected, corrupt, incompatible, disabled or unavailable artifacts. Cache reuse must preserve guest shader semantics and effective host target; it is an optional optimization, not a correctness dependency.
#228 retains learned families and asynchronously prepares missing vertex, optional geometry and fallback-fragment stages. Missing prewarm artifacts are no longer simply skipped. #335 waits for pending pipeline completions rather than polling them. #336 restricts speculative admission to history loaded at launch; new families are saved for future launches rather than triggering optional live builds after already-served specialized draws. Actual demand and Always behavior retain separate routes. See Learned Fallback Readiness.
Cache shaders is enabled by default in config_spec.yml. It is the current Boolean UI control, not the proposed Off / Process only / Persistent exact SPIR-V selector. The typed policy foundation #257 does not by itself deliver all proposed cache modes.
Vulkan initialization latches persistent-session eligibility. A later disable can suppress future optional lookup/publication; re-enabling after an ineligible startup may need Vulkan recreation or a full restart to initialize storage. Do not equate requested, effective and loaded cache state. Hybrid mode is separately process-startup latched, with Prewarm the fresh default.
Persistent files are loaded at controlled initialization boundaries, not read from disk for each draw. Writeback must quiesce producers before serialization. Driver cache save runs in normal GUI pre-shutdown writeback after joining the pipeline worker, and retains finalization support for backend switching. Malformed, incompatible or driver-rejected pipeline data falls back to an empty cache. A cache failure must not prevent the reference compile/build route.
#68 diagnostic: 141 stage-module misses included 121 first-seen source identities and 20 different-key/same-source repeats. Aggregate glslang work was 463.419 ms, including 68.200 ms on those repeats. These are attributed compiler costs on that diagnostic head, not an FPS prediction.
#70 qualification, September: 1,589 persisted artifacts were served across warm retail cells; a warm XISO recorded 71 hits and zero misses. Incremental results improved some tails against previous main but retained a separate cumulative Morrowind p99 gap. These historical observations do not establish a universal current-head gain.
#147 exact candidate a6a1b9d677, September 19: one Windows RTX 3070 Ti Laptop PGR2 pair restored the same frozen SPIR-V/family history and differed in driver-cache presence. Both completed 12 worker pipelines and 12 later demand hits:
| Role | Restored driver bytes | Worker pipeline total / max | Startup-through-input p95 / p99 |
|---|---|---|---|
| Restored | 16,611,034 | 4.740 / 0.674 ms | 33.407 / 35.479 ms |
| Absent | 0 | 44.941 / 5.796 ms | 33.374 / 40.232 ms |
The restored role ran first, so later ambient driver warming favored the absent-cache control. This pair demonstrates lower pipeline-worker construction time, not a balanced game-FPS result. Separate normal-GUI-exit smoke proved save/restore of 5,332,329 identical compatible bytes across two launches. A full candidate Vulkan XISO correctness/validation run passed, but lacked a matched parent timing control and scheduled no cold-history prewarm jobs; its suite duration is not a #147 speedup. See #147 for exact executable, release and retained evidence access limits.
The later #335 texture-tail tradeoff and #336 unresolved seeded-history black/stopped-flip result remain in Hybrid Specialization. Cache presence or a successful later replay does not erase a failed observation.
- Key the exact source, stage, generator ABI, compiler policy and target; validate record structure, checksum and bounds before use.
- Validate module/reflection construction after a disk hit; rejection must return to normal compilation.
- Preserve generation/ticket ownership, worker shutdown order and renderer-thread publication.
- Record source/executable, GPU/driver, cache input/output hashes, hybrid mode and run order. Separate compiler, module, pipeline-worker and game measurements.
- Keep per-test timings, correctness, controls and adverse results. A hit count or aggregate suite time cannot establish a game speedup.
| File | Role |
|---|---|
vk/shaders.c |
Exact source, module caches, SPIR-V lookup/fallback and module adoption |
vk/spirv-prewarm.c |
Persistent SPIR-V parsing, validation, bounded retention and publication |
vk/hybrid-family-history.c / hybrid-family-history.h
|
Bounded family recipes and loaded-history eligibility |
vk/hybrid-prewarm.c |
Launch/service budgets and family preparation |
vk/draw.c |
Pipeline LRU, driver cache restore/save and worker adoption |
vk/pipeline-cache-data.c |
Driver header/device/UUID validation |
vk/renderer.c |
Init, pre-save/pre-shutdown and producer quiescence |
See Vulkan Renderer, Hybrid Ubershader and #70 historical record.
DSP tooling guide and navigation updated November 2, 2026 for experimental PR #384, source 8f51d237. Capture/replay usage and limits.
The earlier wiki-wide review was published November 1, 2026. Emulator source: b7140848. Reviewed wiki content: 1d2b671. Current status · Release availability · Publication process.
- Home
- Current status
- Stable versus main
- Implemented mechanisms
- Controls and defaults
- Measured results and limits
- Complete change register
- System
- CPU and vCPU
- Memory and DMA
- Graphics / NV2A
- APU and audio
- Timing and timers
- Platform and I/O
- Hardware observations
- Fidelity boundaries
- Methodology
- PGR2 routes
- Debugging lag / hot paths
- Tools and commands
- DSP capture, replay and fuzzing
- HLE readiness and public XISO proof
- Concurrent DSP shadow and OpenAL proof
- DSP HLE operation inventory
- DSP HLE fix examples and testing
- Development
- Upstream shortlist
- Wiki maintenance
- Research / retired work
- Optimization catalog
- Hot-path shortcuts
- Researched experiments
- Unproven proposal directory
- PR lessons
- September26 snapshot
Repository · PRs · Issues