From 9c24569db6935acd9cf82ac386811abc59e18720 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 8 Aug 2026 14:08:27 +0200 Subject: [PATCH] fix(spike): --codec pyrowave encoded PyroWave off a capture negotiated for somebody else MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found while taking PW2's on-glass measurement, and it is what made the measurement possible. `spike` built its capture request from `OutputFormat::resolve`, the constructor shared with the GameStream path, which hard-codes `pyrowave: false` ("GameStream never negotiates PyroWave"). On Linux that flag is not cosmetic: `capture_virtual_output` feeds it to `zero_copy_policy` as `ZeroCopyPolicy::pyrowave_session`, which is what puts the capture on the raw-dmabuf passthrough. So `--codec pyrowave` opened a PyroWave encoder over a capture negotiated for a different consumer, and the only way to exercise the real path was the host-global `PUNKTFUNK_ENCODER=pyrowave` lever. That lever cannot stand in for the per-session flag, which is the part that matters here: it resolves the backend to `Pyrowave`, and `linux_zero_copy_is_vaapi_for` returns true for that — so it ALSO flips `backend_is_vaapi` on. A per-session PyroWave negotiation on an auto/NVENC host, where `backend_is_vaapi` is false, was therefore unreachable from the CLI — and that is exactly the configuration whose CPU downgrade logged nothing at all. The spike now sets the flag from its own codec, the same comparison `session_plan::output_format` makes for a real session. With it, the before/after on .21 is unambiguous: origin/main logs zero capture-path lines on that configuration, this branch logs two (the resolved arm, and the named downgrade with its cause and fix). --- crates/punktfunk-host/src/spike.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/punktfunk-host/src/spike.rs b/crates/punktfunk-host/src/spike.rs index 33b1169f..dca0f091 100644 --- a/crates/punktfunk-host/src/spike.rs +++ b/crates/punktfunk-host/src/spike.rs @@ -114,9 +114,21 @@ pub fn run(opts: Options) -> Result<()> { refresh_hz: opts.fps, }) .context("create virtual output")?; + // `resolve` is the shared GameStream/spike constructor and hard-codes `pyrowave: false` + // (GameStream never negotiates it). The spike DOES know its codec, and on Linux that + // flag is what puts the capture on the raw-dmabuf passthrough + // (`ZeroCopyPolicy::pyrowave_session`, set from the same comparison in + // `session_plan::output_format`). Left false, `--codec pyrowave` encoded PyroWave off a + // capture negotiated for somebody else, and the only way to exercise the real path was + // the host-global `PUNKTFUNK_ENCODER=pyrowave` lever — which ALSO flips + // `backend_is_vaapi`, so it cannot reproduce a per-session PyroWave negotiation on an + // auto/NVENC host at all. That is precisely the configuration PW2 exists for. + let mut want = + capture::OutputFormat::resolve(false, crate::encode::resolved_backend_is_gpu()); + want.pyrowave = opts.codec == Codec::PyroWave; capture::capture_virtual_output( vout, - capture::OutputFormat::resolve(false, crate::encode::resolved_backend_is_gpu()), + want, crate::session_plan::CaptureBackend::resolve(), compositor == crate::vdisplay::Compositor::Kwin, )