Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 491a344f23 | |||
| d398e2296f | |||
| f9668b16a1 |
Generated
+27
-27
@@ -2159,7 +2159,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "latency-probe"
|
name = "latency-probe"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
@@ -2264,7 +2264,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libvpl-sys"
|
name = "libvpl-sys"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"cmake",
|
"cmake",
|
||||||
@@ -2299,7 +2299,7 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loss-harness"
|
name = "loss-harness"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"punktfunk-core",
|
"punktfunk-core",
|
||||||
]
|
]
|
||||||
@@ -2788,7 +2788,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-capture"
|
name = "pf-capture"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
@@ -2808,7 +2808,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-client-core"
|
name = "pf-client-core"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
@@ -2832,7 +2832,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-clipboard"
|
name = "pf-clipboard"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
@@ -2850,7 +2850,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-console-ui"
|
name = "pf-console-ui"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
@@ -2871,7 +2871,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-encode"
|
name = "pf-encode"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
@@ -2894,7 +2894,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-ffvk"
|
name = "pf-ffvk"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ash",
|
"ash",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
@@ -2903,7 +2903,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-frame"
|
name = "pf-frame"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2915,7 +2915,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-gpu"
|
name = "pf-gpu"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"pf-host-config",
|
"pf-host-config",
|
||||||
@@ -2929,11 +2929,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-host-config"
|
name = "pf-host-config"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-inject"
|
name = "pf-inject"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
@@ -2961,14 +2961,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-paths"
|
name = "pf-paths"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-presenter"
|
name = "pf-presenter"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
@@ -2983,7 +2983,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-vdisplay"
|
name = "pf-vdisplay"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ashpd",
|
"ashpd",
|
||||||
@@ -3013,7 +3013,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-win-display"
|
name = "pf-win-display"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"pf-paths",
|
"pf-paths",
|
||||||
@@ -3025,7 +3025,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pf-zerocopy"
|
name = "pf-zerocopy"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ash",
|
"ash",
|
||||||
@@ -3221,7 +3221,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-client-android"
|
name = "punktfunk-client-android"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_logger",
|
"android_logger",
|
||||||
"jni",
|
"jni",
|
||||||
@@ -3237,7 +3237,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-client-linux"
|
name = "punktfunk-client-linux"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
@@ -3253,7 +3253,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-client-session"
|
name = "punktfunk-client-session"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"pf-client-core",
|
"pf-client-core",
|
||||||
@@ -3268,7 +3268,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-client-windows"
|
name = "punktfunk-client-windows"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"ffmpeg-next",
|
"ffmpeg-next",
|
||||||
@@ -3287,7 +3287,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-core"
|
name = "punktfunk-core"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3318,7 +3318,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-host"
|
name = "punktfunk-host"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
@@ -3400,7 +3400,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-probe"
|
name = "punktfunk-probe"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"mdns-sd",
|
"mdns-sd",
|
||||||
@@ -3414,7 +3414,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "punktfunk-tray"
|
name = "punktfunk-tray"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ksni",
|
"ksni",
|
||||||
@@ -3437,7 +3437,7 @@ checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyrowave-sys"
|
name = "pyrowave-sys"
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"cmake",
|
"cmake",
|
||||||
|
|||||||
+1
-1
@@ -48,7 +48,7 @@ exclude = [
|
|||||||
ndk = { path = "clients/android/native/vendor/ndk" }
|
ndk = { path = "clients/android/native/vendor/ndk" }
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.14.0"
|
version = "0.15.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.82"
|
rust-version = "1.82"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
"name": "MIT OR Apache-2.0",
|
"name": "MIT OR Apache-2.0",
|
||||||
"identifier": "MIT OR Apache-2.0"
|
"identifier": "MIT OR Apache-2.0"
|
||||||
},
|
},
|
||||||
"version": "0.14.0"
|
"version": "0.15.0"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/v1/clients": {
|
"/api/v1/clients": {
|
||||||
|
|||||||
@@ -27,9 +27,13 @@ ui = ["dep:pf-console-ui", "dep:serde_json"]
|
|||||||
# Same Linux+Windows gating as the rest of the client stack; elsewhere this is a stub
|
# Same Linux+Windows gating as the rest of the client stack; elsewhere this is a stub
|
||||||
# binary.
|
# binary.
|
||||||
[target.'cfg(any(target_os = "linux", windows))'.dependencies]
|
[target.'cfg(any(target_os = "linux", windows))'.dependencies]
|
||||||
pf-presenter = { path = "../../crates/pf-presenter" }
|
# `default-features = false` on both: THIS crate's `pyrowave` feature (above) is the single
|
||||||
|
# switch that turns the wavelet codec on, and it enables it explicitly on each. Inheriting their
|
||||||
|
# defaults instead would make `--no-default-features` a lie — the Windows ARM64 leg builds that
|
||||||
|
# way precisely to skip the vendored PyroWave C++, which has no ARM64 SIMD path.
|
||||||
|
pf-presenter = { path = "../../crates/pf-presenter", default-features = false }
|
||||||
pf-console-ui = { path = "../../crates/pf-console-ui", optional = true }
|
pf-console-ui = { path = "../../crates/pf-console-ui", optional = true }
|
||||||
pf-client-core = { path = "../../crates/pf-client-core" }
|
pf-client-core = { path = "../../crates/pf-client-core", default-features = false }
|
||||||
punktfunk-core = { path = "../../crates/punktfunk-core", features = ["quic"] }
|
punktfunk-core = { path = "../../crates/punktfunk-core", features = ["quic"] }
|
||||||
# The fake-library dev hook (`PUNKTFUNK_FAKE_LIBRARY`, browse mode) parses GameEntry JSON.
|
# The fake-library dev hook (`PUNKTFUNK_FAKE_LIBRARY`, browse mode) parses GameEntry JSON.
|
||||||
serde_json = { version = "1", optional = true }
|
serde_json = { version = "1", optional = true }
|
||||||
|
|||||||
@@ -29,7 +29,17 @@ punktfunk-core = { path = "../../crates/punktfunk-core", features = ["quic"] }
|
|||||||
# The shared client service layer: the trust/settings stores (ONE `Settings` struct for the
|
# The shared client service layer: the trust/settings stores (ONE `Settings` struct for the
|
||||||
# shell and the spawned session binary — src/trust.rs re-exports it) and the game-library
|
# shell and the spawned session binary — src/trust.rs re-exports it) and the game-library
|
||||||
# data model (fetch + art pipeline) behind the library page.
|
# data model (fetch + art pipeline) behind the library page.
|
||||||
pf-client-core = { path = "../../crates/pf-client-core" }
|
#
|
||||||
|
# `default-features = false` drops pf-client-core's default `pyrowave`, which would otherwise
|
||||||
|
# build the vendored PyroWave C++ INTO THE SHELL — dead weight here (the shell never decodes;
|
||||||
|
# it only offers "pyrowave" as a codec preference string the session binary acts on) and fatal
|
||||||
|
# on ARM64, where Granite's math falls back to x86 SSE intrinsics and stops at
|
||||||
|
# `simd.hpp: #error "Implement me."`. This does NOT drop PyroWave from the Windows client:
|
||||||
|
# decode lives in the spawned punktfunk-session binary, whose own default enables the feature,
|
||||||
|
# and cargo's feature unification turns it back on for the shared pf-client-core whenever that
|
||||||
|
# binary is in the same build (x64). On the ARM64 leg both are built --no-default-features, so
|
||||||
|
# nothing enables it and the C++ is never compiled.
|
||||||
|
pf-client-core = { path = "../../crates/pf-client-core", default-features = false }
|
||||||
|
|
||||||
# WinUI 3 UI via windows-reactor (a declarative React-like framework backed by WinUI). Its
|
# WinUI 3 UI via windows-reactor (a declarative React-like framework backed by WinUI). Its
|
||||||
# `build.rs` downloads the Windows App SDK NuGets and stages the bootstrap DLL + resources.pri
|
# `build.rs` downloads the Windows App SDK NuGets and stages the bootstrap DLL + resources.pri
|
||||||
|
|||||||
@@ -59,9 +59,14 @@
|
|||||||
</Application>
|
</Application>
|
||||||
<!--
|
<!--
|
||||||
Second entry point: the couch/console UI, for an HTPC or a TV-attached box where the
|
Second entry point: the couch/console UI, for an HTPC or a TV-attached box where the
|
||||||
desktop shell is the wrong first screen. Same full-trust executable, launched with
|
desktop shell is the wrong first screen. Its own executable (punktfunk-console.exe)
|
||||||
`--console`, which hands straight off to the session binary's controller-driven
|
because an MSIX Application entry cannot pass arguments to a full-trust exe; it hands
|
||||||
browse mode (host list, pairing, settings, library) fullscreen.
|
straight off to the session binary's controller-driven browse mode (host list,
|
||||||
|
pairing, settings, library) fullscreen.
|
||||||
|
|
||||||
|
NOTE: never write a double hyphen in this file. XML forbids it inside a comment, and
|
||||||
|
makepri rejects the whole manifest ("Appx manifest not found or is invalid") — which
|
||||||
|
is exactly how the console flag spelled out here broke the v0.15.0 MSIX build.
|
||||||
-->
|
-->
|
||||||
<Application Id="PunktfunkConsole" Executable="punktfunk-console.exe"
|
<Application Id="PunktfunkConsole" Executable="punktfunk-console.exe"
|
||||||
EntryPoint="Windows.FullTrustApplication">
|
EntryPoint="Windows.FullTrustApplication">
|
||||||
|
|||||||
@@ -1078,7 +1078,18 @@ impl Encoder for NvencCudaEncoder {
|
|||||||
// 4:4:4 honesty: engage FREXT only on a genuine YUV444 input; a subsampled NV12/RGB input
|
// 4:4:4 honesty: engage FREXT only on a genuine YUV444 input; a subsampled NV12/RGB input
|
||||||
// can't reconstruct full chroma, so clear the flag so `caps().chroma_444` is truthful.
|
// can't reconstruct full chroma, so clear the flag so `caps().chroma_444` is truthful.
|
||||||
self.chroma_444 = self.chroma_444 && buf.yuv444;
|
self.chroma_444 = self.chroma_444 && buf.yuv444;
|
||||||
self.init_session()?;
|
// `init_session` publishes `self.encoder` before its remaining fallible steps (bitstream
|
||||||
|
// buffers, input-surface alloc, `register_resource`), so a failure there leaves a live
|
||||||
|
// session with `inited == false`. Every guard on the re-init path keys off `inited`, so
|
||||||
|
// without this the next submit would skip teardown and overwrite `self.encoder`, leaking
|
||||||
|
// the session and its registered input surfaces permanently. `teardown` keys off
|
||||||
|
// `encoder.is_null()`, not `inited`, so it cleans up exactly this half-built state.
|
||||||
|
if let Err(e) = self.init_session() {
|
||||||
|
// SAFETY: the encode thread owns the session and a failed init leaves nothing
|
||||||
|
// mid-encode to race with.
|
||||||
|
unsafe { self.teardown() };
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Steady state: the copy helpers need the shared context current on this thread.
|
// Steady state: the copy helpers need the shared context current on this thread.
|
||||||
cuda::make_current().context("cuCtxSetCurrent (encode thread)")?;
|
cuda::make_current().context("cuCtxSetCurrent (encode thread)")?;
|
||||||
|
|||||||
@@ -1135,7 +1135,19 @@ impl Encoder for NvencD3d11Encoder {
|
|||||||
self.chroma_444 = false;
|
self.chroma_444 = false;
|
||||||
}
|
}
|
||||||
let device = frame.device.clone();
|
let device = frame.device.clone();
|
||||||
self.init_session(&device)?;
|
// `init_session` publishes `self.encoder` (and charges LIVE_SESSION_UNITS) BEFORE its
|
||||||
|
// last fallible steps, so a failure there leaves a live session with `inited == false`.
|
||||||
|
// Every guard on the re-init path keys off `inited`, so without this the next submit
|
||||||
|
// would skip teardown and overwrite `self.encoder` — leaking the session permanently
|
||||||
|
// (toward the driver's per-process cap) along with its session-budget units.
|
||||||
|
// `teardown` keys off `encoder.is_null()`, not `inited`, so it cleans up exactly this
|
||||||
|
// half-built state and is a no-op when nothing was opened.
|
||||||
|
if let Err(e) = self.init_session(&device) {
|
||||||
|
// SAFETY: same contract as the teardown above — the encode thread owns the session,
|
||||||
|
// and a failed init leaves nothing mid-encode to race with.
|
||||||
|
unsafe { self.teardown() };
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
self.init_device = dev_raw;
|
self.init_device = dev_raw;
|
||||||
}
|
}
|
||||||
// The session's opening frame — NVENC emits it as an IDR regardless of pic flags, so the
|
// The session's opening frame — NVENC emits it as an IDR regardless of pic flags, so the
|
||||||
|
|||||||
@@ -146,7 +146,12 @@ const NUM_LTR_SLOTS: usize = 2;
|
|||||||
/// `PUNKTFUNK_NO_QSV_LTR` — defeat switch for the LTR-RFI path (parity with
|
/// `PUNKTFUNK_NO_QSV_LTR` — defeat switch for the LTR-RFI path (parity with
|
||||||
/// `PUNKTFUNK_NO_AMF_LTR`); loss recovery then always falls back to IDR.
|
/// `PUNKTFUNK_NO_AMF_LTR`); loss recovery then always falls back to IDR.
|
||||||
fn ltr_disabled() -> bool {
|
fn ltr_disabled() -> bool {
|
||||||
std::env::var("PUNKTFUNK_NO_QSV_LTR").is_ok_and(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
// Same accepted spellings as AMF's `ltr_disabled` — this had dropped the `trim()` and the
|
||||||
|
// `yes`/`on` forms, so a value with stray whitespace (easy to produce with `set VAR=1 `)
|
||||||
|
// silently left LTR enabled on Intel while the identical value worked on AMD.
|
||||||
|
std::env::var("PUNKTFUNK_NO_QSV_LTR")
|
||||||
|
.map(|v| matches!(v.trim(), "1" | "true" | "yes" | "on"))
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Frames between LTR marks (`PUNKTFUNK_LTR_INTERVAL_FRAMES`, shared with AMF); default ~1/4 s
|
/// Frames between LTR marks (`PUNKTFUNK_LTR_INTERVAL_FRAMES`, shared with AMF); default ~1/4 s
|
||||||
@@ -171,13 +176,22 @@ fn ltr_test_force_at() -> Option<i64> {
|
|||||||
/// Mirrors [`super::amf`]'s `PUNKTFUNK_INTRA_REFRESH` opt-in: request the intra-refresh wave
|
/// Mirrors [`super::amf`]'s `PUNKTFUNK_INTRA_REFRESH` opt-in: request the intra-refresh wave
|
||||||
/// instead of LTR (mutually exclusive — the wave sweeps the whole picture, LTR pins references).
|
/// instead of LTR (mutually exclusive — the wave sweeps the whole picture, LTR pins references).
|
||||||
fn intra_refresh_requested() -> bool {
|
fn intra_refresh_requested() -> bool {
|
||||||
|
// Spelling parity with AMF (see `ltr_disabled` above).
|
||||||
std::env::var("PUNKTFUNK_INTRA_REFRESH")
|
std::env::var("PUNKTFUNK_INTRA_REFRESH")
|
||||||
.is_ok_and(|v| v == "1" || v.eq_ignore_ascii_case("true"))
|
.map(|v| matches!(v.trim(), "1" | "true" | "yes" | "on"))
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The wave period in frames (~0.5 s), the same shape as Linux NVENC / AMF.
|
/// The wave period in frames (~0.5 s), `PUNKTFUNK_IR_PERIOD_FRAMES` overrides — the same knob and
|
||||||
|
/// default as AMF / Linux NVENC. (This claimed parity while ignoring the env var entirely, so the
|
||||||
|
/// knob silently did nothing on Intel; the clamp is kept because `mfxU16` bounds the field.)
|
||||||
fn intra_refresh_period(fps: u32) -> u16 {
|
fn intra_refresh_period(fps: u32) -> u16 {
|
||||||
(fps / 2).clamp(8, 240) as u16
|
std::env::var("PUNKTFUNK_IR_PERIOD_FRAMES")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.trim().parse::<u32>().ok())
|
||||||
|
.filter(|v| *v >= 2)
|
||||||
|
.unwrap_or(fps / 2)
|
||||||
|
.clamp(8, 240) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -223,6 +223,13 @@ impl Encoder for TrackedEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ceiling applied to the negotiated bitrate before it reaches openh264: software H.264 realistically
|
||||||
|
/// caps far below the rates a hardware session negotiates, and handing it the full figure just
|
||||||
|
/// misconfigures its rate control. Module-scope so BOTH software arms share one value — the Linux
|
||||||
|
/// arm was missing the clamp the Windows arm applied.
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||||
|
const SW_BITRATE_CEIL: u64 = 100_000_000;
|
||||||
|
|
||||||
/// Open the platform encoder backend. Returns the encoder together with the display label of the
|
/// Open the platform encoder backend. Returns the encoder together with the display label of the
|
||||||
/// branch that ACTUALLY opened (`nvenc`/`vaapi`/`vulkan`/`amf`/`qsv`/`software`) — the label feeds
|
/// branch that ACTUALLY opened (`nvenc`/`vaapi`/`vulkan`/`amf`/`qsv`/`software`) — the label feeds
|
||||||
/// the mgmt API's live-session record, and only the open site knows which internal fallback won
|
/// the mgmt API's live-session record, and only the open site knows which internal fallback won
|
||||||
@@ -407,8 +414,14 @@ fn open_video_backend(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let _ = (cuda, bit_depth); // software path is CPU + 8-bit only
|
let _ = (cuda, bit_depth); // software path is CPU + 8-bit only
|
||||||
sw::OpenH264Encoder::open(format, width, height, fps, bitrate_bps)
|
sw::OpenH264Encoder::open(
|
||||||
.map(|e| (Box::new(e) as Box<dyn Encoder>, "software"))
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
fps,
|
||||||
|
bitrate_bps.min(SW_BITRATE_CEIL),
|
||||||
|
)
|
||||||
|
.map(|e| (Box::new(e) as Box<dyn Encoder>, "software"))
|
||||||
}
|
}
|
||||||
"auto" | "" => {
|
"auto" | "" => {
|
||||||
// A CUDA frame can ONLY be consumed by NVENC. Otherwise the shared auto decision
|
// A CUDA frame can ONLY be consumed by NVENC. Otherwise the shared auto decision
|
||||||
@@ -610,8 +623,6 @@ fn open_video_backend(
|
|||||||
(build a GPU backend: --features nvenc or amf-qsv, or request H264)"
|
(build a GPU backend: --features nvenc or amf-qsv, or request H264)"
|
||||||
);
|
);
|
||||||
let _ = (bit_depth, chroma); // the software H.264 path is 8-bit 4:2:0 only
|
let _ = (bit_depth, chroma); // the software H.264 path is 8-bit 4:2:0 only
|
||||||
// Software H.264 realistically caps far below the negotiated hardware rates.
|
|
||||||
const SW_BITRATE_CEIL: u64 = 100_000_000;
|
|
||||||
sw::OpenH264Encoder::open(
|
sw::OpenH264Encoder::open(
|
||||||
format,
|
format,
|
||||||
width,
|
width,
|
||||||
@@ -784,6 +795,12 @@ fn nvidia_present() -> bool {
|
|||||||
/// picks its vendor's backend — AMD/Intel → VAAPI on that GPU's render node, NVIDIA → NVENC (still
|
/// picks its vendor's backend — AMD/Intel → VAAPI on that GPU's render node, NVIDIA → NVENC (still
|
||||||
/// requiring the proprietary driver's device nodes; a nouveau NVIDIA GPU can't NVENC) — otherwise
|
/// requiring the proprietary driver's device nodes; a nouveau NVIDIA GPU can't NVENC) — otherwise
|
||||||
/// today's NVIDIA-presence probe, unchanged.
|
/// today's NVIDIA-presence probe, unchanged.
|
||||||
|
///
|
||||||
|
/// ⚠ This resolves the **`auto` case only** — it deliberately ignores `encoder_pref`. It is NOT a
|
||||||
|
/// mirror of [`open_video`]'s dispatch and must not be used to decide which backend a capability
|
||||||
|
/// probe should ask: use [`linux_zero_copy_is_vaapi`], which layers `encoder_pref` on top of this.
|
||||||
|
/// (`can_encode_10bit` used this directly and answered for the wrong backend whenever a host
|
||||||
|
/// forced one.)
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn linux_auto_is_vaapi() -> bool {
|
fn linux_auto_is_vaapi() -> bool {
|
||||||
if let Some(g) = pf_gpu::manual_selection() {
|
if let Some(g) = pf_gpu::manual_selection() {
|
||||||
@@ -997,7 +1014,13 @@ pub fn can_encode_10bit(codec: Codec) -> bool {
|
|||||||
// only half the Linux gate — the capture side (GNOME 50+ portal monitor in HDR mode)
|
// only half the Linux gate — the capture side (GNOME 50+ portal monitor in HDR mode)
|
||||||
// is resolved separately by the host (`capturer_supports_hdr` / the GameStream RTSP
|
// is resolved separately by the host (`capturer_supports_hdr` / the GameStream RTSP
|
||||||
// honor), since this probe can't know what the compositor will negotiate.
|
// honor), since this probe can't know what the compositor will negotiate.
|
||||||
if linux_auto_is_vaapi() {
|
// Resolve through the SAME helper `can_encode_444` uses (and which mirrors
|
||||||
|
// `open_video`'s dispatch): `linux_auto_is_vaapi` ignores `encoder_pref`, so on a box
|
||||||
|
// that forces a backend — e.g. `encoder_pref = "vaapi"` on an NVIDIA host — this probe
|
||||||
|
// would answer for NVENC while the session actually opens VAAPI, and the negotiated bit
|
||||||
|
// depth (plus the HDR/SDR colour label derived from it) would describe a backend that
|
||||||
|
// never runs. That is exactly the dishonesty this probe exists to prevent.
|
||||||
|
if linux_zero_copy_is_vaapi() {
|
||||||
vaapi::probe_can_encode_10bit(codec)
|
vaapi::probe_can_encode_10bit(codec)
|
||||||
} else {
|
} else {
|
||||||
linux::probe_can_encode_10bit(codec)
|
linux::probe_can_encode_10bit(codec)
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ repository.workspace = true
|
|||||||
# Same Linux+Windows gating as the rest of the client stack (dmabuf import is the one
|
# Same Linux+Windows gating as the rest of the client stack (dmabuf import is the one
|
||||||
# Linux-only module — see lib.rs).
|
# Linux-only module — see lib.rs).
|
||||||
[target.'cfg(any(target_os = "linux", windows))'.dependencies]
|
[target.'cfg(any(target_os = "linux", windows))'.dependencies]
|
||||||
pf-client-core = { path = "../pf-client-core" }
|
# `default-features = false`: the PyroWave decode backend is turned on through THIS crate's own
|
||||||
|
# `pyrowave` feature (which re-exports it below), never by inheriting the dependency's default.
|
||||||
|
# Otherwise a consumer that deliberately builds us without `pyrowave` still drags the vendored
|
||||||
|
# C++ in — fatal on Windows ARM64, where Granite has no SIMD path.
|
||||||
|
pf-client-core = { path = "../pf-client-core", default-features = false }
|
||||||
# AVVkFrame access (Vulkan Video frames: live sync state under the frames lock).
|
# AVVkFrame access (Vulkan Video frames: live sync state under the frames lock).
|
||||||
pf-ffvk = { path = "../pf-ffvk" }
|
pf-ffvk = { path = "../pf-ffvk" }
|
||||||
punktfunk-core = { path = "../punktfunk-core", features = ["quic"] }
|
punktfunk-core = { path = "../punktfunk-core", features = ["quic"] }
|
||||||
|
|||||||
Reference in New Issue
Block a user