refactor(host/W6.2): extract virtual-display orchestration into the pf-vdisplay crate

vdisplay.rs + vdisplay/* (the per-compositor Linux backends — KWin zkde-screencast,
wlroots swaymsg, Mutter RemoteDesktop, Hyprland — and the Windows IddCx/pf-vdisplay
driver backend, behind one VirtualDisplay trait; the mode-conflict admission
registry, the display policy/identity/custom-preset state, and the session-env /
gamescope routing) move into crates/pf-vdisplay (plan §W6). The DDC/CI panel-power
control (used only here) and the KWin zkde protocol XML move with it. This
completes the host-crate decomposition: capture, encode, inject, and vdisplay are
now four subsystem crates over the shared leaves, and punktfunk-host is the
orchestrator (serve/supervisor + native + gamestream + mgmt).

Coupling breaks (all down-only, cargo-tree acyclic):
- capture::dxgi identity -> pf_frame::dxgi; win_display/monitor_devnode/
  console_session_mismatch -> pf-win-display leaf; can_open_another_session ->
  pf-encode (the NVENC session-budget admission gate — acyclic peer edge).
- The registry's DisplayCreated/DisplayReleased emits into the host SSE event bus
  invert to a leaf hook: pf-vdisplay emits a neutral DisplayEvent to a
  host-registered DISPLAY_EVENT_SINK, so it never reaches the orchestrator's
  events module.
- The IddCx driver module is renamed pf_vdisplay -> driver (its old name collided
  with the crate name through the host's `mod vdisplay` shim glob).

The host keeps `mod vdisplay { pub use pf_vdisplay::* }` so every crate::vdisplay::*
path (serve/mgmt/native/the capture FrameChannelSender seam) is unchanged; the
heavy deps (wayland/ashpd/tokio + the zkde protocol) moved with the crate.
Co-authored: a fail-closed IOCTL-reply-length security fix (reject short/zeroed
pf-vdisplay driver replies before trusting protocol_version/target_id/wudf_pid/luid,
security-review 2026-07-17) rides this commit in the moved driver module.

Verified: Linux clippy -D warnings (pf-vdisplay + host nvenc,vulkan-encode,pyrowave
--all-targets) + pf-vdisplay 63/63 + host 167/167 tests; Windows clippy -D warnings
(pf-vdisplay --all-targets + host nvenc,amf-qsv --all-targets) Finished exit 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 12:14:08 +02:00
parent f6c6e4e594
commit 27a5d8daac
29 changed files with 291 additions and 122 deletions
+26 -9
View File
@@ -29,9 +29,6 @@ mod wol;
#[cfg(target_os = "windows")]
#[path = "windows/crash.rs"]
mod crash;
#[cfg(target_os = "windows")]
#[path = "windows/ddc.rs"]
mod ddc;
#[cfg(target_os = "linux")]
#[path = "linux/drm_sync.rs"]
mod drm_sync;
@@ -76,13 +73,16 @@ mod session_status;
mod spike;
mod stats_recorder;
mod stream_marker;
mod vdisplay;
// The Windows display-topology cluster (CCD/GDI mode-set + PnP monitor devnodes) lives in the
// `pf-win-display` leaf crate (plan §W6); import the modules at the crate root so the host's
// `crate::{win_display,monitor_devnode}::*` paths stay valid. (`display_events` moved with the
// IDD-push capturer into pf-capture, which names it directly.)
// `monitor_devnode::startup_recover()` (below) re-enables PnP monitor devnodes disabled by a prior
// run; it lives in the `pf-win-display` leaf crate (plan §W6).
#[cfg(target_os = "windows")]
use pf_win_display::{monitor_devnode, win_display};
use pf_win_display::monitor_devnode;
// Virtual-display orchestration lives in the `pf-vdisplay` subsystem crate (plan §W6); this shim
// keeps every existing `crate::vdisplay::*` path valid (serve/mgmt/native/capture consume the trait,
// registry, and manager through it). The DDC panel control + the KWin zkde protocol moved with it.
mod vdisplay {
pub(crate) use pf_vdisplay::*;
}
// The zero-copy GPU plumbing lives in the `pf-zerocopy` leaf crate (plan §W6); this shim keeps
// every existing `crate::zerocopy::*` path valid for the host's remaining callers (session_plan).
#[cfg(target_os = "linux")]
@@ -183,6 +183,23 @@ fn real_main() -> Result<()> {
punktfunk_core::ABI_VERSION
);
// Wire pf-vdisplay's display-lifecycle events into the SSE event bus (the subsystem crate emits a
// neutral DisplayEvent; the orchestrator owns the bus type — plan §W6). Set once, ignore re-set.
let _ = pf_vdisplay::DISPLAY_EVENT_SINK.set(Box::new(|ev| match ev {
pf_vdisplay::DisplayEvent::Created {
backend,
width,
height,
refresh_hz,
} => events::emit(events::EventKind::DisplayCreated {
backend,
mode: events::mode_str(width, height, refresh_hz),
}),
pf_vdisplay::DisplayEvent::Released { count } => {
events::emit(events::EventKind::DisplayReleased { count })
}
}));
// Install the win32u GPU-preference hook (same technique as Apollo, reimplemented — no GPL source
// copied) BEFORE anything touches DXGI (the virtual-display
// render-adapter selection creates a DXGI factory during virtual-display setup, well before