Files
punktfunk/packaging/windows/pf-vkhdr-layer
enricobuehler e6bcac8770
apple / swift (pull_request) Successful in 1m34s
apple / screenshots (pull_request) Skipped
ci / web (pull_request) Successful in 1m6s
ci / rust-arm64 (pull_request) Successful in 1m31s
ci / bun-nix (pull_request) Successful in 21s
ci / docs-site (pull_request) Successful in 1m23s
android / android (pull_request) Successful in 3m58s
ci / rust (pull_request) Successful in 8m28s
nix / flake (pull_request) Successful in 13m20s
windows-drivers / probe-and-proto (pull_request) Successful in 2m56s
windows-drivers / driver-build (pull_request) Successful in 10m19s
windows / build (aarch64-pc-windows-msvc) (pull_request) Successful in 18m19s
windows / build (x86_64-pc-windows-msvc) (pull_request) Successful in 24m1s
chore(license): name the copyright holder "unom - Enrico Bühler"
"unom" alone is not the legal entity name. Updated the copyright line in
all nine first-party license files -- the root MIT/Apache pair and the
hand-maintained copies under clients/apple, clients/decky,
packaging/windows/drivers and packaging/windows/pf-vkhdr-layer (there is
no script that syncs these, so each is edited directly).

The Linux and Windows clients' About screens pick this up automatically:
both `include_str!` the root LICENSE-MIT / LICENSE-APACHE at compile time.

Deliberately untouched:
- Third-party license texts (Geist OFL, FFmpeg, VB-CABLE, the vendored
  pyrowave/Granite tree, KDE protocol XMLs, the os-icon licenses) -- those
  are other parties' copyrights.
- Publisher/author/maintainer metadata, which is identity rather than
  license text and is reported separately for a decision.
2026-08-06 23:16:16 +02:00
..

pf-vkhdr-layer — HDR Vulkan layer for the virtual display

A tiny Vulkan implicit layer (VK_LAYER_PUNKTFUNK_hdr_inject) that lets Vulkan games enable HDR while streaming over the punktfunk virtual display.

The problem it solves

On Windows, NVIDIA/AMD Vulkan ICDs do not advertise any HDR color space (VK_COLOR_SPACE_HDR10_ST2084_EXT, VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT) for a surface that lives on an IddCx indirect / virtual display — even when Windows "Use HDR" is on and the desktop is composited at 10-bit. So Vulkan games (Doom: The Dark Ages and the rest of id Tech, Indiana Jones and the Great Circle, …) query vkGetPhysicalDeviceSurfaceFormatsKHR, find no HDR color space, and refuse HDR ("This device does not support HDR"). D3D11/D3D12 HDR works on the very same display because the OS compositor drives it — only the Vulkan WSI enumeration is gated.

This was long believed unfixable from outside the GPU driver (the Apollo/Sunshine/Virtual-Display- Driver communities all concluded "it's in Windows's kernel"). It isn't: an on-box experiment proved the ICD happily accepts and presents a forced HDR swapchain on that exact virtual-display surface (vkCreateSwapchainKHR + vkSetHdrMetadataEXT + present all succeed) — it simply won't advertise the format. So the whole fix is to add the HDR surface formats to the enumeration the game queries; once the game requests that swapchain, the ICD honors it. Validated live: Doom: The Dark Ages enables HDR over the virtual display with this layer.

What it does

  • Intercepts vkGetPhysicalDeviceSurfaceFormatsKHR / ...2KHR, calls down to the ICD, and appends {A2B10G10R10_UNORM_PACK32, HDR10_ST2084_EXT} + {R16G16B16A16_SFLOAT, EXTENDED_SRGB_LINEAR_EXT} (deduped — a no-op on real HDR monitors that already list them).
  • Self-gates: it only injects when the surface's monitor actually has Windows advanced-color (HDR) enabled right now (checked via DisplayConfigGetDeviceInfo / GET_ADVANCED_COLOR_INFO). So it does nothing on SDR sessions/displays — no washed-out "SDR-in-HDR". It tracks VkSurfaceKHR → HWND by intercepting vkCreateWin32SurfaceKHR.
  • Everything else is pass-through dispatch chaining (instance + device).

It is shipped as an always-on implicit layer (loads via the registry, so it works regardless of how a game is launched — including via an already-running Steam, which env-based scoping can't guarantee). Because of the self-gate it is inert outside HDR streaming.

Controls

Variable Effect
DISABLE_PF_VKHDR=1 Loader-standard off-switch — disables the whole layer for that process.
PF_VKHDR_EXCLUDE=foo.exe,bar.exe Extra exe basenames to skip (in addition to a small built-in kernel-anti-cheat default list: cs2.exe, rainbowsix.exe, …).
PF_VKHDR_LOG=1 Write a debug log to %TEMP%\pf_vkhdr_layer.log.

Build / install

Standalone crate (own [workspace]), Windows-only cdylib:

cargo build --release           # -> target/release/pf_vkhdr_layer.dll

The host installer (packaging/windows/pack-host-installer.ps1punktfunk-host.iss) builds it, lays pf_vkhdr_layer.dll + pf_vkhdr_layer.json into {app}\vklayer, and registers it under HKLM64\SOFTWARE\Khronos\Vulkan\ImplicitLayers (opt-out task "Install the HDR Vulkan layer").

Manual dev install: drop the DLL + JSON in one directory and add a REG_DWORD value named after the JSON's full path (data 0) under HKLM\SOFTWARE\Khronos\Vulkan\ImplicitLayers (or HKCU\...). Confirm with vulkaninfo (Surface section) — HDR10_ST2084_EXT should appear when the display has HDR enabled.

Notes

  • x64 only (the Windows host is x64 only).
  • Anti-cheat: the layer is benign (it only adds surface formats; it never touches rendering, memory, or input) and is signed, but because it's always-on it is present in every Vulkan process. The built-in exclude list + PF_VKHDR_EXCLUDE + DISABLE_PF_VKHDR cover kernel-anti- cheat titles you'd rather it stay out of.