Commit Graph

7 Commits

Author SHA1 Message Date
enricobuehler fecbec2daf fix(encode): make LTR-RFI loss recovery sound under sustained loss
ci / web (push) Successful in 53s
ci / docs-site (push) Successful in 1m6s
apple / swift (push) Successful in 1m17s
decky / build-publish (push) Successful in 19s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 10s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 9s
ci / bench (push) Successful in 5m40s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 5m6s
apple / screenshots (push) Successful in 6m12s
deb / build-publish (push) Successful in 9m5s
docker / deploy-docs (push) Successful in 24s
deb / build-publish-host (push) Successful in 13m49s
windows-host / package (push) Successful in 16m17s
arch / build-publish (push) Successful in 17m24s
android / android (push) Successful in 12m53s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m31s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 20m5s
ci / rust (push) Successful in 25m35s
Field report (lid-closed Intel laptop, ~6-19% sustained loss): the stream
never healed — permanent macroblock soup. Three stacked bugs:

- QSV answered RFI with PreferredRefList only, a reorder HINT per the VPL
  spec — the recovery frame could keep predicting from tainted short-term
  refs. Now rejects every other DPB candidate (RejectedRefList) and caps
  L0 at one active entry (AVC/HEVC), matching AMF's hard
  ForceLTRReferenceBitfield / NVENC invalidation semantics.
- Neither QSV nor AMF taint-swept LTR slots across losses: a slot marked
  inside the client's corrupt window became the "known-good" anchor of the
  NEXT loss, propagating corruption through every recovery. Both now drop
  slots at-or-after the loss start before picking an anchor, and guard a
  queued force whose slot the sweep emptied (no false recovery_anchor tag).
- The native plane re-anchored the FULL IDR cooldown on every successful
  RFI, so under sustained loss the client's escalating keyframe requests
  were coalesced away indefinitely (field log: dozens swallowed, one IDR
  per ~8 s). RFI now anchors a 300 ms echo window with a 2-swallow budget
  per loss episode; a client still asking past that gets its IDR.

Live-validated on Arc (qsv feature): 6/6 including the new
qsv_live_ltr_rfi_taint_sweep_declines (a loss covering every live mark
declines the RFI and falls back to IDR recovery).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 17:53:48 +02:00
enricobuehler ebd9967547 feat(pyrowave): Windows host encoder — separate-plane zero-copy D3D11→Vulkan
Wire PyroWave into the Windows host (design/pyrowave-windows-host-zerocopy.md).
Before this a macOS client + Windows host that both selected PyroWave silently ran
HEVC: the host never advertised CODEC_PYROWAVE and open_video_backend bailed.

Approach (zero-copy, no GPU→CPU→GPU): pyrowave owns its own Vulkan device
(create_device_by_compat, by render-GPU vendor/device-id — NOT LUID, invalid in
Session 0). The capturer runs a BGRA→YUV BT.709-limited CSC (matching rgb2yuv.comp)
into TWO SEPARATE shareable plane textures — full-res R8 Y + half-res R8G8 CbCr —
which the encoder imports into pyrowave's device. Separate single/two-component
textures import reliably on NVIDIA at any size; a single planar NV12 import does NOT
(the vendored interop test: "only very specific resource sizes" — confirmed on-glass:
1024² fine, 720p/1080p/1440p garbage). A shared D3D11 fence, signalled after the CSC,
is imported as a Vulkan timeline semaphore so the wavelet read is ordered after it.

- pf-encode: enc/windows/pyrowave.rs (Encoder impl, two-plane import + Linux-style
  plane views); host_wire_caps advertises CODEC_PYROWAVE on Windows when the backend
  isn't Software; open_video_backend routes a negotiated PyroWave session first;
  pyrowave-sys on the Windows target; interop confirmed at open → clean HEVC fallback.
- pf-encode: shared, unit-tested enc/pyrowave_wire.rs (single source of truth for the
  client-facing AU framing); Linux encoder uses it too.
- pf-capture: dxgi.rs BgraToYuvPlanes CSC; idd_push.rs pyrowave mode — forces the
  virtual display SDR (the VideoProcessor can't ingest the FP16 HDR ring), a
  two-plane shareable out-ring, a shared fence passed every frame (so a rebuilt
  encoder re-imports it). Threaded via OutputFormat::pyrowave.
- pf-frame: D3d11Frame::pyro carries the CbCr plane + fence; OutputFormat::pyrowave.

Verified on .173 (RTX 4090): full-host build + clippy -D warnings (nvenc,amf-qsv) +
fmt --all --check; pyrowave_wire unit tests; pyrowave_win_smoke GPU test round-trips
distinct Y/Cb/Cr (100/180/60) exactly at 1024²/720p/1080p/1440p; Stage-0 interop
validated in the real Session-0 service context on-glass. Deployed to the box.
Owed: final on-glass picture/latency confirmation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 11:39:44 +02:00
enricobuehler df70bf00f9 test(qsv): live on-glass matrix — HEVC, Main10+HDR, AV1 10-bit, LTR-RFI, no-IDR retarget
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:55:43 +02:00
enricobuehler 9e6ab9b94d fix(qsv): enable D3D11 multithread protection before SetHandle (on-glass -16 on Arc)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:52:44 +02:00
enricobuehler 0a617e7779 fix(qsv): clippy — per-block SAFETY comments, div_ceil, clamp, vec_box allow
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:44:16 +02:00
enricobuehler 75d1322b8a fix(qsv): end the inner borrow before the retarget param rebuild
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:39:08 +02:00
enricobuehler 55e7f3fca9 feat(encode): native QSV backend — libvpl-sys + qsv.rs (Phases 0-3 of design/native-qsv-encoder.md)
Vendored MIT VPL dispatcher (static, trimmed tree, pin 674d015b/v2.17.0) built
via cmake+bindgen behind new feature 'qsv' (pf-encode + punktfunk-host forward).
qsv.rs: dispatcher session on the capture adapter (LUID-matched), SetHandle
D3D11, AsyncDepth=1/GopRefDist=1/VDEnc/CBR + HRD-off low-latency config,
GetSurfaceForEncode + GPU CopySubresourceRegion input (zero-copy, no readback
path), bounded sync-point poll, in-place reset with teardown escalation, no-IDR
bitrate retarget (Reset + StartNewSequence=OFF), 10-bit P010 HEVC-Main10/AV1,
HDR mastering/CLL SEI-OBU at IDR + BT.2020/PQ VSI, LTR-RFI via mfxExtRefListCtrl
(AMF slot policy port, Query-gated per codec, wire-index FrameOrder pinning).
Dispatch: native-first with ffmpeg fallback + PUNKTFUNK_QSV_FFMPEG hatch;
probes (can_encode_10bit / windows_codec_support / windows_backend_is_probed)
now answer natively for QSV.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 19:34:18 +02:00