fix(gamestream): advertise AV1 Main10, and honour HDR per negotiated codec
`ServerCodecModeSupport` layered `SCM_HEVC_MAIN10` and never `SCM_AV1_MAIN10`, on the stated theory that "the GameStream AV1 path is left off until live-confirmed". But the SDR baseline has always offered AV1 **Main8** to every client, so that path is either live or it is not — the DEPTH was never the uncertain part, and the omission only cost AV1-preferring clients their HDR. Now that the encoders probe 10-bit per codec, each bit is gated on that codec's own `can_encode_10bit` AND the SDR baseline already advertising it. A box that does HEVC Main10 but not 10-bit AV1 — or the reverse — advertises the truth instead of one bit standing in for both. Two gates follow from that: * `host_hdr_capable` becomes codec-agnostic (ANY 10-bit-capable codec makes the host HDR-capable). It was asking about HEVC alone, which would have hidden HDR entirely on a hypothetical AV1-only-10-bit box; * the RTSP honor gains the per-session half: a client that negotiated the codec this host CANNOT do 10-bit with degrades to 8-bit SDR there, rather than being handed a PQ label over an 8-bit stream. H.264 always lands there — there is no 10-bit H.264 encode anywhere. The unit test now pins each bit independently, including the two one-without- the-other cases a single shared flag got wrong in both directions.
This commit is contained in:
@@ -45,6 +45,7 @@ On current KDE Plasma (6.7 and newer), Punktfunk's direct way of talking to the
|
||||
- **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).
|
||||
- **Vulkan Video learned 10-bit**, which is what keeps AMD/Intel HDR on the good path: an HDR session opens a 10-bit video profile (HEVC Main10 / AV1 Main at 10 bits) with a `G10X6…3PACK16` picture and DPB, headers carrying the depth and the BT.2020/PQ CICP triplet — an SPS `bit_depth_*_minus8 = 2` for HEVC, `high_bitdepth` plus the matching sequence-header OBU bits for AV1 — 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.
|
||||
- **GameStream advertises its 10-bit codec bits per codec.** `ServerCodecModeSupport` layered `SCM_HEVC_MAIN10` and never `SCM_AV1_MAIN10` — a blanket omission on the theory that the GameStream AV1 path was unconfirmed, even though the SDR baseline has always offered AV1 Main8, so the depth was never the uncertain part. Each 10-bit bit is now gated on that codec's own `can_encode_10bit` probe AND the baseline already advertising it, and the RTSP honor degrades a session whose NEGOTIATED codec can't carry 10 bits rather than labelling an 8-bit stream PQ. `host_hdr_capable` became codec-agnostic to match (any 10-bit-capable codec makes the host HDR-capable; which one a session gets is the session's question).
|
||||
- **The Vulkan encode backend is now capability-probed per codec AND depth**, mirroring what the direct-SDK NVENC path already does with its GUID probe. `vkGetPhysicalDeviceVideoCapabilitiesKHR` is asked against the very profile the session open will build, so the dispatcher's prediction cannot disagree with reality: a device that can encode 10-bit keeps the Vulkan path, one that can't routes to libav VAAPI *before* burning a failed session open, and `can_encode_10bit` reports the union of what VAAPI and Vulkan Video can do rather than VAAPI's answer alone (which was under-reporting 10-bit on hardware that could do it).
|
||||
- **The zero-CSC RGB-direct (EFC) source works in HDR too.** The `VK_VALVE_video_encode_rgb_conversion` probe now asks for the BT.2020 model and the captured 10-bit packed-RGB format instead of assuming BT.709/BGRA, and the session selects the matching model — so an HDR session with no pointer to composite (the GameStream desktop mirror) hands the captured buffer straight to the encoder's fixed-function front end and runs no host CSC at all. Sessions that DO composite a pointer keep the compute CSC, as before: the EFC cannot blend.
|
||||
- **NVIDIA gained a zero-copy HDR leg**, and the VAAPI fallback needed no new encoder code. 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.
|
||||
|
||||
Reference in New Issue
Block a user