Repository navigation
M4.07
Pre-release[M4.07] — 2026-10-21
The first M4.xx iteration after the M4.06 pre-release: the two Low findings
that the game hosts feel most directly — the per-frame allocation churn in
the render path and the C API's null-handle contract — plus the SPIR-V cache
enabler, which lets a host's own compile cache be correct by construction.
Added
-
The SPIR-V cache enabler (
PresetLoadOptions::spirvCache) — the
library keeps no disk cache (that is the host's business, and the
reference host already has one), but it hands the host a correct key
so the host's own cache cannot serve a stale shader:- the host is asked for a pass's compiled SPIR-V before the library
invokes glslang, and is handed the result afterwards; a hit skips the
compile; - the key is a SHA-256 over the exact GLSL handed to glslang plus the
compiler's version and target environment. Hashing the compiler's
input makes the key correct by construction — it changes exactly when
the compiled output would, so a host caching by it can never serve a
stale shader, not even when the preset includes other files (which a
host-side hash of the.slangpalone would miss); - the compile environment moved into constants shared by the compile and
the key, so the two cannot drift; - the C surface mirrors it (
slangvk_spirv_cache, load/store function
pointers); src/core/sha256.{hpp,cpp}— a self-contained SHA-256, so the library
gains no dependency for a cache key.
test_runner_cachepins the contract: the host is asked before the
compile, a hit skips it, the key is stable across loads, and the key
changes when the shader source changes. - the host is asked for a pass's compiled SPIR-V before the library
Fixed
-
PERF-09 — per-frame allocations in the render path. The render path no
longer allocates per frame:- the command buffer belongs to the frame slot — allocated once and reset
per frame, instead of avkAllocateCommandBuffers+
vkFreeCommandBuffersround-trip per frame; - the uniform block fill writes straight into the mapped UBO (no
temporary vector, no copy); - the pass sizes, alias sizes, descriptor write arrays and the pipeline
array are chain scratch: cleared and refilled, never reallocated; - the LUT sizes and the merged parameter overrides are cached and only
rebuilt when the chain is rebuilt or a parameter is overridden.
Measured with a malloc counter over the bundled fixtures (184 rendered
frames): 130,806 → 129,177 allocations, i.e. ~8.9 fewer heap
allocations per frame in the library's own code. - the command buffer belongs to the frame slot — allocated once and reset
-
SEC-07 — C API null-handle validation. The C API checks the required
Vulkan handles itself and names the offending one ("input->view is
VK_NULL_HANDLE") rather than letting the C++ layer report a generic
message. The optional handles (input->image,target->image) stay
optional. The test now pins the contract for every entry point: a NULL
pointer or a NULL required view isSLANGVK_ERR_INVALID_ARGUMENTwith a
message.
Validation
- Downstream host — the M4.07 build was smoke-tested on the
DevilutionX-libslang-vk fork: presets load, the shaders work, and the
run holds 140+ FPS with FXAA.slangp. This is the first frame-rate
figure from real hardware rather than the software rasterizer, so the
allocation work above is confirmed on a real GPU rather than only counted.
(The other reference implementation, Chocolate-Doom-VK, is engine-locked
to 35 FPS, so it exercises the shader path but its frame rate says nothing
about the shader cost.)
Changed
- The README is now a landing page (677 → 88 lines). The prose moved to
docs/STATUS.md, the API examples to
docs/EXAMPLES.md, and the usage to USAGE.md.
The README now names the two reference implementations:
DevilutionX-libslang-vk (the fork branch) and
Chocolate-Doom-VK (VTSTech/chocolate-doom-vk).
Audited
- SEC-07 and PERF-09 are removed from audit.md and recorded in
deltas.md. 8 findings remain, all Low severity.
Full Changelog: M4.06...M4.07