Skip to content

M4.07

Pre-release
Pre-release

Choose a tag to compare

@VTSTech VTSTech released this 23 Oct 19:49

[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 .slangp alone 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_cache pins 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
    .

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 a vkAllocateCommandBuffers +
      vkFreeCommandBuffers round-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.

  • 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 is SLANGVK_ERR_INVALID_ARGUMENT with 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