The client stops promising an HDR its video processor can't tone-map #427

Merged
enricobuehler merged 1 commits from worktree-arc-pq-tonemap-probe into main 2026-08-28 12:31:54 +00:00
Owner

Field report 2026-08-26 (Discord): an Intel Arc A370M client's monitor "turns green" on fullscreen against a Windows/RX 9070 XT host. The host logs pinned it: every H265 Main10 HDR session at the display-native 2880x1620@120 stormed decode-recovery keyframes + RFI on a ~2 s cycle, while AV1 8-bit SDR at the exact same mode ran clean — and the FEC feedback saw ~zero wire loss, so the frames died inside the client. Fullscreen was a proxy: it selects the display-native mode, and with the client's 10-bit setting on, HDR negotiates.

VIDEO_CAP_HDR invites a PQ stream. On a Windows box with no HDR10 swapchain, the D3D11VA hand-off shows that stream through the video processor's PQ→sRGB tonemap — a driver capability nothing ever validated. VideoProcessorSetStream/OutputColorSpace1 accept anything and the Blt succeeds either way; where the conversion is missing the driver renders garbage instead of failing. Our own host-side code documents the sibling on NVIDIA (RGB→P010 "renders green", pf-capture's VideoConverter docs).

The fix, following the 4:4:4-promise pattern:

  • video_d3d11::pq_tonemap_supported() — one throwaway device + enumerator on the presenter's adapter, asking ID3D11VideoProcessorEnumerator1::CheckVideoProcessorFormatConversion for the exact pair the SDR ring sets: P010 YCBCR_STUDIO_G2084_LEFT_P2020 in, BGRA8 RGB_FULL_G22_NONE_P709 out. Only the driver's definitive "no" answers false; an API failure keeps today's behaviour.
  • video::hdr_presentable() — wraps the probe behind the short-circuits that make it free everywhere it doesn't matter: no D3D11 import path (rung skipped entirely), HDR10 pass-through available (no tonemap needed), non-Windows (our own CSC shader tonemaps). The promise is checked against D3D11VA specifically because that rung is in every Windows ladder — first on Intel/unknown, the demotion target on NVIDIA/AMD.
  • The session binary ANDs the HDR setting with it, with a loud warn when the switch is on and not honored — the host then sends SDR instead of a stream the client can only show green. ten_bit_sdr stays unprobed on purpose: a 10-bit SDR stream is no tonemap.

Also: log_layout_once now keys on decoder × layout (frame dims, pool dims, PQ) instead of decoder alone, so a mid-stream Reconfigure or in-band SDR↔PQ flip re-logs the frame-vs-pool relationship — the fact a green-bar/smear report hinges on — for the shape that failed, not just the one the session started at.

Verified: cargo fmt + dockerized Linux clippy -D warnings green for pf-client-core + punktfunk-client-session. ⚠ The cfg(windows) half (the probe itself) is not compilable from the dev box and xcheck doesn't cover pf-client-corelet the Windows CI leg go green before merging (the exact gap that pushed a red main on 2026-07-25).

Scope caveat: this cures the unprobed-tonemap mechanism. The field report has a second candidate (references resolving into never-written P010 slots after the client's queue shed) that only the still-owed client-side log can confirm or rule out; if that one proves real it needs its own cure.

Field report 2026-08-26 (Discord): an Intel Arc A370M client's monitor "turns green" on fullscreen against a Windows/RX 9070 XT host. The host logs pinned it: every **H265 Main10 HDR** session at the display-native 2880x1620@120 stormed decode-recovery keyframes + RFI on a ~2 s cycle, while **AV1 8-bit SDR at the exact same mode ran clean** — and the FEC feedback saw ~zero wire loss, so the frames died inside the client. Fullscreen was a proxy: it selects the display-native mode, and with the client's 10-bit setting on, HDR negotiates. `VIDEO_CAP_HDR` invites a PQ stream. On a Windows box with no HDR10 swapchain, the D3D11VA hand-off shows that stream through the video processor's PQ→sRGB tonemap — a driver capability nothing ever validated. `VideoProcessorSetStream/OutputColorSpace1` accept anything and the Blt succeeds either way; where the conversion is missing the driver renders garbage instead of failing. Our own host-side code documents the sibling on NVIDIA (RGB→P010 "renders green", `pf-capture`'s `VideoConverter` docs). **The fix, following the 4:4:4-promise pattern:** - `video_d3d11::pq_tonemap_supported()` — one throwaway device + enumerator on the presenter's adapter, asking `ID3D11VideoProcessorEnumerator1::CheckVideoProcessorFormatConversion` for the exact pair the SDR ring sets: P010 `YCBCR_STUDIO_G2084_LEFT_P2020` in, BGRA8 `RGB_FULL_G22_NONE_P709` out. Only the driver's definitive "no" answers false; an API failure keeps today's behaviour. - `video::hdr_presentable()` — wraps the probe behind the short-circuits that make it free everywhere it doesn't matter: no D3D11 import path (rung skipped entirely), HDR10 pass-through available (no tonemap needed), non-Windows (our own CSC shader tonemaps). The promise is checked against D3D11VA specifically because that rung is in every Windows ladder — first on Intel/unknown, the demotion target on NVIDIA/AMD. - The session binary ANDs the HDR setting with it, with a loud warn when the switch is on and not honored — the host then sends SDR instead of a stream the client can only show green. `ten_bit_sdr` stays unprobed on purpose: a 10-bit SDR stream is no tonemap. **Also:** `log_layout_once` now keys on decoder × layout (frame dims, pool dims, PQ) instead of decoder alone, so a mid-stream `Reconfigure` or in-band SDR↔PQ flip re-logs the frame-vs-pool relationship — the fact a green-bar/smear report hinges on — for the shape that failed, not just the one the session started at. **Verified:** `cargo fmt` + dockerized Linux `clippy -D warnings` green for `pf-client-core` + `punktfunk-client-session`. ⚠ The `cfg(windows)` half (the probe itself) is not compilable from the dev box and `xcheck` doesn't cover `pf-client-core` — **let the Windows CI leg go green before merging** (the exact gap that pushed a red main on 2026-07-25). **Scope caveat:** this cures the unprobed-tonemap mechanism. The field report has a second candidate (references resolving into never-written P010 slots after the client's queue shed) that only the still-owed client-side log can confirm or rule out; if that one proves real it needs its own cure.
enricobuehler added 1 commit 2026-08-28 11:29:46 +00:00
fix(client): don't advertise HDR a video processor can't tone-map — the green-monitor Arc report
ci / rust-arm64 (pull_request) Successful in 1m55s
ci / web (pull_request) Successful in 1m55s
ci / bun-nix (pull_request) Successful in 24s
ci / docs-drift (pull_request) Successful in 31s
ci / docs-site (pull_request) Successful in 2m5s
windows-client / client (arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (pull_request) Successful in 3m17s
android / android (pull_request) Successful in 6m4s
ci / rust (pull_request) Successful in 8m12s
windows-client / client (x64, , x86_64-pc-windows-msvc, C:\t) (pull_request) Successful in 6m41s
a86edba4ca
VIDEO_CAP_HDR invites a PQ stream, and on a Windows box with no HDR10
swapchain the D3D11VA hand-off shows it through the video processor's
PQ->sRGB tonemap — a driver capability nothing ever validated. The Blt
accepts the colorspaces either way and renders garbage where the
conversion is missing (host-side sibling: NVIDIA RGB->P010 'renders
green'). Field 2026-08-26: an Arc A370M client went green on every HDR
session while AV1 8-bit SDR at the same 2880x1620@120 streamed clean.

video_d3d11 gains pq_tonemap_supported() — one throwaway device +
enumerator asked CheckVideoProcessorFormatConversion for the exact pair
the SDR ring sets (P010 G2084 studio in, BGRA8 sRGB out). Only the
driver's definitive 'no' answers false; API failure keeps today's
behaviour. video::hdr_presentable() wraps it behind the short-circuits
that make it free everywhere it doesn't matter (!d3d11_import,
d3d11_hdr10 pass-through, non-Windows shader tonemap), and the session
binary ANDs the HDR setting with it exactly like the 4:4:4 promise —
loud warn when the switch is on and not honored. ten_bit_sdr stays
unprobed on purpose: 10-bit SDR is no tonemap.

Also: log_layout_once keys on decoder x layout instead of decoder alone,
so a mid-stream Reconfigure or SDR<->PQ flip re-logs the frame-vs-pool
dims — the fact a green-bar/smear report hinges on — for the shape that
failed, not just the one the session started at.

Verified: cargo fmt + dockerized Linux clippy -D warnings green for
pf-client-core + punktfunk-client-session; the cfg(windows) half needs
the Windows CI leg (not compilable from this box).
enricobuehler merged commit d12d494f68 into main 2026-08-28 12:31:54 +00:00
enricobuehler deleted branch worktree-arc-pq-tonemap-probe 2026-08-28 12:31:59 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#427