fix(encode): a forced-Vulkan pref must not advertise codecs that arm will refuse
ci / docs-site (push) Successful in 54s
ci / web (push) Successful in 56s
decky / build-publish (push) Successful in 20s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 10s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 11s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 9s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 8s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 8s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 59s
apple / swift (push) Successful in 5m10s
ci / bench (push) Successful in 5m58s
windows-host / package (push) Successful in 10m3s
deb / build-publish (push) Successful in 12m10s
docker / deploy-docs (push) Successful in 27s
deb / build-publish-host (push) Successful in 12m52s
android / android (push) Successful in 15m8s
arch / build-publish (push) Successful in 15m42s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m27s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 15m51s
ci / rust (push) Successful in 22m34s
apple / screenshots (push) Successful in 24m6s

With `PUNKTFUNK_ENCODER=vulkan`, `open_video_backend`'s vulkan arm bails outright for
anything that is not HEVC/AV1 ("the Vulkan Video encoder supports HEVC + AV1; the
session negotiated {codec:?}"). But `host_wire_caps` for that same pref fell through
to the VAAPI probe / static superset, which includes H.264 — so the host advertised
H.264, a client could negotiate it, and the session died at encoder open.

The pref now contributes a CEILING that is intersected with the device probe, never a
replacement for it. That distinction is the whole fix: pinning a static HEVC|AV1
would have ADDED AV1 on the AMD/Intel hosts whose probe currently withholds it
(pre-RDNA3, pre-Arc), re-creating this very bug for a different codec. Intersecting
can only ever narrow.

Without the `vulkan-encode` feature the pref cannot open anything at all — that arm
bails with "requires a build with --features vulkan-encode" — so the ceiling is
empty there rather than optimistic.

Costs nothing on the handshake path: a `&str` match plus a const-folded `cfg!`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-25 03:17:45 +02:00
co-authored by Claude Opus 5
parent 087a3e358a
commit 310b85f155
+23 -2
View File
@@ -78,13 +78,34 @@ impl Codec {
) { ) {
return punktfunk_core::quic::CODEC_H264; return punktfunk_core::quic::CODEC_H264;
} }
// A pref that FORCES the raw Vulkan Video backend can only ever serve what that
// backend encodes: `open_video_backend`'s `vulkan` arm bails outright for anything
// that is not HEVC/AV1 ("the Vulkan Video encoder supports HEVC + AV1; the session
// negotiated {codec:?}"). Advertising H.264 there let a client negotiate it and die
// at encoder open. Without the `vulkan-encode` feature that arm cannot open at all,
// so the pref advertises nothing.
//
// This is a CEILING intersected with the device probe below, never a replacement
// for it: pinning a static HEVC|AV1 would ADD AV1 on the AMD/Intel hosts whose probe
// currently withholds it (pre-RDNA3, pre-Arc), i.e. it would re-create this very bug
// for a different codec. Intersecting can only narrow.
let pref_ceiling: u8 = match pf_host_config::config().encoder_pref.as_str() {
"vulkan" | "vulkan-video" => {
if cfg!(feature = "vulkan-encode") {
punktfunk_core::quic::CODEC_HEVC | punktfunk_core::quic::CODEC_AV1
} else {
0
}
}
_ => GPU_SUPERSET,
};
if linux_zero_copy_is_vaapi() { if linux_zero_copy_is_vaapi() {
if let Some(m) = vaapi_codec_support().wire_mask() { if let Some(m) = vaapi_codec_support().wire_mask() {
return m; return m & pref_ceiling;
} }
} }
// NVENC (static superset, like GameStream) — or an empty VAAPI probe (see above). // NVENC (static superset, like GameStream) — or an empty VAAPI probe (see above).
GPU_SUPERSET GPU_SUPERSET & pref_ceiling
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
{ {