fix(host): warn loudly when a CUDA session runs a build without direct-SDK NVENC

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 00:03:26 +02:00
co-authored by Claude Fable 5
parent 0bca67f73e
commit d2b4e3d71c
+22
View File
@@ -817,6 +817,28 @@ fn open_nvenc_probed(
chroma,
)?) as Box<dyn Encoder>);
}
// 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();