Skip to content

Releases

1.6.0-dev-fd578d1

Choose a tag to compare

@VTSTech VTSTech released this 22 Oct 01:27

1.6.0-dev-fd578d1 (2026-10-21 09:03:35 PM)

Integration-track work since the last release snapshot below. The
upstream-facing payload of this work is split one topical PR per change
(docs/merge-plan-r4.md): diasurgical#8750 (pr/1, SDL3 dependency
builds), diasurgical#8753 (pr/4, test missing-asset guards), diasurgical#8754 (pr/5, GPU scaler,
stacked on pr/1), diasurgical#8755 (pr/6, SDL3 main glue) — all open. The resolution/DPI
fix (diasurgical#8746: SDL_GetWindowDisplayScale() handling, above-native resolution
selection, OS-UI-scale exclusion for physical-pixel modes) intentionally
rides as a separate lightweight PR outside the r4 plan.

The 2026-10-21 wave moves onto upstream libslang-vk M4.07 final: the
dependency pin leaves the pre-release for d176d1b, the scaler gains a
SPIR-V disk cache keyed by the library's pass key, and it learns to recover
from a lost Vulkan device — plus the deep-preset browser scan fix that had
been hiding nested stock presets.

Added

GPU scaler integration

  • Shader base resolution: a new Graphics.shaderBaseResolution option plus a
    cycle entry inside the shader preset browser — the browser shows the active
    base resolution and activating the entry cycles to the next value without
    leaving the browser.
  • tools/build-local-win11.ps1: local Windows 11 build script mirroring the
    CI gate — static and nonstatic (DLL) variants, pinned vcpkg
    (.vcpkg-local, 40f3c709db), FetchContent SDL 3.5.0 with vcpkg's shadowing
    SDL3 payload removed, and an explicitly selected MSVC x64 environment.
  • build_r4_branches.py: branch automation for the merge track — cuts one
    branch per payload change from upstream/master with EOL normalization
    against upstream and attribution stamps; --recut / --push (lease) /
    --prune / --verify-only, and --check-prs for live upstream PR state
    (flags closed/merged plan PRs as retire/prune candidates instead of leaving
    the next one to be noticed by hand).

libslang-vk M4.07 — SPIR-V disk cache and device-lost recovery

  • SPIR-V disk cache: the scaler wires up PresetLoadOptions::spirvCache
    (the M4.07 cache enabler) — one file per pass under
    shaders/cache/spv/<key>.bin, the layout the Packaging
    clear_shader_cache scripts already wipe. The key is the library's (a
    SHA-256 over the exact GLSL handed to glslang plus the compiler version
    and target environment), so an entry can never serve a stale binary the
    way the fork's old in-tree GLSL-only hash would have across a glslang
    upgrade. Reads are validated (container magic and version, framing,
    SPIR-V header, a 64 MB per-stage sanity cap, path-traversal rejection),
    so a torn or hand-edited file degrades to a recompile instead of a broken
    preset; stores go through a temp file + rename, so a crash mid-store
    cannot leave a torn entry. First field run: a 20-pass and a 2-pass preset
    each compiled once, then 20/20 and 2/2 passes served from the cache on
    every later load.
  • Device-lost recovery, host side of the M4.06 contract: a
    VK_ERROR_DEVICE_LOST on any of the three surfaces the host touches
    (vkAcquireNextImageKHR, Chain::render, vkQueuePresentKHR) recovers
    in place instead of ending the shader path. The render case is the
    library-driven one — the library has already replaced the device and
    rebuilt the chain, and reports Errc::vk_device_lost so the host
    recreates its own device-side resources; acquire and present are
    host-driven, calling Device::recover() directly. Either way the host
    forgets its stale objects (game image, swapchain, acquire semaphore,
    staging buffer), frees the staging MappedBuffer through the old
    allocator (it is not in the device's release registry), re-binds the
    exe's own volk device table (GPU_SCALER_SHARED builds carry a separate
    copy), and lets the chain rebuild itself on the next render through the
    generation check. Three recoveries in a row without a completed frame
    give up and fall back to the stock renderer.

Fixed

Audio

  • Source/engine/fbbsanitizer.cpp: the ShootFireballBow sound effect's WAV
    data in hellfire.mpq is invalid (missing pad byte after the data chunk; the
    smpl chunk breaks SDL3 playback) — sanitize it at load time by truncating
    after the data chunk and adjusting the RIFF chunk length.

SDL3 display / input

  • Scaler mouse-coordinate mapping: when the scaler owns the window there is
    no SDL renderer for SDL to convert events with, so
    gpu_scaler::MapWindowToGame() maps window and game space through the
    scaler's last present rect (display.h / sdl_compat.h hooks). The two
    hook call sites are qualified (devilution::gpu_scaler::...) so
    translation units that include sdl_compat.h without display.h still
    compile — the Linux CI failure mode cannot recur on the PR branches.

Windows build

  • MSVC nonstatic (DLL) build: the shared slangvk target's import library
    moved to slangvk-shared-implib/, removing the duplicate slangvk.lib
    rule that broke Link nonstatic.
  • build-local-win11.ps1: -DCMAKE_SUPPRESS_REGENERATION=ON added to both
    variant flag sets — Ninja's RERUN_CMAKE auto-regeneration fired endlessly
    inside the build step on some Windows filesystems (each cycle a full cached
    re-configure, no compile edge ever ran). The script always configures
    explicitly right before building, so self-regeneration is redundant.
  • Dead patch.exe PATH block removed from the build script (no patch
    application remains in the tree since the WAV layer drop).

GPU scaler / libslang-vk

  • Deep-preset browser scan: ScanPresets() scanned three levels deep while
    the stock shader corpus nests up to seven (API.md §4.2), so deeper
    presets never appeared in the browser — and the stored-preset self-heal
    then wiped such a selection at startup as missing. The scan now runs at
    depth 8.
  • First-acquire semaphore: the acquire path could reach its first
    vkAcquireNextImageKHR with a VK_NULL_HANDLE semaphore and a null
    fence — the semaphore used to be created only after a failed render, and
    an acquire needs one of the two. The semaphore is now created before the
    first acquire and rebuilt after a failed render leaves it signaled
    without a wait, so every acquire is well-formed.

Changed

CI (fork-only gate)

  • gpu-scaler-build.yml: Windows MSVC x64 (vcpkg manifest + preset with an
    explicit MSVC dev environment, sodium vendored static) and Linux x64 (ctest
    as the regression signal) jobs, --version binary smoke tests on both,
    ccache, path-keyed build-tree caching with a workspace-path backstop, and
    if: always() artifact uploads. The retired wav-mixer-fix branch is
    removed from the push triggers.

Docs

  • README.md: branch-aware phrasing for the master references and the branch
    table; the deleted wav-mixer-fix branch row dropped.

libslang-vk

  • Dependency pin: the CMake FetchContent tag moved from 5b72331
    ("M4.07 Pre-Release") to d176d1b (M4.07 final) — the pre-release
    lacked the SPIR-V cache enabler the disk cache above is built on. The
    stale M4.05 comment above the pin went with it.
  • README.md: the shader-cache section now describes the shaders/cache/spv/
    disk cache and drops the stale references to the removed in-tree cache
    scripts; the Vulkan render-path section documents the in-place
    device-lost recovery.

Removed

WAV fallback / robustness layer

  • The generic WAV fallback/decoder-robustness layer is dropped from the tree
    (SDL3_mixer zero-length-chunk patch, CMake flags, SoundSample fallback
    logic — 9 files, 228 lines removed): upstream sanitizes the broken audio
    data itself now, so the layer is not wanted upstream (PR diasurgical#8751 closed) and
    the same layer left the tip. pr/2-wav-audio-robustness is retired and
    pruned from the plan.
  • pr/3-robustness-guards (diasurgical#8752) retired as well: review showed the
    menu-time item-cursor crash was fork-side — the scaler's
    renderer-recreation path called InitVirtualGamepadGFX() outside a game
    session; the tip gates that path on gbRunGame, and the remaining
    capture.cpp LogError one-liner is left for upstream.

Full Changelog: libslang-vk-v4...libslang-vk-v9

1.6.0-dev-638b973

Choose a tag to compare

@VTSTech VTSTech released this 20 Oct 21:31

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog
and this project adheres to Semantic Versioning.

Fork releases are numbered 1.6.0-dev-<commit>, where <commit> is the
short hash of the commit a build or overlay was produced from, and are
dated with an America/Toronto timestamp. Upstream (diasurgical) release
history lives in docs/CHANGELOG_UPSTREAM.md
and is not modified.

The libslang-vk integration branch does not cut numbered releases; its
integration milestones are recorded under Unreleased below, dated by their
commit window.

[1.6.0-dev-638b973] 2026-10-20 5:30:09 PM

Integration-track work since the last release snapshot below. The
upstream-facing payload of this work is split one topical PR per change
(docs/merge-plan-r4.md): diasurgical#8750 (pr/1, SDL3 dependency
builds), diasurgical#8753 (pr/4, test missing-asset guards), diasurgical#8754 (pr/5, GPU scaler,
stacked on pr/1), diasurgical#8755 (pr/6, SDL3 main glue) — all open. The resolution/DPI
fix (diasurgical#8746: SDL_GetWindowDisplayScale() handling, above-native resolution
selection, OS-UI-scale exclusion for physical-pixel modes) intentionally
rides as a separate lightweight PR outside the r4 plan.

Added

GPU scaler integration

  • Shader base resolution: a new Graphics.shaderBaseResolution option plus a
    cycle entry inside the shader preset browser — the browser shows the active
    base resolution and activating the entry cycles to the next value without
    leaving the browser.
  • tools/build-local-win11.ps1: local Windows 11 build script mirroring the
    CI gate — static and nonstatic (DLL) variants, pinned vcpkg
    (.vcpkg-local, 40f3c709db), FetchContent SDL 3.5.0 with vcpkg's shadowing
    SDL3 payload removed, and an explicitly selected MSVC x64 environment.
  • build_r4_branches.py: branch automation for the merge track — cuts one
    branch per payload change from upstream/master with EOL normalization
    against upstream and attribution stamps; --recut / --push (lease) /
    --prune / --verify-only, and --check-prs for live upstream PR state
    (flags closed/merged plan PRs as retire/prune candidates instead of leaving
    the next one to be noticed by hand).
  • libslang-vk M4.05 single-submit frame path: the scaler's per-frame
    upload no longer pays the standalone Image::update round-trip (its own
    staging alloc + command buffer + submit + fence drain, on top of the
    render submit). A persistent slv::Device::MappedBuffer — created once
    per game-frame size and released/recreated on resolution changes — now
    holds the tightly packed copy of the SDL_Surface frame (the pitch is not
    promised to equal width * 4, so the packing copy stays); every present
    memcpys into the mapped memory and hands the buffer to the chain via
    InputFrame::pixelBuffer, and the runner records the buffer→image copy
    at the top of its own frame submit. Per frame: one command buffer, one
    submit, one fence wait, zero staging churn. The vendored libslang-vk
    GIT_TAG rides the tagged M4.05 release (c3567b03 → fa65b6d5):
    Device::createMappedBuffer / InputFrame::pixelBuffer (1a9911b), the
    public-header fix that keeps slangvk/runner.hpp off the VMA include
    path (540c9d6), and the M4.05 docs (fa65b6d5).

Fixed

Audio

  • Source/engine/fbbsanitizer.cpp: the ShootFireballBow sound effect's WAV
    data in hellfire.mpq is invalid (missing pad byte after the data chunk; the
    smpl chunk breaks SDL3 playback) — sanitize it at load time by truncating
    after the data chunk and adjusting the RIFF chunk length.

SDL3 display / input

  • Scaler mouse-coordinate mapping: when the scaler owns the window there is
    no SDL renderer for SDL to convert events with, so
    gpu_scaler::MapWindowToGame() maps window and game space through the
    scaler's last present rect (display.h / sdl_compat.h hooks). The two
    hook call sites are qualified (devilution::gpu_scaler::...) so
    translation units that include sdl_compat.h without display.h still
    compile — the Linux CI failure mode cannot recur on the PR branches.

Windows build

  • MSVC nonstatic (DLL) build: the shared slangvk target's import library
    moved to slangvk-shared-implib/, removing the duplicate slangvk.lib
    rule that broke Link nonstatic.
  • build-local-win11.ps1: -DCMAKE_SUPPRESS_REGENERATION=ON added to both
    variant flag sets — Ninja's RERUN_CMAKE auto-regeneration fired endlessly
    inside the build step on some Windows filesystems (each cycle a full cached
    re-configure, no compile edge ever ran). The script always configures
    explicitly right before building, so self-regeneration is redundant.
  • Dead patch.exe PATH block removed from the build script (no patch
    application remains in the tree since the WAV layer drop).

Changed

GPU scaler

  • Heartbeat diagnostics: the 5-second gpu-scaler.log heartbeat line now
    carries EMA-smoothed per-phase timings (upload / render / present, ms;
    α = 1/32, measured with SDL_GetPerformanceCounter since the phases are
    sub-millisecond), so a field log separates CPU upload cost from chain GPU
    cost from acquire/present cost — the data that identified the old
    two-submit frame path as sync-bound. The loaded preset's re-stat (the
    hot-reload check) is throttled to at most every 500 ms — it is a
    filesystem call, measurable at uncapped frame rates.

CI (fork-only gate)

  • gpu-scaler-build.yml: Windows MSVC x64 (vcpkg manifest + preset with an
    explicit MSVC dev environment, sodium vendored static) and Linux x64 (ctest
    as the regression signal) jobs, --version binary smoke tests on both,
    ccache, path-keyed build-tree caching with a workspace-path backstop, and
    if: always() artifact uploads. The retired wav-mixer-fix branch is
    removed from the push triggers.

Docs

  • README.md: branch-aware phrasing for the master references and the branch
    table; the deleted wav-mixer-fix branch row dropped.

Removed

WAV fallback / robustness layer

  • The generic WAV fallback/decoder-robustness layer is dropped from the tree
    (SDL3_mixer zero-length-chunk patch, CMake flags, SoundSample fallback
    logic — 9 files, 228 lines removed): upstream sanitizes the broken audio
    data itself now, so the layer is not wanted upstream (PR diasurgical#8751 closed) and
    the same layer left the tip. pr/2-wav-audio-robustness is retired and
    pruned from the plan.
  • pr/3-robustness-guards (diasurgical#8752) retired as well: review showed the
    menu-time item-cursor crash was fork-side — the scaler's
    renderer-recreation path called InitVirtualGamepadGFX() outside a game
    session; the tip gates that path on gbRunGame, and the remaining
    capture.cpp LogError one-liner is left for upstream.

Full Changelog: libslang-vk-v4...libslang-vk-v8

1.6.0-dev-ba8691f

Choose a tag to compare

@VTSTech VTSTech released this 20 Oct 14:09

Changelog

[1.6.0-dev-ba8691f]

Shader Base Resolution & console packaging (dea220a...ba8691f)

Added

  • Shader Base Resolution — new setting controlling the canvas size handed to the
    slang shader chain while a filter is active. The game renders into the configured
    base, the window and swapchain keep the selected Resolution, and the chain maps
    mouse coordinates through the present rect. A base smaller than the window gives
    upscaler presets (ScaleFX, HQx) the input < output headroom they are designed for;
    CRT-style overlays (scanlines, masks, grids) keep working at any input size.
    Values: Auto (window size), 640x360, 960x540 (default), 1280x720, 1600x900,
    1920x1080. Non-16:9 windows letterbox.
  • In-browser base resolution picker — the Shader Filter browser shows a persistent
    "Shader Base Resolution: " entry below "Off" in every browsed folder.
    Activating it opens a nested value sub-list (same UI as a normal list option);
    leaving it resumes the parent browser in place with focus intact. No auto-cycling,
    and the standalone Graphics-menu row is hidden to avoid showing the setting twice.
  • Nested list browsing infrastructure in the settings menu (GetNavigationSubList(),
    listOptionStack): any list option can now drill into a sub-list and return to the
    parent view without closing or flickering the menu.
  • Hellfire on 3DS / Switch — hf.mpq is now built and deployed to romfs on both
    consoles; MPQ search path adds romfs:/, with assets and mods laid out under
    romfs:/assets and romfs:/mods.
  • BUILD_MOD_MPQS CMake option plus DEVILUTIONX_MODS_MPQ_DIRECTORY to build mod
    MPQs independently of BUILD_ASSETS_MPQ.
  • build_r4_branches.py --recut [--push|--prune]: rebuilds all pr/* branches from the
    current libslang-vk tip, keeps unchanged branch tips stable, and sanitizes
    sdl_compat.h on the way out so the PR branches stay CI-green.

Changed

  • README rewritten: Project Status — October 2026, What this mod adds, Requirements,
    Setting Up Shaders, Using Shaders, Contributing.
  • Merged upstream diasurgical:master into libslang-vk.

Fixed

  • Mod manifests (manifest.ini) for loose (unpacked) mods are now searched under the
    same paths LoadModArchives() registers as OverridePaths (PrefPath/BasePath), so
    loose mod requirements resolve consistently with packed archives.

Full Changelog: libslang-vk-v4...libslang-vk-v7

1.6.0-dev-3b94a42

Choose a tag to compare

@VTSTech VTSTech released this 23 Oct 20:30

Now linked against libslang-vk M4.08

[M4.08] — 2026-10-24

The first iteration measured by its own benchmark suite: this release
ships a real benchmarking framework (google/benchmark, six executables,
built in-tree behind one flag), and the framework immediately paid for
itself — its first real-GPU run surfaced a double file-read in
TranslateSlang, fixed here and measured at −18% per call on
Windows
. Two more audit findings close on the cheap: the preset
parser's edge-case contract is now pinned by tests, and the
thread-safety guarantees are stated in the public headers.

Added

  • The benchmark framework (closes the framework half of TEST-12):
    six google/benchmark v1.9.1 executables built with the library behind
    -DSLANGVK_BUILD_BENCHMARKS=ON — preset parse, slang translate, slang
    compile, chain create+destroy, blit render, FXAA render. The original
    suite (M0) had machine-specific build wiring and never produced a
    valid measurement outside its author's workstation; the rework links
    the in-tree slangvk::slangvk target (transitive glslang), fetches
    google/benchmark pinned via FetchContent, uses repo-relative data
    roots, wires in the orphaned bench_vk_render_fxaa.cpp, and makes
    every bench count its failures and print first-failure diagnostics
    instead of silently timing error paths. Runner scripts for Windows
    (VS2022/MSVC) and Linux ship in benchmarks/scripts/.
    benchmarks/README.md documents the
    measurement contract and carries the first numbers: the lavapipe
    reference (2 vCPU sandbox, GCC 14.2) and the first real-GPU run —
    RX 560 / Windows 11 / MSVC 19.44, where an FXAA frame completes
    end-to-end in 411 µs (~2,400 FPS ceiling, 13.1× the software
    rasterizer) and blit presentation in 225 µs (5.1×)
    .

  • Preset-parser edge-case tests (audit ROB-36, test half): 23 checks
    pinning the parse contract on adversarial inputs — empty files
    (rejected at top level, legal as #reference targets), lines without
    =, unknown-key tolerance, duplicate keys (last wins), CRLF inputs,
    comment forms including quoted # literals, missing #reference
    targets, self/two-file reference cycles, the 9-vs-10-file
    #reference depth boundary, and the 8 MiB size cap (ROB-20).

  • Thread-safety contract in the public headers (audit ARCH-04,
    documentation half): the full contract block at the top of
    runner.hpp and @par Thread safety notes on Device, Image and
    Preset — the library is single-threaded per Device by design;
    distinct Devices (separate Vulkan devices/queues) are independent and
    may be used concurrently; the core layer keeps no shared mutable state
    apart from the shader-root global (set it once at startup); glslang's
    process initialization is internally mutex-guarded, so concurrent
    CompileSlang calls are supported. The existing Chain and
    SetShaderRootDir notes predate this and now have company.

Fixed

  • TranslateSlang reads the shader file once per call — the first
    optimization surfaced by the benchmark suite above (the translate
    bench on Windows was paying for two file opens per call). The
    include-resolution walk now captures the raw top-level bytes it
    already read, and the source fingerprint (sourceSize/sourceHash)
    is computed from that capture — previously the file was opened a
    second time purely for the fingerprint (ReadWholeFileBytes).
    Measured: 1,364 → 1,119 µs per call on the RX 560 box (−18%),
    84.4 → 81.6 µs on the lavapipe sandbox (where a read costs ~1 µs).
    Byte-for-byte parity of all SlangTranslation fields verified across
    LF, CRLF, include-resolved and failure-path cases (the fingerprint
    remains a hash of the raw file bytes, CRLF included). The saving
    applies per translated shader — and per pass, since chain creation
    translates every pass shader.

Full Changelog: libslang-vk-v4...libslang-vk-v10

1.6.0-dev-dea220a

Choose a tag to compare

@VTSTech VTSTech released this 20 Oct 02:45

1.6.0-dev-dea220a (2026-10-19 10:13:33 PM)

Window fc9743319..dea220af4 — 64 commits, 163 files changed (+7,501 / −32,700),
2026-10-18 00:20:57 → 2026-10-19 10:13:33 PM America/Toronto.

The window that turned the fork's shader stack inside out. The in-tree slang
translator/preset runner was extracted into the standalone
libslang-vk library — first vendored,
then consumed via CMake FetchContent with the pin climbing M4 → M4.05 — leaving
gpu_scaler.cpp as a pure host adapter (window claim, frame upload,
presentation, OSD, diagnostics, session fallback). Mid-window the tree was
reset to the upstream baseline (clean tree): upstream's CI workflow set and
README were restored, the fork's audit tooling and design docs were purged,
and the changelog was consolidated back to the upstream history. On top of
that reset came a chain of SDL3 display/DPI fixes for real field crashes,
mouse-coordinate mapping for the scaler-owned presentation path, MSVC link
repairs for the static and nonstatic builds, a fork-only CI build gate, a
local Windows 11 build script, and the merge-plan-r4 individual-change PR
staging. Upstream was synced twice (diasurgical/master PRs #2 and #3),
picking up the PCX scanline padding fix. The repository is now
DevilutionX-libslang-vk.

Added

GPU scaler / libslang-vk

  • libslang-vk adoption — the slang compile/translate/preset-runner stack
    moved out of the fork and into a standalone reusable library
    (VTSTech/libslang-vk), consumed by CMake FetchContent and pinned at
    M4.05 (c3567b03) after stepping through M4, the CMake 3.22 floor, the
    push-block runner fix, and M4.04 ("2637 load, 21 fail"). 3rdParty/libslang-vk,
    3rdParty/SPIRV-Cross, 3rdParty/glslang, Source/engine/render/gpu/preset/,
    the prebuilt SPV/MSL headers and gen_spv_header.cmake are all gone;
    Vulkan translation and preset execution now live behind slv::Chain.
  • Mouse mapping for scaler presentation — devilution::gpu_scaler:: MapWindowToGame() / MapGameToWindow(): the last presented frame's output
    rect is cached at present time and invalidated with the swapchain, and the
    SDL3 OutputToLogical path routes through the mapping so the cursor stays
    truthful when the scaler owns the window (window points → swapchain pixels
    → letterboxed game rect, and back).
  • libdevilutionx_options decoupling — the resolution helpers
    (GetNativeDesktopResolution, ClampResolutionForIntegerScaling,
    IsResolutionAboveNative) moved from display.cpp into options.cpp so
    the standalone options object library links without the display translation
    unit.
  • Disabled-option UI support — OptionEntryBase::IsDisabled() virtual;
    greyed-out entries render silver-dark, ignore selection, and are skipped in
    navigation (ElementDisabled).

Build / CI / tooling

  • gpu-scaler-build.yml — fork-only build gate (upstream's workflows
    don't trigger on fork refs): Linux x64 SDL3 + Windows MSVC x64 with
    -DUSE_GPU_SCALER=ON, vendored sodium, explicit MSVC dev env, no Vulkan
    SDK needed at build time (volk loads the loader at runtime), build outputs
    always uploaded as artifacts, ctest kept as the Linux green signal.
  • Full upstream CI set restored — 25+ workflows (3ds, Android, iOS,
    macOS arm64/x86_64, PS4/PS5, Switch, Vita, Xbox nxdk/One, Windows
    MSVC/MinGW x64+x86/XP/9x, Linux x86/x86_64/aarch64/SDL1/SDL3-test,
    amiga-m68k, miyoo_mini, opendingux, retrofw, s390x big-endian QEMU,
    src_dist, translations, clang-tidy, cache-cleanup); the fork-only
    gpu-shaders.yml retired.
  • tools/build-local-win11.ps1 + .cmd — local Windows 11 build
    reproducing the CI Windows job 1:1, with -Link static (default,
    self-contained exe), -Link nonstatic (libslangvk.dll + SDL3 trio
    collected into a runnable package and smoke-tested like a user machine)
    and -Link both.
  • Packaging helpers — install_git.cmd (winget Git for Windows + LFS),
    install_shaders.cmd (clones libretro slang-shaders + git lfs pull
    into shaders/), clear_gpu-scaler.log.cmd, Linux/Windows
    clear_shader_cache scripts; .gitignore gains gpu-scaler.log.
  • BUILD_SHARED_LIBS pin — set(BUILD_SHARED_LIBS OFF) at root scope in
    Dependencies.cmake: SDL_image/SDL_mixer's CMake glue was FORCE-writing
    BUILD_SHARED_LIBS=ON into the global cache, turning libzt's
    natpmp_pic/zto_pic into DLLs and breaking the nonstatic MinGW/Linux
    links (undefined __imp_socket etc.).

Tests

  • test/options_test.cpp (+220) — covers the resolution list filtering,
    integer-scaling clamping and the new disabled-option semantics, with
    malformed preset_smoke fixtures (bad count/index/slang, empty,
    missing shader, broken shader) staged at runtime.
  • test/pcx_to_clx_test.cpp (+212) — PCX→CLX conversion regression
    tests, including scanline padding cases.
  • Missing-asset guards — DevilutionTest::MissingAssets() lets MPQ-less
    test runs skip SetUp cleanly instead of failing.

Upstream merge planning

  • docs/merge-plan-r3.md and docs/merge-plan-r4.md +
    build_r4_branches.py
    — the r4 plan implements upstream maintainers'
    "make a branch for your individual changes" directive: the builder script
    cuts one topical branch per change (pr/1-sdl3-build-fixes,
    pr/2-wav-audio-robustness, pr/3-robustness-guards,
    pr/4-test-missing-asset-guards, pr/5-gpu-scaler, pr/6-sdl3-main-glue,
    …) straight from fork payload blobs, with EOL normalization against each
    upstream file's stored convention and attribution stamps applied to the
    scaler PR's new files.

Changed

  • Clean-tree reset — fork README replaced by the upstream base, fork CI
    replaced by the upstream workflow set, and the changelog consolidated:
    docs/CHANGELOG.md now carries the upstream (diasurgical) history,
    docs/CHANGELOG_UPSTREAM.md deleted, and the fork's 1.6.0-dev narrative
    entries retired (this log resumes with the present entry).
  • Repository renamed to DevilutionX-libslang-vk — workflow URLs, plan
    docs, build script and the gszProductName branding string
    (DevilutionX-libslang-vk <version>, shown in the main-menu footer and
    Discord rich presence) all updated.
  • Audit-era content purged — docs/audit/, tools/audit/,
    docs/GPU_SHADERS.md, docs/SLANG_SPEC.md, docs/deltas.md,
    docs/brief.md, docs/diablo-handoff.md, docs/libslang-vk-plan.md and
    the merge-plan r1/r2 drafts removed with the in-tree shader stack they
    documented (−32,700 lines across the window).
  • Options plumbing — the shader-filter preset browser stores
    slv::preset::PresetEntry behind a forward declaration so options.h
    stops dragging library headers into every target; EOL normalization for
    Source/options.cpp, vcpkg.json, 3rdParty/SDL3_image/CMakeLists.txt
    and CMake/Tests.cmake (the fork had rewritten CRLF files to LF,
    inflating true diffs ~10x; re-normalized per upstream convention).
  • Upstream syncs — diasurgical/master merged twice (fork PRs #2 and
    #3), bringing upstream's PCX scanline padding fix (Gleb Mazovetskiy) and
    other upstream movement onto the branch.

Fixed

Display / DPI (SDL3)

  • SDL_GetWindowDisplayScale() misread as pixel density — Windows, Linux
    and Android SDL3 backends report display modes in physical pixels, but the
    resolution list was multiplying them by the OS UI scale: at 125% Windows
    scaling every mode became a phantom size (1920×1080 listed as 2400×1350
    "1350p"), hiding the native mode and offering above-panel resolutions that
    crash Integer Scaling. Physical-pixel backends now use a scale factor of
    1.0; the Apple point-based backends (UIKit/Cocoa) keep using the window
    display scale, as does the SDL2 renderer-output path.
  • Above-native resolution selection crash — selecting a 1920p-class entry
    on a 1080p desktop with Integer Scaling enabled floored the integer factor
    to zero and divided by zero (field CTD). Interactive selections are now
    caught by ClampResolutionForIntegerScaling() with a messagebox and a
    fallback to native; CalculatePreferredWindowSize() clamps the factor to
    at least 1 (logged) as a backstop for stale devilutionx.ini values
    carried over from other displays.
  • Integer Scaling can no longer be enabled in the crash state — the
    option greys out via OptionEntryIntegerScaling::IsDisabled() while the
    game runs above the native desktop resolution (hand-edited ini or a GPU
    driver VSR mode), until a within-native resolution is selected.
  • Resolution-DPI settings polish — the above fixes ride a settings-menu
    rework: disabled entries draw greyed-out and non-interactive, and the
    resolution list filters above-native sizes while Integer Scaling is on.

Build (Windows / MSVC)

  • LNK2019 unresolved external symbol WinMain — SDL3's SDL.h no longer
    includes SDL_main.h; Source/main.cpp now includes it so WIN32
    GUI-subsystem executables get the SDL_main/WinMain entry points.
  • "Multiple rules generate slangvk.lib" (MSVC/Ninja, nonstatic build) —
    the static slangvk target and the shared slangvk-shared variant both
    emitted slangvk.lib on DLL platforms; from the consumer side the shared
    variant is renamed to the documented libslangvk artifact, its import
    library moves to its own folder, and distinct PDB names stop the
    static/D link-PDB race. Linux/macOS untouched (libslangvk.so).
  • libzt/MinGW nonstatic link failures — fixed by the root-scope
    BUILD_SHARED_LIBS pin above.

PCX (upstream)

  • PCX scanline padding handling — fixed upstream-style in
    load_pcx.cpp / pcx_to_clx.cpp / surface_to_pcx.cpp (Gleb
    Mazovetskiy), with ...
Read more

1.6.0-libslang-vk-v5

Choose a tag to compare

@VTSTech VTSTech released this 19 Oct 14:11

Now using libslang-vk M4.05

[M4.05]

Added

  • shader_demo r / reload — re-reads the current preset from disk and
    rebuilds its chain: the edit-slangp → reload → see-result loop without
    restarting the demo. The fresh parse goes into a side slot and the cache
    entry swaps only after the rebuilt chain replaced the old one, so the
    cache-outlives-chain invariant holds at every step and a failed re-parse
    leaves the previous preset + chain fully intact. Runtime parameter
    overrides are cleared by a reload (the chain is rebuilt from file
    values). First entry of the M4.04-post follow-up wave.
  • Process-global glslang frontend mutex (freeze-review F-1, decision
    D-3a): docs/API.md §5.3/§6 claimed "glslang is process-globally
    guarded", but GlslangRuntime guarded lifecycle only —
    InitializeProcess() once, FinalizeProcess() at exit, no lock ever
    taken (the <mutex> include was dead weight). Two frontend sites ran
    unserialized — CompileStageToSpv's TShader::parse/link/
    GlslangToSpv and the translate-time dead-code oracle's
    TShader::preprocess — so two concurrent Preset::loads could race
    inside glslang, with nothing in CI exercising concurrency. One
    process-global std::mutex (GlslangFrontendMutex, defined in
    slang_compile.cpp, forward-declared in slang_translate.cpp per the
    EnsureGlslangRuntime pattern) now serializes both entry points;
    seconds-scale loads make contention irrelevant and the written threading
    claim is true as published. API.md §4.4/§5.3 state the contract.

Changed

  • Chain::resize drops its two dead input-size parameters
    (freeze-review F-2, decision D-1a; pre-freeze signature break):
    resize(inputW, inputH, outputW, outputH) is now
    resize(outputWidth, outputHeight). The review proved all three
    documented input-size clauses wrong — pass FBOs derive from the
    per-frame InputFrame size plus the stored target at render, and pass
    targets, the history ring and the mip copy are (re)created lazily on
    size drift; the impl only validated the output size and stored it (the
    input params were even commented out of the definition). Call sites were
    ours (test_runner_m2.cpp, shader_demo.cpp). API.md §5.4 rewritten to
    the lazy-rederive semantics; §8 gains the host duty that a swapchain
    extent change (window resize / VK_SUBOPTIMAL_KHR) must be followed by
    resize() with the new extent before the next render (F-3 — render
    rejects a drifted extent with invalid_argument).
  • docs/API.md folds the eight freeze-review findings (Task 29):
    §3 names the library's only two stderr writers as documented exceptions
    and documents SLANGVK_FILL_DEBUG (F-8, decision D-4a); §5.4 states
    setParameter is write-only by design — no getter in v1, UI-facing
    hosts track the merged view from parameterInfo() + their own calls
    (F-2's getter gap, decision D-2b); §4.2 documents ResolvePresetFilePath
    refusing out-of-root hits as the deliberate SEC-01 sandbox behavior
    (F-5); §4.3 enumerates the 14 UniformType values (F-7); §5.5 carries
    the header default of SwapchainFrame::format (F-6) and the three
    undocumented render-time validations — offscreen target needs a concrete
    ChainOptions::outputFormat, SwapchainFrame::format UNDEFINED/
    zero-texel rejection, null InputFrame::image when history/mip is
    required (F-4); §9 cross-references the stderr exceptions.

Fixed

  • shader_demo params now shows live values. It printed the preset
    default as the current value, so after set BRIGHTNESS 3.0 the display
    still read 1.250 — indistinguishable from "the set didn't take" (the
    exact confusion behind the maintainer's live-parameter field report).
    Runtime overrides are now tracked per session and reported with a
    [runtime override] tag; the lib path itself was never broken —
    verified by byte-different PNG dumps before/after set on llvmpipe.
    Help text and both CI artifact USAGE blocks document reload and the
    file-edits-need-reload rule.

Planned

  • M5 (1.0): API freeze, packaging, docs/API.md.
  • The 21 ledger-FAIL presets are upstream-broken or malformed (see M4.03) —
    no library action planned; they stay pinned as FAIL in the baseline.
    Full Changelog: gpu-shaders-v18...libslang-vk-v5

1.6.0-libslang-vk-v4

Choose a tag to compare

@VTSTech VTSTech released this 18 Oct 15:59

Now using libslang-vk M4.02

[M4.02] — 2026-10-18

Corpus rescan release: full-corpus verdict went from 826 LOAD / 1832 FAIL
(2026-10-17 baseline) to 2567 LOAD / 91 FAIL — zero regressions at the
pinned revision.

Fixed

  • #reference merge rebase stored cwd-relative paths (RebaseReferenceFilePath()
    in src/core/preset_parser.cpp): when the scan root was relative (the
    documented corpus_sweep slang-shaders invocation), rebased pass/texture
    paths were joined onto the importing preset's directory at load time,
    producing garbled paths and failing ~700 otherwise-healthy presets. Rebased
    paths are now absolutized inside the SEC-01 shader root. Regression test in
    tests/test_preset_parser.cpp (relative root + #reference chdir fixture
    asserts an absolute, existing merged path).

Added

  • corpus_sweep --only-from FILE whitelist for chunked rescans (keeps
    corpus-root semantics; enables full-corpus sweeps in sandboxed/short-lived
    environments).
  • CI: the Windows shader-demo artifact now bundles corpus_sweep.exe (Linux
    ships corpus_sweep), with an updated USAGE.txt section showing the
    absolute-root invocation.
  • .github/workflows/corpus.yml workflow_dispatch can regenerate the ledger
    without any local binary.

Changed

  • corpus/baseline-ledger.txt refreshed at the same corpus rev: 2658 presets
    → 2567 LOAD / 91 FAIL, 0 regressions, +1741 improved (bezel +1367,
    presets +160, hdr +146, crt +32, ...). Added/gone: 0/0.

[M4.01] — 2026-10-18

Fixed

  • slang: unknown texture reference 'PhosphorPassFeedback' on presets
    whose passes are named only via #pragma name (no aliasN — e.g.
    crt-yah.slangp): the translator's texture-name universe only knew LUT
    names, aliasN and User#, while the chain runtime already resolved pragma
    names, Feedback-suffix taps and <name>Size. Pass names from
    #pragma name are now collected at load time and seeded into the universe,
    so bare-name taps, previous-frame <name>Feedback taps and <name>Size
    UBO members all bind.

Added

  • Public API slv::preset::CollectSlangPragmaNames(shaderPath, out)
    (include/slangvk/core/slang_translate.hpp): soft-fail include-once scan
    with the same ResolveIncludes bucketing as TranslateSlang; scan failure
    is silent and real errors surface from per-pass translation.

Tests

  • Four feedback-tap regressions in tests/test_slang_translate.cpp: collector
    finds the pragma name; seeded universe binds PhosphorPassFeedback in set 2;
    lowercase spelling resolves; empty universe still hard-fails with the
    original diagnostic.

[M4] — 2026-10-17/18

DevilutionX presentation spike (plan §8 mode (a)) plus the shader_demo
example app and its first two real-world fix waves.

Added

  • examples/shader_demo: hybrid windowed/headless demo — GLFW backend
    probing with headless-only fallback, TUI preset browser, animated-pattern +
    image inputs, PNG frame writer, and a --headless --no-menu --frames N --out DIR sweep mode used for corpus verification (~2k lines across
    shader_demo.cpp, window_target.hpp, input_source.hpp,
    preset_browser.hpp, frame_writer.hpp).
  • Default input: bundled assets/testcard.png (480×320 pixel-art
    Goku/Mario/Luigi, generated by tools/make_testcard.py + tools/sprites/),
    with a 5-level portable asset lookup starting at the executable's directory.
  • Corpus tooling: corpus/baseline-ledger.txt (per-preset LOAD/FAIL
    baseline) + .github/workflows/corpus.yml — nightly pinned-rev sweep with a
    no-regression gate.
  • Runner presentation: SwapchainFrame with letterbox and rotation;
    push-block / size-param runner coverage (test_runner_m4.cpp,
    test_runner_pushblock.cpp, sizeparam/pushfrag golden shaders).
  • docs/CHECKLIST.md, tools/scan_codefindings.py, vendored
    stb_image_write.h; README CI badge + screenshot.

Fixed

  • crt-consumer.slangp black screen: UBO member parsing stripped smooth
    from float smoothness; via a left-token match, leaving member ness
    zero-initialized and the corner mask at 0. Added a right-token-boundary
    check plus a SLANGVK_FILL_DEBUG block-fill dump in chain.cpp, with a
    byte-exact golden regression (tests/data/runner/smoothqual.*).
  • analog-service-menu.slangp include target outside the shaders root:
    the SEC-01 ancestor-retry now also fires on that error string (previously
    only on cannot-open).
  • shader_demo defaulted to the animated pattern (characters never visible);
    it now defaults to the testcard image and falls back only if the asset is
    missing.

1.6.0-libslang-vk-v3

Choose a tag to compare

@VTSTech VTSTech released this 18 Oct 01:28

1.6.0-libslang-vk-01ea2bf

Choose a tag to compare

@VTSTech VTSTech released this 17 Oct 23:52

1.6.0-libslang-vk-a98c6d5

Choose a tag to compare

@VTSTech VTSTech released this 17 Oct 20:28

What's Changed

Full Changelog: gpu-shaders-v18...libslang-vk-v1