feat(pyrowave): Windows host HDR + 4:4:4, Rust client HDR present
Phase 3 of design/pyrowave-444-hdr.md. A PyroWave session now negotiates HDR
(10-bit) and 4:4:4 on a Windows host exactly like HEVC/AV1, and the Linux
client presents it through the real HDR10 path.
Host (Windows): BgraToYuvPlanes becomes mode-aware — SDR/BGRA and HDR/scRGB
variants at half- or full-res chroma. The HDR passes reuse HdrP010Converter's
exact colour math (scRGB -> PQ BT.2020 limited studio codes, verified by
hdr_p010_selftest) but write P010-style MSB-packed codes into two separate
shareable R16_UNORM/R16G16_UNORM textures; chroma keeps the pyrowave family's
centre-sited 2x2 box. idd_push pins the composition to the NEGOTIATED depth
(SDR sessions force advanced color off as before; 10-bit sessions enable it
and ride the FP16 ring), and the descriptor poller re-asserts that state
instead of following display flips the fixed-format encoder can't. The
encoder imports 8/16-bit planes per session and stamps the sequence header's
BT.2020/PQ/matrix bits on HDR (stamp_color_bits, extending 574e3e4e's range
stamp); supports_10bit/can_encode_10bit/can_encode_444 gates open (HDR
Windows-only — Linux capture has no HDR source).
Client: the plane ring becomes R16_UNORM for 10-bit sessions (with a
STORAGE_IMAGE format probe), the planar CSC pass joins the HDR10 swapchain
rebuild (set_hdr_mode previously destroyed it without rebuilding — latent),
st.hdr follows frame.color.is_pq(), and the planar push constants carry
depth-10 MSB-packed rows + the PQ tonemap mode, identical to the NV12 arm.
Verified: .173 (RTX 4090) deploy-config clippy + fmt + wire tests + the
extended pyrowave_win_smoke (10-case {SDR,HDR}x{420,444} matrix incl. R16
imports and header stamps); .21 (RTX 5070 Ti) clippy across 4 crates, host
186 tests, client/presenter/encode tests, both Linux GPU smokes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -37,11 +37,19 @@ pub(crate) fn packet_boundary(wire_chunk: Option<usize>, dense_cap: usize) -> us
|
||||
/// zeroed VUI fields (BT.709 primaries / transform / transfer) are already correct.
|
||||
///
|
||||
/// `seq_offset` is the byte offset of the frame's 8-byte `BitstreamSequenceHeader` in `bitstream` —
|
||||
/// the SOF packet's offset. `ycbcr_range` is bit 30 of the little-endian second word, i.e. bit 6 of
|
||||
/// byte `seq_offset + 7` (`0x40`).
|
||||
pub(crate) fn mark_limited_range(bitstream: &mut [u8], seq_offset: usize) {
|
||||
/// the SOF packet's offset. The colour bits live in the little-endian second word's top byte
|
||||
/// (`seq_offset + 7`): `color_primaries` bit 27 (`0x08`), `transfer_function` bit 28 (`0x10`),
|
||||
/// `ycbcr_transform` bit 29 (`0x20`), `ycbcr_range` bit 30 (`0x40`); `chroma_siting` bit 31 stays 0
|
||||
/// (CENTER — the pyrowave CSCs use the centre-sited 2×2 box, unlike the left-cosited P010 path).
|
||||
/// Range is ALWAYS stamped LIMITED (both CSCs emit studio range); `bt2020_pq` additionally stamps
|
||||
/// BT.2020 primaries + PQ transfer + BT.2020 matrix — upstream's own enum semantics
|
||||
/// (`pyrowave_common.hpp`), matching the session's negotiated `ColorInfo`.
|
||||
pub(crate) fn stamp_color_bits(bitstream: &mut [u8], seq_offset: usize, bt2020_pq: bool) {
|
||||
if let Some(b) = bitstream.get_mut(seq_offset + 7) {
|
||||
*b |= 0x40;
|
||||
if bt2020_pq {
|
||||
*b |= 0x08 | 0x10 | 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,16 +190,20 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mark_limited_range_sets_only_the_range_bit() {
|
||||
fn stamp_color_bits_sets_range_and_hdr_bits() {
|
||||
let mut bs = vec![0u8; 16];
|
||||
mark_limited_range(&mut bs, 0);
|
||||
stamp_color_bits(&mut bs, 0, false);
|
||||
// ycbcr_range = bit 30 of the LE second word = bit 6 of byte 7 (0x40); nothing else touched.
|
||||
assert_eq!(bs[7], 0x40);
|
||||
assert!(bs[..7].iter().all(|&b| b == 0));
|
||||
assert!(bs[8..].iter().all(|&b| b == 0));
|
||||
// Idempotent; an out-of-range offset is a silent no-op (never panics).
|
||||
mark_limited_range(&mut bs, 0);
|
||||
stamp_color_bits(&mut bs, 0, false);
|
||||
assert_eq!(bs[7], 0x40);
|
||||
mark_limited_range(&mut bs, 100);
|
||||
stamp_color_bits(&mut bs, 100, false);
|
||||
// HDR adds BT.2020 primaries (0x08) + PQ transfer (0x10) + BT.2020 matrix (0x20);
|
||||
// chroma_siting (0x80) stays CENTER.
|
||||
stamp_color_bits(&mut bs, 0, true);
|
||||
assert_eq!(bs[7], 0x78);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user