From 49c6dd00c940697adae4a0c7475010eca428c3ac Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Tue, 21 Jul 2026 13:21:54 +0200 Subject: [PATCH] fix(presenter): CPU frames never take the HDR10 passthrough surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Software decode uploads swscale RGBA with no CSC/tonemap pass. On the new desktop-compositor HDR10 surfaces (GNOME 48 / Plasma 6 + Mesa >= 25.1 offer ST2084 even on SDR desktops) that sRGB-encoded content was composed as PQ — the field-reported psychedelic picture (Fedora clients decode HEVC in software because stock Mesa strips it; reproduced + fix live-validated on GNOME Wayland: mode-0 soup -> HDR→SDR washed-out-but-correct). The CPU lane keeps the SDR swapchain and its known untonemapped-PQ gap; a real PQ→sRGB pass for CPU frames is the follow-up. Co-Authored-By: Claude Fable 5 --- crates/pf-presenter/src/vk/present.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/crates/pf-presenter/src/vk/present.rs b/crates/pf-presenter/src/vk/present.rs index 3c451cda..d7bdf9fc 100644 --- a/crates/pf-presenter/src/vk/present.rs +++ b/crates/pf-presenter/src/vk/present.rs @@ -30,9 +30,17 @@ impl Presenter { // switch modes before anything touches this frame. Only where the surface // offers HDR10 — otherwise PQ stays on the SDR swapchain and the CSC shader // tonemaps (mode 1). + // + // CPU frames NEVER take the HDR10 surface: software decode uploads swscale RGBA with + // no CSC/tonemap pass, so on a mode-0 swapchain that sRGB-encoded content would be + // composed as PQ — the field-reported psychedelic cyan/magenta picture (reproduced + // 2026-07-21: Fedora-class client, no hw HEVC decode, GNOME/Mesa offering HDR10 even + // on an SDR desktop). On the SDR swapchain the same frames are merely untonemapped + // (washed out) — wrong in the known, benign way until the CPU lane grows a real + // PQ→sRGB pass. let frame_pq = match &input { FrameInput::Redraw => None, - FrameInput::Cpu(f) => Some(f.color.is_pq()), + FrameInput::Cpu(_) => Some(false), #[cfg(target_os = "linux")] FrameInput::Dmabuf(d) => Some(d.color.is_pq()), FrameInput::VkFrame(v) => Some(v.color.is_pq()),