Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dab40ed98e |
@@ -51,6 +51,9 @@ const CODECS: &[(&str, &str)] = &[
|
|||||||
("hevc", "HEVC (H.265)"),
|
("hevc", "HEVC (H.265)"),
|
||||||
("h264", "H.264 (AVC)"),
|
("h264", "H.264 (AVC)"),
|
||||||
("av1", "AV1"),
|
("av1", "AV1"),
|
||||||
|
// Preference-only by design: `resolve_codec` never auto-picks PyroWave, and asking for
|
||||||
|
// it on a host or device that can't do it simply falls back down the ladder to HEVC.
|
||||||
|
("pyrowave", "PyroWave (wired LAN)"),
|
||||||
];
|
];
|
||||||
/// Virtual-pad presets: `(stored value, display label)` — the pad the HOST creates. Same set the
|
/// Virtual-pad presets: `(stored value, display label)` — the pad the HOST creates. Same set the
|
||||||
/// GTK client offers; "Automatic" resolves from the physical controller at connect.
|
/// GTK client offers; "Automatic" resolves from the physical controller at connect.
|
||||||
@@ -278,7 +281,7 @@ pub(crate) fn settings_page(
|
|||||||
s.codec = CODECS[i].0.to_string();
|
s.codec = CODECS[i].0.to_string();
|
||||||
})
|
})
|
||||||
.tooltip(
|
.tooltip(
|
||||||
"A soft preference \u{2014} the host falls back to the best codec both sides support.",
|
"A soft preference \u{2014} the host falls back to the best codec both sides support. PyroWave is the low-latency wavelet codec for a WIRED link: it trades bitrate (hundreds of Mb/s) for near-zero decode time, so it needs gigabit Ethernet.",
|
||||||
);
|
);
|
||||||
// Free-form Mb/s (0 = host default) instead of presets, so a speed-test recommendation
|
// Free-form Mb/s (0 = host default) instead of presets, so a speed-test recommendation
|
||||||
// round-trips exactly.
|
// round-trips exactly.
|
||||||
|
|||||||
@@ -24,6 +24,14 @@ ffmpeg-next = "8"
|
|||||||
opus = "0.3"
|
opus = "0.3"
|
||||||
|
|
||||||
mdns-sd = "0.20"
|
mdns-sd = "0.20"
|
||||||
|
|
||||||
|
# PyroWave decode (the opt-in wired-LAN wavelet codec, design/pyrowave-codec-plan.md
|
||||||
|
# §4.5) — pure Vulkan compute on the presenter's shared device, so it builds wherever the
|
||||||
|
# spawned Vulkan session presenter runs: Linux AND Windows (pyrowave-sys covers both; it
|
||||||
|
# is an empty stub elsewhere). `ash` only wraps the presenter's existing raw handles
|
||||||
|
# (same pinned version as pf-presenter).
|
||||||
|
pyrowave-sys = { path = "../pyrowave-sys", optional = true }
|
||||||
|
ash = { version = "0.38", optional = true }
|
||||||
# Game-library fetch from the host's management API over mTLS + fingerprint pinning.
|
# Game-library fetch from the host's management API over mTLS + fingerprint pinning.
|
||||||
# `ureq` is small + sync (the host uses it too) and its rustls unifies with the
|
# `ureq` is small + sync (the host uses it too) and its rustls unifies with the
|
||||||
# workspace's (quinn's) 0.23; the pinning verifier mirrors core's private `PinVerify`.
|
# workspace's (quinn's) 0.23; the pinning verifier mirrors core's private `PinVerify`.
|
||||||
@@ -40,11 +48,6 @@ tracing = "0.1"
|
|||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
pipewire = "0.9"
|
pipewire = "0.9"
|
||||||
sdl3 = { version = "0.18", features = ["hidapi"] }
|
sdl3 = { version = "0.18", features = ["hidapi"] }
|
||||||
# PyroWave decode (the opt-in wired-LAN wavelet codec, design/pyrowave-codec-plan.md
|
|
||||||
# §4.5) — pure Vulkan compute on the presenter's shared device. `ash` only wraps the
|
|
||||||
# presenter's existing raw handles (same pinned version as pf-presenter).
|
|
||||||
pyrowave-sys = { path = "../pyrowave-sys", optional = true }
|
|
||||||
ash = { version = "0.38", optional = true }
|
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
wasapi = "0.23"
|
wasapi = "0.23"
|
||||||
|
|||||||
@@ -41,11 +41,14 @@ mod video_software;
|
|||||||
mod video_vaapi;
|
mod video_vaapi;
|
||||||
#[cfg(any(target_os = "linux", windows))]
|
#[cfg(any(target_os = "linux", windows))]
|
||||||
mod video_vulkan;
|
mod video_vulkan;
|
||||||
// PyroWave decode — Linux + `pyrowave` feature only (plan §4.5; the Windows client's
|
// PyroWave decode — Linux + Windows (plan §4.5; the Apple Metal port is its own phase).
|
||||||
// present-path decision and the Apple Metal port are their own phases).
|
// Windows joined once its client moved to the SAME spawned Vulkan session presenter as
|
||||||
|
// Linux's: the decoder is plain Vulkan compute on the presenter's device (no fds, no
|
||||||
|
// dmabuf, no D3D11 interop), so the old "Windows present-path decision" that gated it
|
||||||
|
// resolved itself — the present path is now literally the same code.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod video_d3d11;
|
pub mod video_d3d11;
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
pub mod video_pyrowave;
|
pub mod video_pyrowave;
|
||||||
|
|
||||||
pub mod wol;
|
pub mod wol;
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ fn pump(
|
|||||||
// the plan-§3 contract: the host only ever picks PyroWave when the client names it.
|
// the plan-§3 contract: the host only ever picks PyroWave when the client names it.
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut preferred = params.preferred_codec;
|
let mut preferred = params.preferred_codec;
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if std::env::var("PUNKTFUNK_PREFER_PYROWAVE").as_deref() == Ok("1") {
|
if std::env::var("PUNKTFUNK_PREFER_PYROWAVE").as_deref() == Ok("1") {
|
||||||
if params.vulkan.as_ref().is_some_and(|v| v.pyrowave_decode) {
|
if params.vulkan.as_ref().is_some_and(|v| v.pyrowave_decode) {
|
||||||
preferred = punktfunk_core::quic::CODEC_PYROWAVE;
|
preferred = punktfunk_core::quic::CODEC_PYROWAVE;
|
||||||
@@ -296,7 +296,7 @@ fn pump(
|
|||||||
// A negotiated PyroWave session decodes on the presenter's device, no FFmpeg —
|
// A negotiated PyroWave session decodes on the presenter's device, no FFmpeg —
|
||||||
// reachable only through the explicit preference above (resolve_codec never
|
// reachable only through the explicit preference above (resolve_codec never
|
||||||
// auto-picks the bit), so failing loudly here is failing an opted-in experiment.
|
// auto-picks the bit), so failing loudly here is failing an opted-in experiment.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
let built = if connector.codec == punktfunk_core::quic::CODEC_PYROWAVE {
|
let built = if connector.codec == punktfunk_core::quic::CODEC_PYROWAVE {
|
||||||
let mode = connector.mode();
|
let mode = connector.mode();
|
||||||
// The wavelet bitstream has no VUI: the negotiated Welcome colour signalling IS
|
// The wavelet bitstream has no VUI: the negotiated Welcome colour signalling IS
|
||||||
@@ -325,7 +325,7 @@ fn pump(
|
|||||||
} else {
|
} else {
|
||||||
Decoder::new(codec_id, ¶ms.decoder, params.vulkan.as_ref())
|
Decoder::new(codec_id, ¶ms.decoder, params.vulkan.as_ref())
|
||||||
};
|
};
|
||||||
#[cfg(not(all(target_os = "linux", feature = "pyrowave")))]
|
#[cfg(not(all(any(target_os = "linux", windows), feature = "pyrowave")))]
|
||||||
let built = Decoder::new(codec_id, ¶ms.decoder, params.vulkan.as_ref());
|
let built = Decoder::new(codec_id, ¶ms.decoder, params.vulkan.as_ref());
|
||||||
let mut decoder = match built {
|
let mut decoder = match built {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
@@ -528,7 +528,7 @@ fn pump(
|
|||||||
DecodedImage::VkFrame(_) => "vulkan",
|
DecodedImage::VkFrame(_) => "vulkan",
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
DecodedImage::D3d11(_) => "d3d11va",
|
DecodedImage::D3d11(_) => "d3d11va",
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
DecodedImage::PyroWave(_) => "pyrowave",
|
DecodedImage::PyroWave(_) => "pyrowave",
|
||||||
};
|
};
|
||||||
if total_frames == 1 {
|
if total_frames == 1 {
|
||||||
@@ -539,7 +539,10 @@ fn pump(
|
|||||||
DecodedImage::VkFrame(v) => (v.width, v.height, "vulkan-video"),
|
DecodedImage::VkFrame(v) => (v.width, v.height, "vulkan-video"),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
DecodedImage::D3d11(d) => (d.width, d.height, "d3d11va"),
|
DecodedImage::D3d11(d) => (d.width, d.height, "d3d11va"),
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(
|
||||||
|
any(target_os = "linux", windows),
|
||||||
|
feature = "pyrowave"
|
||||||
|
))]
|
||||||
DecodedImage::PyroWave(f) => (f.width, f.height, "pyrowave"),
|
DecodedImage::PyroWave(f) => (f.width, f.height, "pyrowave"),
|
||||||
};
|
};
|
||||||
tracing::info!(width = w, height = h, path, "first frame decoded");
|
tracing::info!(width = w, height = h, path, "first frame decoded");
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ pub enum DecodedImage {
|
|||||||
/// PyroWave planar output: three R8 plane views on the presenter's own device,
|
/// PyroWave planar output: three R8 plane views on the presenter's own device,
|
||||||
/// decode already fence-complete, GENERAL layout — the presenter's planar CSC
|
/// decode already fence-complete, GENERAL layout — the presenter's planar CSC
|
||||||
/// samples them directly (BT.709 limited, the codec's fixed colour contract).
|
/// samples them directly (BT.709 limited, the codec's fixed colour contract).
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
PyroWave(crate::video_pyrowave::PyroWavePlanarFrame),
|
PyroWave(crate::video_pyrowave::PyroWavePlanarFrame),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ impl DecodedImage {
|
|||||||
DecodedImage::VkFrame(f) => f.keyframe,
|
DecodedImage::VkFrame(f) => f.keyframe,
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
DecodedImage::D3d11(f) => f.keyframe,
|
DecodedImage::D3d11(f) => f.keyframe,
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
DecodedImage::PyroWave(f) => f.keyframe,
|
DecodedImage::PyroWave(f) => f.keyframe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ impl DecodedImage {
|
|||||||
DecodedImage::VkFrame(f) => (f.width, f.height),
|
DecodedImage::VkFrame(f) => (f.width, f.height),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
DecodedImage::D3d11(f) => (f.width, f.height),
|
DecodedImage::D3d11(f) => (f.width, f.height),
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
DecodedImage::PyroWave(f) => (f.width, f.height),
|
DecodedImage::PyroWave(f) => (f.width, f.height),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,9 +238,10 @@ enum Backend {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
D3d11va(crate::video_d3d11::D3d11vaDecoder),
|
D3d11va(crate::video_d3d11::D3d11vaDecoder),
|
||||||
/// PyroWave (wired-LAN wavelet codec): pyrowave compute on the presenter's device,
|
/// PyroWave (wired-LAN wavelet codec): pyrowave compute on the presenter's device,
|
||||||
/// no FFmpeg involvement. No demotion rung — there is no other decoder for it.
|
/// no FFmpeg involvement (Linux + Windows — same Vulkan presenter on both). No demotion
|
||||||
|
/// rung — there is no other decoder for it.
|
||||||
/// Boxed: the decoder (pinned create-info hold + plane ring) dwarfs the other variants.
|
/// Boxed: the decoder (pinned create-info hold + plane ring) dwarfs the other variants.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
PyroWave(Box<crate::video_pyrowave::PyroWaveDecoder>),
|
PyroWave(Box<crate::video_pyrowave::PyroWaveDecoder>),
|
||||||
Software(SoftwareDecoder),
|
Software(SoftwareDecoder),
|
||||||
}
|
}
|
||||||
@@ -322,11 +323,11 @@ pub fn decodable_codecs() -> u8 {
|
|||||||
/// under its explicit opt-in.
|
/// under its explicit opt-in.
|
||||||
pub fn decodable_codecs_for(vk: Option<&VulkanDecodeDevice>) -> u8 {
|
pub fn decodable_codecs_for(vk: Option<&VulkanDecodeDevice>) -> u8 {
|
||||||
let bits = decodable_codecs();
|
let bits = decodable_codecs();
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if vk.map(|v| v.pyrowave_decode).unwrap_or(false) {
|
if vk.map(|v| v.pyrowave_decode).unwrap_or(false) {
|
||||||
return bits | punktfunk_core::quic::CODEC_PYROWAVE;
|
return bits | punktfunk_core::quic::CODEC_PYROWAVE;
|
||||||
}
|
}
|
||||||
#[cfg(not(all(target_os = "linux", feature = "pyrowave")))]
|
#[cfg(not(all(any(target_os = "linux", windows), feature = "pyrowave")))]
|
||||||
let _ = vk;
|
let _ = vk;
|
||||||
bits
|
bits
|
||||||
}
|
}
|
||||||
@@ -572,7 +573,7 @@ impl Decoder {
|
|||||||
/// Open a PyroWave decoder for a `CODEC_PYROWAVE` session (plan §4.5): pyrowave
|
/// Open a PyroWave decoder for a `CODEC_PYROWAVE` session (plan §4.5): pyrowave
|
||||||
/// compute on the presenter's device, no FFmpeg. `codec_id` is irrelevant (kept as
|
/// compute on the presenter's device, no FFmpeg. `codec_id` is irrelevant (kept as
|
||||||
/// HEVC so an — impossible — demotion path stays well-formed).
|
/// HEVC so an — impossible — demotion path stays well-formed).
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
pub fn new_pyrowave(
|
pub fn new_pyrowave(
|
||||||
vk: &VulkanDecodeDevice,
|
vk: &VulkanDecodeDevice,
|
||||||
width: u32,
|
width: u32,
|
||||||
@@ -596,6 +597,15 @@ impl Decoder {
|
|||||||
vaapi_fails: 0,
|
vaapi_fails: 0,
|
||||||
first_fail: None,
|
first_fail: None,
|
||||||
want_keyframe: false,
|
want_keyframe: false,
|
||||||
|
// A PyroWave session never demotes (nothing else decodes it — a failure
|
||||||
|
// renegotiates the codec instead), so the D3D11VA rebuild facts are unused
|
||||||
|
// here; keep them well-formed rather than plumbing them in for nothing.
|
||||||
|
#[cfg(windows)]
|
||||||
|
d3d11_import: false,
|
||||||
|
#[cfg(windows)]
|
||||||
|
adapter_luid: None,
|
||||||
|
#[cfg(windows)]
|
||||||
|
d3d11_hdr10: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +649,7 @@ impl Decoder {
|
|||||||
au: &[u8],
|
au: &[u8],
|
||||||
// Only the PyroWave backend reads the flags; without that feature the param is unused.
|
// Only the PyroWave backend reads the flags; without that feature the param is unused.
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
not(all(target_os = "linux", feature = "pyrowave")),
|
not(all(any(target_os = "linux", windows), feature = "pyrowave")),
|
||||||
allow(unused_variables)
|
allow(unused_variables)
|
||||||
)]
|
)]
|
||||||
user_flags: u32,
|
user_flags: u32,
|
||||||
@@ -657,7 +667,7 @@ impl Decoder {
|
|||||||
// No demote ladder below PyroWave (nothing else decodes it): propagate the
|
// No demote ladder below PyroWave (nothing else decodes it): propagate the
|
||||||
// error; the pump surfaces it and the session falls back to HEVC by
|
// error; the pump surfaces it and the session falls back to HEVC by
|
||||||
// renegotiation (plan §4.6), not by decoder swap.
|
// renegotiation (plan §4.6), not by decoder swap.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
Backend::PyroWave(p) => {
|
Backend::PyroWave(p) => {
|
||||||
let aligned = user_flags & punktfunk_core::packet::USER_FLAG_CHUNK_ALIGNED != 0;
|
let aligned = user_flags & punktfunk_core::packet::USER_FLAG_CHUNK_ALIGNED != 0;
|
||||||
return Ok(p
|
return Ok(p
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ struct StreamState {
|
|||||||
/// PyroWave present has no demote rung (nothing else decodes the codec), so a
|
/// PyroWave present has no demote rung (nothing else decodes the codec), so a
|
||||||
/// persistent non-device-lost present failure would warn on every frame. Latch it:
|
/// persistent non-device-lost present failure would warn on every frame. Latch it:
|
||||||
/// warn on the first failure of a streak, then stay quiet until a present succeeds.
|
/// warn on the first failure of a streak, then stay quiet until a present succeeds.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
pyro_present_warned: bool,
|
pyro_present_warned: bool,
|
||||||
hw_fails: u32,
|
hw_fails: u32,
|
||||||
/// The OSD's text (multi-line; rebuilt each Stats window and on a live tier cycle).
|
/// The OSD's text (multi-line; rebuilt each Stats window and on a live tier cycle).
|
||||||
@@ -267,7 +267,7 @@ impl StreamState {
|
|||||||
win_start: Instant::now(),
|
win_start: Instant::now(),
|
||||||
presented: PresentedWindow::default(),
|
presented: PresentedWindow::default(),
|
||||||
dmabuf_demoted: false,
|
dmabuf_demoted: false,
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
pyro_present_warned: false,
|
pyro_present_warned: false,
|
||||||
hw_fails: 0,
|
hw_fails: 0,
|
||||||
osd_text: String::new(),
|
osd_text: String::new(),
|
||||||
@@ -1007,7 +1007,7 @@ fn run_inner(mut opts: SessionOpts, mut mode: ModeCtl) -> Result<Option<Outcome>
|
|||||||
// PyroWave planar frames: already on the presenter's device and
|
// PyroWave planar frames: already on the presenter's device and
|
||||||
// fence-complete — a present failure has no demote rung (nothing
|
// fence-complete — a present failure has no demote rung (nothing
|
||||||
// else decodes the codec); only device loss ends the session.
|
// else decodes the codec); only device loss ends the session.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
DecodedImage::PyroWave(f) => {
|
DecodedImage::PyroWave(f) => {
|
||||||
// The wavelet stream carries the negotiated ColorInfo (no VUI): an
|
// The wavelet stream carries the negotiated ColorInfo (no VUI): an
|
||||||
// HDR (PQ) pyrowave session presents through the HDR10 path exactly
|
// HDR (PQ) pyrowave session presents through the HDR10 path exactly
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ pub enum FrameInput<'a> {
|
|||||||
D3d11(pf_client_core::video::D3d11Frame),
|
D3d11(pf_client_core::video::D3d11Frame),
|
||||||
/// PyroWave planar output — three R8 plane views already on THIS device, decode
|
/// PyroWave planar output — three R8 plane views already on THIS device, decode
|
||||||
/// fence-complete, GENERAL layout (`pf_client_core::video_pyrowave`).
|
/// fence-complete, GENERAL layout (`pf_client_core::video_pyrowave`).
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
PyroWave(pf_client_core::video_pyrowave::PyroWavePlanarFrame),
|
PyroWave(pf_client_core::video_pyrowave::PyroWavePlanarFrame),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ pub struct Presenter {
|
|||||||
csc: CscPass,
|
csc: CscPass,
|
||||||
/// The planar (3-plane) CSC variant for PyroWave frames; built only when the device
|
/// The planar (3-plane) CSC variant for PyroWave frames; built only when the device
|
||||||
/// passed the pyrowave probe.
|
/// passed the pyrowave probe.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
csc_planar: Option<CscPass>,
|
csc_planar: Option<CscPass>,
|
||||||
/// FFmpeg Vulkan Video decode handles — `None` when the stack can't do it.
|
/// FFmpeg Vulkan Video decode handles — `None` when the stack can't do it.
|
||||||
video_export: Option<pf_client_core::video::VulkanDecodeDevice>,
|
video_export: Option<pf_client_core::video::VulkanDecodeDevice>,
|
||||||
@@ -304,7 +304,7 @@ impl Drop for Presenter {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
self.hw.take();
|
self.hw.take();
|
||||||
self.csc.destroy(&self.device);
|
self.csc.destroy(&self.device);
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if let Some(p) = &self.csc_planar {
|
if let Some(p) = &self.csc_planar {
|
||||||
p.destroy(&self.device);
|
p.destroy(&self.device);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ impl Presenter {
|
|||||||
FrameInput::VkFrame(v) => Some(v.color.is_pq()),
|
FrameInput::VkFrame(v) => Some(v.color.is_pq()),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
FrameInput::D3d11(d) => Some(d.color.is_pq()),
|
FrameInput::D3d11(d) => Some(d.color.is_pq()),
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
FrameInput::PyroWave(f) => Some(f.color.is_pq()),
|
FrameInput::PyroWave(f) => Some(f.color.is_pq()),
|
||||||
};
|
};
|
||||||
if let Some(pq) = frame_pq {
|
if let Some(pq) = frame_pq {
|
||||||
@@ -68,7 +68,7 @@ impl Presenter {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let mut win_frame: Option<crate::d3d11::HwFrame> = None;
|
let mut win_frame: Option<crate::d3d11::HwFrame> = None;
|
||||||
let mut vk_frame: Option<(VkVideoFrame, [vk::ImageView; 2])> = None;
|
let mut vk_frame: Option<(VkVideoFrame, [vk::ImageView; 2])> = None;
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
let mut pyro_frame: Option<pf_client_core::video_pyrowave::PyroWavePlanarFrame> = None;
|
let mut pyro_frame: Option<pf_client_core::video_pyrowave::PyroWavePlanarFrame> = None;
|
||||||
let cpu_frame = match input {
|
let cpu_frame = match input {
|
||||||
FrameInput::Redraw => None,
|
FrameInput::Redraw => None,
|
||||||
@@ -96,7 +96,7 @@ impl Presenter {
|
|||||||
vk_frame = Some((v, views));
|
vk_frame = Some((v, views));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
FrameInput::PyroWave(f) => {
|
FrameInput::PyroWave(f) => {
|
||||||
pyro_frame = Some(f);
|
pyro_frame = Some(f);
|
||||||
None
|
None
|
||||||
@@ -155,7 +155,7 @@ impl Presenter {
|
|||||||
}
|
}
|
||||||
self.csc.bind_planes(&self.device, views[0], views[1]);
|
self.csc.bind_planes(&self.device, views[0], views[1]);
|
||||||
}
|
}
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if let Some(f) = &pyro_frame {
|
if let Some(f) = &pyro_frame {
|
||||||
if self
|
if self
|
||||||
.video
|
.video
|
||||||
@@ -317,7 +317,7 @@ impl Presenter {
|
|||||||
// PyroWave frame: the planes are already on THIS device, decode
|
// PyroWave frame: the planes are already on THIS device, decode
|
||||||
// fence-complete and barriered to fragment sampling (GENERAL) by the
|
// fence-complete and barriered to fragment sampling (GENERAL) by the
|
||||||
// decoder — no acquire needed, just the planar CSC pass.
|
// decoder — no acquire needed, just the planar CSC pass.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if let (Some(f), Some(v)) = (&pyro_frame, &self.video) {
|
if let (Some(f), Some(v)) = (&pyro_frame, &self.video) {
|
||||||
let extent = vk::Extent2D {
|
let extent = vk::Extent2D {
|
||||||
width: v.width,
|
width: v.width,
|
||||||
@@ -695,7 +695,7 @@ impl Presenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// [`record_csc`] over the planar (PyroWave) pass — always 8-bit, no MSB packing.
|
/// [`record_csc`] over the planar (PyroWave) pass — always 8-bit, no MSB packing.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
unsafe fn record_csc_planar(
|
unsafe fn record_csc_planar(
|
||||||
&self,
|
&self,
|
||||||
framebuffer: vk::Framebuffer,
|
framebuffer: vk::Framebuffer,
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ impl Presenter {
|
|||||||
// The planar (PyroWave) pass renders to the same intermediate — rebuild it at the
|
// The planar (PyroWave) pass renders to the same intermediate — rebuild it at the
|
||||||
// new format too (an HDR pyrowave session needs the 10-bit intermediate exactly
|
// new format too (an HDR pyrowave session needs the 10-bit intermediate exactly
|
||||||
// like the H.26x path; 8-bit PQ bands visibly).
|
// like the H.26x path; 8-bit PQ bands visibly).
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
if let Some(p) = self.csc_planar.take() {
|
if let Some(p) = self.csc_planar.take() {
|
||||||
p.destroy(&self.device);
|
p.destroy(&self.device);
|
||||||
self.csc_planar = Some(CscPass::new_planar(&self.device, self.video_format)?);
|
self.csc_planar = Some(CscPass::new_planar(&self.device, self.video_format)?);
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ impl Presenter {
|
|||||||
let csc = CscPass::new(&device, vk::Format::R8G8B8A8_UNORM)?;
|
let csc = CscPass::new(&device, vk::Format::R8G8B8A8_UNORM)?;
|
||||||
// Starts SDR like `csc`; an HDR (PQ) pyrowave session rebuilds it at the 10-bit
|
// Starts SDR like `csc`; an HDR (PQ) pyrowave session rebuilds it at the 10-bit
|
||||||
// intermediate via `set_hdr_mode`, exactly like the H.26x pass.
|
// intermediate via `set_hdr_mode`, exactly like the H.26x pass.
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
let csc_planar = if pyrowave_ok {
|
let csc_planar = if pyrowave_ok {
|
||||||
Some(CscPass::new_planar(&device, vk::Format::R8G8B8A8_UNORM)?)
|
Some(CscPass::new_planar(&device, vk::Format::R8G8B8A8_UNORM)?)
|
||||||
} else {
|
} else {
|
||||||
@@ -463,7 +463,7 @@ impl Presenter {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
hw_win,
|
hw_win,
|
||||||
csc,
|
csc,
|
||||||
#[cfg(all(target_os = "linux", feature = "pyrowave"))]
|
#[cfg(all(any(target_os = "linux", windows), feature = "pyrowave"))]
|
||||||
csc_planar,
|
csc_planar,
|
||||||
video_export,
|
video_export,
|
||||||
overlay_pipe,
|
overlay_pipe,
|
||||||
|
|||||||
Reference in New Issue
Block a user