From d2b4e3d71c296a13cc4ae1f51a226c2116f97112 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Wed, 15 Jul 2026 00:03:26 +0200 Subject: [PATCH] fix(host): warn loudly when a CUDA session runs a build without direct-SDK NVENC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nvenc feature is off by default, and a Linux host built without --features punktfunk-host/nvenc silently compiles the direct-SDK path out: a CUDA session degrades to libav hevc_nvenc — no RFI loss recovery, an encoder rebuild + IDR on every adaptive-bitrate step, and the libav bitrate clamp — with nothing in the logs saying why. This bit the Linux packagers once (fixed in e89b2f60) and an ad-hoc host deploy again on 2026-07-14, where the on-glass Automatic-climb session showed rebuild-per-step behavior that read as a pipeline gap (it wasn't: the Portal/PipeWire path delivers EGL-imported CUDA NV12 frames and goes direct whenever the feature is in the build). One WARN per process, skipped under an explicit PUNKTFUNK_NVENC_DIRECT=0. Validated on .21 (GNOME/Mutter Portal capture, feature build): probe session logs `Linux direct-SDK NVENC`, and probe --rebitrate lands as `encoder bitrate reconfigured in place (adaptive bitrate — no IDR)`. Co-Authored-By: Claude Fable 5 --- crates/punktfunk-host/src/encode.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/crates/punktfunk-host/src/encode.rs b/crates/punktfunk-host/src/encode.rs index ae632ffd..21b32c63 100644 --- a/crates/punktfunk-host/src/encode.rs +++ b/crates/punktfunk-host/src/encode.rs @@ -817,6 +817,28 @@ fn open_nvenc_probed( chroma, )?) as Box); } + // The silent-degrade trap: a build without `--features nvenc` compiles the direct-SDK + // path OUT, and a CUDA session quietly loses real RFI + the no-IDR bitrate reconfigure + // with nothing in the logs. This bit the Linux packagers once (fixed e89b2f60) and an + // ad-hoc host deploy again on 2026-07-14 — say it loudly instead. (Skipped when the + // operator explicitly chose libav via PUNKTFUNK_NVENC_DIRECT=0.) + #[cfg(not(feature = "nvenc"))] + if cuda + && !std::env::var("PUNKTFUNK_NVENC_DIRECT") + .map(|v| matches!(v.trim(), "0" | "false" | "no" | "off")) + .unwrap_or(false) + { + // Once per process — featureless builds rebuild the encoder on every bitrate step, + // and one line is enough to diagnose the build. + static WARNED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); + if !WARNED.swap(true, std::sync::atomic::Ordering::Relaxed) { + tracing::warn!( + "direct-SDK NVENC is NOT compiled into this build (`--features punktfunk-host/nvenc`) \ + — CUDA frames take the libav path: no RFI loss recovery, and every adaptive-bitrate \ + step costs an encoder rebuild + IDR" + ); + } + } const MIN_PROBE_BPS: u64 = 50_000_000; let mut candidates = vec![bitrate_bps]; let cap = codec.max_bitrate_bps();