feat(encode/vulkan): Vulkan Video encodes 10-bit, so AMD/Intel HDR keeps the good path
The Vulkan Video backend was 8-bit for no structural reason — the API has `VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT` and `PROFILE_IDC_MAIN_10` in the very fields this pinned to 8 and MAIN, and AMD VCN and Intel both encode Main10. It was six hardcoded sites, and the cost of leaving them was paid twice over: an HDR session had to take libav VAAPI, losing real RFI loss recovery AND the compute CSC's cursor blend — which on gamescope is the only way the pointer reaches the stream at all, since gamescope has no embedded-cursor mode. An HDR session now opens a Main10 profile with 10-bit component depths, a `G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16` picture + DPB, and an SPS carrying `bit_depth_*_minus8 = 2` with the BT.2020/PQ CICP triplet instead of BT.709. `rgb2yuv10.comp` is the CSC's twin, and the two interesting parts of it are: * it is a PURE 3x3 matrix. The samples arrive already PQ-encoded (gamescope composites into the PQ container), so BT.2020 NCL applies to the code values as they are — there is no transfer function to apply here and applying one would be wrong; * the scratch planes are `R16`/`RG16`, not the picture's plane formats. The 10-bit ycbcr plane formats are not storage-image formats, so the shader writes the value into the HIGH bits by hand (`code10 << 6`, hence the `64/65535` factor and not `1/1023`) into planes that are merely SIZE-compatible with the picture's — which is all `vkCmdCopyImage` requires. Scope and safety: * HEVC only. AV1 10-bit encode has far thinner driver coverage, and a session open is not the place to gamble on it — those stay on VAAPI, as does a device that fails the Main10 profile query inside the open (the pre-existing "failed Vulkan open falls back to VAAPI" net, no new probe needed). * HDR pins the compute-CSC arm over the EFC RGB-direct one, which the EFC could not serve anyway: its fixed-function conversion is 8-bit BT.709 narrow with no knob for BT.2020. * `open_inner` binds `hdr` to the parameter-set HEADER bytes, so the depth flag is `ten_bit` there — the one name collision this change had to route around.
This commit is contained in:
@@ -27,8 +27,9 @@ the Punktfunk sysext; there's an Arch package, a NixOS option, and a build scrip
|
||||
else. `punktfunk-host hdr-probe` tells you exactly which pieces are in place.
|
||||
|
||||
Opt-in for this release while it soaks: without the knob, or without the extra package, the
|
||||
gamescope path streams SDR exactly as before. One known gap on AMD and Intel: the on-screen mouse
|
||||
pointer is missing from HDR sessions (NVIDIA is unaffected) — SDR sessions still have it.
|
||||
gamescope path streams SDR exactly as before. One thing to know on AMD and Intel: keep the codec on
|
||||
HEVC — a 10-bit AV1 session falls back to a slower encode path that also loses the on-screen mouse
|
||||
pointer. NVIDIA is unaffected either way.
|
||||
|
||||
## Fixed: newer KDE Plasma silently fell back to a slower, less reliable way to arrange displays
|
||||
|
||||
@@ -45,7 +46,8 @@ On current KDE Plasma (6.7 and newer), Punktfunk's direct way of talking to the
|
||||
- **KWin's in-process output-management path now also binds `kde_output_device_registry_v2`**, not just the per-output `kde_output_device_v2` globals it originally shipped with — KWin 6.7 stopped advertising the latter, so the module written specifically to avoid shelling out to `kscreen-doctor` (0.19.x) saw zero devices and silently degraded to it on every session. Both models are supported now; registry-sourced devices arrive one Wayland round-trip later, so the handshake gains one conditional extra barrier.
|
||||
- **gamescope HDR is decided statically, before the display exists.** The punktfunk/1 Welcome fixes a session's bit depth up front and cannot take it back (PQ frames on an 8-bit encoder are a deliberate hard error), so the capability answer is the identity of the gamescope binary the host will spawn — a `+pfhdr` marker in its `--version` banner, probed once per boot — never an optimistic negotiation. The capture-side gate became source-aware (`capturer_supports_hdr_for(compositor)`), the HDR negotiation-failure latch became per-source (a wedged monitor mirror no longer disables a gamescope session's HDR, or vice versa), and the keep-alive reuse key gained `hdr` so a display brought up SDR can never be handed to an HDR session. The GameStream plane's live BT.2100 monitor probe is now scoped to the portal source — a headless gamescope box has no monitor to be in HDR mode.
|
||||
- **The gamescope patch mirrors code already in gamescope's tree.** Its PipeWire node additionally offers `xRGB_210LE`/`xBGR_210LE` with MANDATORY SMPTE ST.2084 + BT.2020 properties, mapped to `DRM_FORMAT_XRGB2101010`/`XBGR2101010` — the same 10-bit capture texture the HDR AVIF screenshot path allocates — and `paint_pipewire()` composites into them with the HDR screenshot LUT set and `EOTF_PQ`, which is exactly the `bHDRScreenshot` branch. The new formats are listed last, so every existing consumer keeps negotiating the 8-bit stream bit-for-bit, and the fixed PQ container is deliberately *not* conditional on the focused app being HDR (a stream's colourimetry must not follow what the game happens to render).
|
||||
- **AMD/Intel HDR needs no new encoder code**; NVIDIA gained a zero-copy leg. The VAAPI path already ingested XR30 dmabufs into `format=p010:out_color_matrix=bt2020`. On NVIDIA the packed 10-bit frame now travels LINEAR dmabuf → Vulkan bridge → CUDA → NVENC `ARGB10`/`ABGR10`, letting NVENC do the BT.2020 CSC itself: no host CSC pass, no depth loss, and the cursor-blend compute shader gained two 10-bit modes so the pointer survives. The tiled EGL de-tile blit is still 8-bit and HDR never routes through it. A host without the direct-SDK NVENC backend keeps HDR on the CPU path, since libav's HDR route swscales into a P010 hardware frame that a packed-10-bit CUDA buffer cannot fill.
|
||||
- **Vulkan Video learned 10-bit** (HEVC Main10), which is what keeps AMD/Intel HDR on the good path: an HDR session opens a Main10 video profile with 10-bit component depths, a `G10X6…3PACK16` picture and DPB, an SPS carrying `bit_depth_*_minus8 = 2` and the BT.2020/PQ CICP triplet, and a new `rgb2yuv10.comp` — the 8-bit BT.709 shader's twin, doing a pure BT.2020 NCL matrix on the already-PQ-encoded samples (there is no transfer function to apply, and applying one would be wrong) and writing 10-bit values into the high bits of `R16`/`RG16` scratch planes that are size-compatible with the picture's. That keeps the two things HDR would otherwise cost on this vendor: real RFI loss recovery, and the compute CSC's cursor blend — the only way a gamescope pointer reaches the stream at all. 10-bit **AV1** still routes to libav VAAPI: encode-side driver coverage for it is far thinner than Main10. A device that can't do Main10 fails the profile query inside the open and lands on the same VAAPI fallback as any other unsupported config.
|
||||
- **AMD/Intel HDR needs no new encoder code on the VAAPI fallback**; NVIDIA gained a zero-copy leg. The VAAPI path already ingested XR30 dmabufs into `format=p010:out_color_matrix=bt2020`. On NVIDIA the packed 10-bit frame now travels LINEAR dmabuf → Vulkan bridge → CUDA → NVENC `ARGB10`/`ABGR10`, letting NVENC do the BT.2020 CSC itself: no host CSC pass, no depth loss, and the cursor-blend compute shader gained two 10-bit modes so the pointer survives. The tiled EGL de-tile blit is still 8-bit and HDR never routes through it. A host without the direct-SDK NVENC backend keeps HDR on the CPU path, since libav's HDR route swscales into a P010 hardware frame that a packed-10-bit CUDA buffer cannot fill.
|
||||
- **CI-only fix:** the winget release-verification step's `envs:` allow-list was a step-level sibling of `with:`/`env:` instead of nested inside `with:`, so `appleboy/ssh-action` never actually received it as an input and the step kept failing on every tag. Moved to match how `REGISTRY_TOKEN` is already forwarded elsewhere.
|
||||
|
||||
See [v0.20.1](v0.20.1.md) for the fixes carried by that release (Windows install/winget, GameStream opt-in default, the gamescope Game Mode takeover hardening, a laptop-panel stall fix, and the PyroWave latency-creep bundle) — all included here too, since this release supersedes it.
|
||||
|
||||
Reference in New Issue
Block a user