feat(clients/windows): port the Vulkan session client to Windows — session-always
The punktfunk-session Vulkan client (clients/linux-session, now clients/session) builds and runs on Windows; the WinUI shell spawns it for every stream. Verified live: 10-bit HEVC via Vulkan Video on both AMD (iGPU) and NVIDIA, 5120x1440 at 130 fps / 8 ms end-to-end on the RTX 4090. - pf-ffvk: Windows bindgen branch (FFMPEG_DIR + PF_FFVK_VULKAN_INCLUDE, no pkg-config); provisioning fetches Vulkan-Headers (pinned v1.4.309). - pf-client-core: builds on Windows — WASAPI audio (audio_wasapi.rs, cfg-swapped via #[path], same surface as the PipeWire twin), VAAPI/dmabuf gated inline (chain = vulkan -> software), trust reads the WinUI shell's %APPDATA% stores (parity tests pin both serialized shapes), Settings gains adapter/hdr_enabled (serde-defaulted; Linux stores unaffected). - pf-presenter: builds on Windows — dmabuf module Linux-gated; SDL keyboard grab while captured (Alt+Tab/Win reach the host); pick_device ranks discrete over integrated (device 0 was the iGPU on hybrid boxes — the silent footgun) and honors PUNKTFUNK_VK_ADAPTER (the Settings GPU pick, exported by the session). - run loop: block in one SDL wait woken by input AND decoded frames (a per- session forwarder pushes a FrameWake user event) instead of a 1 ms poll — measured 111%% -> 5%% of a core (NVIDIA), 86%% -> 3.5%% (AMD), stats unchanged. The pump's decode-fence wait became once-per-window sampling (no per-frame pipeline stall; the stat now shows true backlog). - pf-console-ui: builds on Windows (skia-safe msvc prebuilts); font lookup falls through fontconfig aliases to concrete DirectWrite families (Consolas/Segoe UI) — browse/coverflow works, verified against a live host. - WinUI shell: session-always via new src/spawn.rs (GTK spawn.rs port — CREATE_NO_WINDOW, stdout contract, kill handle); the Stream screen is a status card (chips + stage lines from the child's stats). The legacy in-process D3D11VA path stays behind Settings "Streaming engine" / PUNKTFUNK_BUILTIN_ STREAM=1 as the A/B baseline until Phase 8 deletes it. SessionParams.video_caps makes the HDR toggle real. - clients/linux-session renamed to clients/session (builds for both OSes). - CI/MSIX: both workflows build/test both bins with widened path filters; the MSIX ships punktfunk-session.exe. ARM64 session builds --no-default-features (rust-skia has no aarch64-pc-windows-msvc prebuilts; flip when it does). A/B on this box (5120x1440 HEVC vs home-worker-5): NVIDIA Vulkan 130 fps / 8 ms e2e / 1.6 ms decode — clearly better than the built-in path. The AMD iGPU VCN saturates at ~52 fps where its own D3D11VA does ~70 — Adrenalin Vulkan decode is slower on APU silicon; discrete RDNA validation gates Phase 8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,11 +19,18 @@ const RESOLUTIONS: &[(u32, u32)] = &[
|
||||
/// `0` = the display's native refresh, resolved at connect.
|
||||
const REFRESH: &[u32] = &[0, 30, 60, 90, 120, 144, 165, 240];
|
||||
/// Decode backend presets: `(stored value, display label)`.
|
||||
// A stored legacy "hardware" (the D3D11VA era) matches no preset, so the combo shows
|
||||
// Automatic — which is exactly how the session's decoder chain reads that value.
|
||||
const DECODERS: &[(&str, &str)] = &[
|
||||
("auto", "Automatic (GPU, fall back to CPU)"),
|
||||
("hardware", "Hardware (GPU / D3D11VA)"),
|
||||
("vulkan", "Hardware (GPU / Vulkan Video)"),
|
||||
("software", "Software (CPU)"),
|
||||
];
|
||||
/// Temporary A/B knob (see `Settings::engine`) — deleted with the legacy path.
|
||||
const ENGINES: &[(&str, &str)] = &[
|
||||
("", "Vulkan session window (recommended)"),
|
||||
("builtin", "Built-in D3D11VA (legacy)"),
|
||||
];
|
||||
/// Audio channel presets: `(channel count, display label)`. The host clamps to what it can
|
||||
/// capture; the resolved count drives the decoder + WASAPI render layout.
|
||||
const AUDIO_CHANNELS: &[(u8, &str)] = &[(2, "Stereo"), (6, "5.1 Surround"), (8, "7.1 Surround")];
|
||||
@@ -182,8 +189,8 @@ pub(crate) fn settings_page(
|
||||
s.decoder = DECODERS[i].0.to_string();
|
||||
})
|
||||
.tooltip(
|
||||
"Hardware decode (D3D11VA) is far lighter than software \u{2014} keep it on Automatic \
|
||||
unless debugging.",
|
||||
"Hardware decode (Vulkan Video) is far lighter than software \u{2014} keep it on \
|
||||
Automatic unless debugging.",
|
||||
);
|
||||
// GPU picker, only on a multi-GPU box (hybrid laptop, eGPU): which adapter decodes + presents.
|
||||
// Stored as the adapter description; empty = automatic (the window's monitor's adapter).
|
||||
@@ -239,6 +246,15 @@ pub(crate) fn settings_page(
|
||||
"Advertise 10-bit HDR10 so the host upgrades HDR content. Needs a display in HDR mode; \
|
||||
SDR content is unaffected.",
|
||||
);
|
||||
let (eng_names, eng_i) = presets(ENGINES, |v| *v == s.engine);
|
||||
let engine_combo = setting_combo(ctx, "Streaming engine", eng_names, eng_i, |s, i| {
|
||||
s.engine = ENGINES[i].0.to_string();
|
||||
})
|
||||
.tooltip(
|
||||
"Temporary: compare the Vulkan session window against the legacy in-process \
|
||||
D3D11VA presenter. Applies to the next stream. This option goes away once the \
|
||||
Vulkan path is fully validated.",
|
||||
);
|
||||
|
||||
// --- Input -----------------------------------------------------------------------------
|
||||
// Which physical controller forwards as pad 0: automatic = the most recently connected;
|
||||
@@ -340,6 +356,7 @@ pub(crate) fn settings_page(
|
||||
bitrate_box.into(),
|
||||
hdr_toggle.into(),
|
||||
hud_toggle.into(),
|
||||
engine_combo.into(),
|
||||
]);
|
||||
controls
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user