d01a8fd17a
ci / web (push) Failing after 22s
windows-host / package (push) Failing after 4m16s
ci / rust (push) Failing after 4m56s
ci / docs-site (push) Successful in 1m7s
android / android (push) Successful in 9m19s
ci / bench (push) Successful in 4m47s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Failing after 3s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
docker / deploy-docs (push) Has been skipped
deb / build-publish (push) Failing after 6m29s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Failing after 7m4s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Failing after 7m17s
apple / swift (push) Successful in 1m13s
apple / screenshots (push) Successful in 5m27s
NVIDIA/AMD Vulkan ICDs refuse to *advertise* an HDR color space for a surface on an
IddCx indirect/virtual display, so Vulkan games (Doom: The Dark Ages, id Tech, Indiana
Jones, …) report "device does not support HDR" — even though Windows HDR, DWM compose,
and the client PQ stream all work, and the ICD happily *accepts + presents* a forced HDR
swapchain there. The whole gap is enumeration; the community (Apollo/Sunshine/VDD) wrote
this off as kernel-side / unfixable.
Add VK_LAYER_PUNKTFUNK_hdr_inject (packaging/windows/pf-vkhdr-layer/): a standalone
cdylib Vulkan implicit layer that appends {A2B10G10R10, HDR10_ST2084} + {RGBA16F, scRGB}
to vkGetPhysicalDeviceSurfaceFormats[2]KHR (no need to hook vkCreateSwapchainKHR — the
ICD doesn't validate the color space there). Self-gated on the surface monitor's actual
advanced-color state (DisplayConfig GET_ADVANCED_COLOR_INFO), so it is a complete no-op
on SDR sessions and real monitors (dedup). Always-on (registry-discovered) so it works
regardless of how a game is launched — env-scoping silently fails for already-running
Steam. Escape hatches: DISABLE_PF_VKHDR, PF_VKHDR_EXCLUDE, and a built-in kernel-anti-
cheat denylist.
The installer builds/signs/stages it and registers it under
HKLM64\SOFTWARE\Khronos\Vulkan\ImplicitLayers (opt-out "Install the HDR Vulkan layer"
task); windows-host CI fmt+clippy-gates it (msvc-only FFI).
Live-validated on the RTX box: Doom: The Dark Ages enables HDR over the pf-vdisplay
virtual display.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
4.0 KiB
Markdown
71 lines
4.0 KiB
Markdown
# 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`:
|
|
|
|
```sh
|
|
cargo build --release # -> target/release/pf_vkhdr_layer.dll
|
|
```
|
|
|
|
The host installer (`packaging/windows/pack-host-installer.ps1` → `punktfunk-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.
|