Merge perf/first-frame-latency: driver proto v4 + first-frame/resize latency (P0-P2)

Brings the first-frame-latency branch (P0.1 transition tracing, P1.1/P1.2
Welcome-time display prep, P2 in-place resize; pf-driver-proto v3 -> v4 with
IOCTL_UPDATE_MODES) onto current main. The branch predates the W6.2/W7 splits,
so git's rename detection carried most of it into the moved crates
(pf-capture idd_push, pf-vdisplay manager/pf_vdisplay, pf-win-display,
pf-driver-proto, the driver workspace) and the punktfunk1.rs remainder was
re-homed by hand:

- native/handshake.rs: welcome/start trace marks + the Welcome-time display
  prep spawn (the prep thread BECOMES the stream thread; hand-off via a
  SyncSender<SessionContext>). negotiate() gains bringup/quit/stop and returns
  the PrepHandle.
- native.rs: bringup/resize_ms creation + the stop/quit flags hoisted BEFORE
  the handshake (the close watcher splits: flags pre-handshake, lifecycle
  events post-handshake where `hello` exists); punch_done stamp; the data
  plane adopts the prep thread's result or builds inline.
- native/stream.rs: SessionContext/SendStats carry the trace; send_loop
  finishes it on the first video packet; the resize path gains the in-place
  fast path (try_inplace_resize) with the full rebuild as fallback, restructured
  so both share the post-rebuild bookkeeping; prepare_display/PreparedDisplay/
  PrepHandle; build_pipeline(+retry) thread the stage marks.
- session_status/mgmt: ttff_ms + last_resize_ms per session (union with the
  lifecycle-events fields main added to the same spots).
- pf-capture: Capturer gains capture_target_id() + resize_output() defaults.
- pf-vdisplay manager: perf's faster activation poll (60x50ms) + the settle
  floor before the PnP sweep, on main's knobs/no-trait shape.

Also: packaging/windows/build-gamepad-drivers.ps1 is ASCII again (an em-dash
from the pf-mouse work tripped windows-host.yml's locale-safety gate on main).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-17 16:08:16 +02:00
19 changed files with 1544 additions and 172 deletions
@@ -35,7 +35,8 @@ use windows::Win32::System::Threading::{
use super::{DisplayOwnership, Mode, VirtualOutput};
use pf_win_display::win_display::{
count_other_active, force_extend_topology, isolate_displays_ccd, resolve_gdi_name,
restore_displays_ccd, set_active_mode, set_virtual_primary_ccd, SavedConfig,
restore_displays_ccd, set_active_mode, set_virtual_primary_ccd, wait_mode_settled,
wait_target_departed, SavedConfig,
};
#[path = "manager/driver.rs"]
@@ -204,6 +205,16 @@ pub struct VirtualDisplayManager {
/// `&'static` singleton with no raw-handle smuggling.
device: Mutex<DeviceSlot>,
watchdog_s: AtomicU32,
/// The driver's handshake-reported protocol version (0 until the first open). The in-place
/// resize (latency plan P2) gates its UPDATE_MODES attempt on `>= 4`; a v3 driver keeps the
/// already-advertised fast path + the re-arrival fallback.
driver_proto: AtomicU32,
/// Latched `true` after an UPDATE_MODES round-trip failed to make the new mode settable —
/// on-glass (build 26200) the OS pins a monitor's settable set at ARRIVAL (it re-parses our
/// description + re-queries target modes, then ignores both), so every further attempt for an
/// out-of-arrival-list mode would only waste ~1 s per resize before the same re-arrival
/// fallback. One attempt per process, in case a future OS build honors the refresh.
update_modes_futile: AtomicBool,
/// Monotonic lease-generation counter (was the `MON_GEN` global).
gen: AtomicU64,
state: Mutex<MgrInner>,
@@ -234,6 +245,8 @@ pub(crate) fn init(driver: Box<dyn VdisplayDriver>) -> &'static VirtualDisplayMa
driver,
device: Mutex::new(DeviceSlot::default()),
watchdog_s: AtomicU32::new(3),
driver_proto: AtomicU32::new(0),
update_modes_futile: AtomicBool::new(false),
gen: AtomicU64::new(1),
state: Mutex::new(MgrInner::default()),
setup_lock: Mutex::new(()),
@@ -321,9 +334,10 @@ impl VirtualDisplayManager {
// FFI in the caller's apartment; the `device` mutex (held here) serializes it, so there is no
// concurrent open. `open` has no handle precondition to uphold, and the `OwnedHandle` it
// returns is the sole owner of the device.
let (handle, watchdog_s) = unsafe { self.driver.open(reap)? };
let (handle, watchdog_s, driver_proto) = unsafe { self.driver.open(reap)? };
slot.opened_once = true;
self.watchdog_s.store(watchdog_s, Ordering::Relaxed);
self.driver_proto.store(driver_proto, Ordering::Relaxed);
let raw = HANDLE(handle.as_raw_handle());
slot.current = Some(Arc::new(handle));
if !reap {
@@ -418,9 +432,10 @@ impl VirtualDisplayManager {
if let Some(SlotState::Lingering { mon, .. } | SlotState::Pinned { mon }) =
inner.slots.remove(&slot)
{
let old_target = mon.target_id;
tracing::info!(
slot,
old_target = mon.target_id,
old_target,
"IDD-push reconnect — preempting the kept (lingering/pinned) monitor, recreating a fresh one"
);
// SAFETY: `teardown_removed` requires `dev` to be a valid control handle; `dev` is the
@@ -430,7 +445,16 @@ impl VirtualDisplayManager {
unsafe { self.teardown_removed(dev, &mut inner, mon) };
// Let the OS finish the ASYNC monitor departure before the next ADD; a back-to-back
// REMOVE→ADD races the teardown and the ADD IOCTL is rejected under reconnect churn.
thread::sleep(Duration::from_millis(400));
// Verified-state wait, ceiling = the old fixed 400 ms settle (latency plan P0.3).
// SAFETY: CCD query FFI over a `Copy` target id, under the held `state` lock.
let departed =
unsafe { wait_target_departed(old_target, Duration::from_millis(400)) };
if !departed {
tracing::debug!(
old_target,
"preempted monitor still in the active CCD set after the departure ceiling"
);
}
}
}
@@ -446,9 +470,10 @@ impl VirtualDisplayManager {
if matches!(inner.slots.get(&slot), Some(SlotState::Active { mon, .. }) if !wudf_alive(mon.wudf_pid))
{
if let Some(SlotState::Active { mon, .. }) = inner.slots.remove(&slot) {
let old_target = mon.target_id;
tracing::warn!(
slot,
old_target = mon.target_id,
old_target,
wudf_pid = mon.wudf_pid,
"virtual monitor's WUDFHost is gone — preempting the dead monitor, recreating"
);
@@ -457,8 +482,9 @@ impl VirtualDisplayManager {
// retired, kept alive; see `DeviceSlot`). `mon` was just removed from the map, so it
// is exclusively owned here — no aliasing.
unsafe { self.teardown_removed(dev, &mut inner, mon) };
// Same async-departure settle as the reconnect preempt above.
thread::sleep(Duration::from_millis(400));
// Same async-departure settle as the reconnect preempt above (verified wait, P0.3).
// SAFETY: CCD query FFI over a `Copy` target id, under the held `state` lock.
let _ = unsafe { wait_target_departed(old_target, Duration::from_millis(400)) };
}
}
@@ -475,6 +501,57 @@ impl VirtualDisplayManager {
_ => unreachable!("just matched Active"),
};
if cur_mode != mode {
// IN-PLACE mode set first (latency plan P2): an already-advertised resolution
// (arrival list + the driver's same-id mode history) is CCD-forced on the SAME
// monitor — no REMOVE→ADD, so the monitor's OS identity (saved per-monitor DPI),
// the driver-side swap-chain machinery and the retained frame stash all survive,
// and the whole hotplug cost (departure settle + activation ladder + re-isolate)
// disappears. An out-of-list mode fails FAST (see `resize_in_place`) and falls
// through to the proven re-arrival below.
{
let in_place = {
let Some(SlotState::Active { mon, refs }) = inner.slots.get_mut(&slot)
else {
unreachable!("just matched Active");
};
// SAFETY: `dev` is the handle `ensure_device()` returned above; the CCD
// waits inside run under the held `state` lock (this fn's discipline).
match unsafe { self.resize_in_place(dev, mon, mode) } {
Ok(()) => {
// Same join semantics as the re-arrival: +1 ref for the new
// (build-then-drop overlap) lease; `gen` untouched, so the old
// session's lease stays valid.
*refs += 1;
let refs = *refs;
let out = self.output_for(slot, mon, quit.clone());
tracing::info!(
slot,
refs,
backend = self.driver.name(),
"virtual monitor resized IN PLACE (identity + swap-chain kept)"
);
Some(out)
}
Err(e) => {
// Expected-normal for a first-seen arbitrary size (the OS pins
// settable modes at arrival; the re-arrival teaches it) — info,
// not warn.
tracing::info!(
slot,
reason = %format!("{e:#}"),
"in-place resize not possible — monitor re-arrival"
);
None
}
}
};
if let Some(out) = in_place {
// The width changed — re-arrange the group so auto-row siblings don't
// overlap the resized display (no-op for a single member).
self.apply_group_layout(&mut inner);
return Ok(out);
}
}
let Some(SlotState::Active { mon, refs }) = inner.slots.remove(&slot) else {
unreachable!("just matched Active");
};
@@ -736,8 +813,12 @@ impl VirtualDisplayManager {
/// # Safety
/// Runs the CCD (QueryDisplayConfig / SetDisplayConfig) FFI; call under the `state` lock.
unsafe fn resolve_target_gdi(&self, target_id: u32) -> Option<String> {
for _ in 0..15 {
thread::sleep(Duration::from_millis(200));
// 50 ms sampling (latency plan P0.5): the SAME 3 s per-stage ceilings — the 3-stage ladder
// structure encodes real failure modes (headless auto-activate, integrated-panel clone,
// lid-closed path activation) and is untouched — but a typical activation resolves on an
// early poll, so finer sampling shaves ~150 ms off every stage crossing.
for _ in 0..60 {
thread::sleep(Duration::from_millis(50));
// SAFETY: `resolve_gdi_name` is `unsafe` for its CCD FFI; it takes a plain `Copy` `u32`
// target id by value and returns an owned `String`, so no caller memory is borrowed.
if let Some(n) = unsafe { resolve_gdi_name(target_id) } {
@@ -746,8 +827,8 @@ impl VirtualDisplayManager {
}
// SAFETY: `force_extend_topology` only calls `SetDisplayConfig` (CCD) with no borrowed memory.
unsafe { force_extend_topology() };
for _ in 0..15 {
thread::sleep(Duration::from_millis(200));
for _ in 0..60 {
thread::sleep(Duration::from_millis(50));
// SAFETY: as the resolve loop above.
if let Some(n) = unsafe { resolve_gdi_name(target_id) } {
return Some(n);
@@ -756,8 +837,8 @@ impl VirtualDisplayManager {
// SAFETY: `activate_target_path` runs the CCD query/apply FFI with owned local buffers; the
// `Copy` target id is passed by value, under the `state` lock — the sole topology mutator.
if unsafe { pf_win_display::win_display::activate_target_path(target_id) } {
for _ in 0..15 {
thread::sleep(Duration::from_millis(200));
for _ in 0..60 {
thread::sleep(Duration::from_millis(50));
// SAFETY: as the resolve loops above.
if let Some(n) = unsafe { resolve_gdi_name(target_id) } {
return Some(n);
@@ -919,19 +1000,40 @@ impl VirtualDisplayManager {
);
}
}
thread::sleep(Duration::from_millis(1500)); // let the topology settle before capture opens
// Topology settle before capture opens: verified-state wait (latency plan P0.2) —
// poll until the target's path + active mode are committed, ceiling = the old fixed
// 1500 ms sleep (a rejected mode / slow third-party CCD-lock holder burns the
// ceiling and proceeds, exactly like the sleep it replaces).
let settle_start = std::time::Instant::now();
// SAFETY: CCD/GDI query FFI over a `Copy` target id, under the held `state` lock.
let settled = unsafe {
wait_mode_settled(added.target_id, mode, Duration::from_millis(1500))
};
tracing::info!(
settle_ms = settle_start.elapsed().as_millis() as u64,
verified = settled,
"topology settle (verified-state wait)"
);
// EXPERIMENTAL `pnp_disable_monitors`, second selector (ANY topology): monitors
// that are connected but NOT part of the desktop — the standby TV/monitor the
// deactivated-set selector above structurally misses (it never had an active path
// to deactivate), yet whose periodic standby wake events drive the same Windows
// reaction cascade (rationale in `windows/monitor_devnode.rs`). Runs AFTER the
// settle sleep so the active flags it reads are the committed ones (a display
// still mid-activation from the primary topology's force-EXTEND must not read as
// inactive and get disabled); in Extend the active physical panels are untouched
// by construction. First member only — the sweep is group-scoped like the
// isolate; later members join an already-swept desktop.
// settle so the active flags it reads are the committed ones (a display still
// mid-activation from the primary topology's force-EXTEND must not read as
// inactive and get disabled) — and since the verified wait above only confirms
// OUR target (not a physical still lighting up from force-EXTEND), this opt-in
// sweep keeps the old FULL settle as its floor before reading those flags.
// In Extend the active physical panels are untouched by construction. First
// member only — the sweep is group-scoped like the isolate; later members join
// an already-swept desktop.
if first_member && crate::policy::prefs().pnp_disable_monitors() {
if let Some(rest) =
Duration::from_millis(1500).checked_sub(settle_start.elapsed())
{
thread::sleep(rest);
}
let mut keep = inner.target_ids();
keep.push(added.target_id);
for id in pf_win_display::monitor_devnode::disable_connected_inactive(&keep) {
@@ -962,6 +1064,101 @@ impl VirtualDisplayManager {
})
}
/// Mid-stream resize IN PLACE (latency plan P2): the driver refreshes the LIVE monitor's
/// advertised target-mode list to lead with `mode` (`IOCTL_UPDATE_MODES` →
/// `IddCxMonitorUpdateModes2`, protocol v4), the OS re-enumerates the target's settable modes
/// (waited on, bounded), and the usual CCD/GDI force-set + verified settle (P0.2) commit it —
/// on the SAME monitor: target id, GDI name, saved per-monitor DPI, the driver's swap-chain
/// worker and its retained frame stash all survive (the OS reassigns the swap-chain across a
/// mode set; the preserved-publisher/stash hand-off covers that flap — what it was built for).
/// On success `mon.mode` is updated in place; any failure leaves `mon` untouched (still at the
/// old mode) and the caller falls back to [`re_add`](Self::re_add).
///
/// # Safety
/// `dev` must be the live control handle; runs the CCD/GDI FFI under the `state` lock.
unsafe fn resize_in_place(&self, dev: HANDLE, mon: &mut Monitor, mode: Mode) -> Result<()> {
let gdi = mon
.gdi_name
.clone()
.context("in-place resize needs a resolved GDI name")?;
let t0 = Instant::now();
// FAST PATH (driver-independent): the OS already offers this resolution — the monitor's
// arrival list, which since the driver's mode-history union contains every size this
// identity ever served — so a plain CCD mode set reaches it with no driver round-trip.
let already = crate::win_display::wait_mode_advertised(&gdi, mode, Duration::ZERO);
if !already {
// Out-of-arrival-list mode. On-glass (build 26200) the OS re-parses our description
// AND re-queries target modes after UpdateModes2 — our callbacks served the fresh
// list — yet the SETTABLE set stays pruned to the arrival list: the monitor
// source-mode set is pinned at arrival. So one bounded UPDATE_MODES attempt per
// process (in case a future build honors the refresh), then latch it futile and fail
// fast to the re-arrival — whose same-id history union makes THIS size settable in
// place from then on.
if self.driver_proto.load(Ordering::Relaxed) < 4 {
anyhow::bail!(
"{}x{} is not in the advertised mode set (v3 driver: in-place reaches only \
arrival-list modes)",
mode.width,
mode.height
);
}
if self.update_modes_futile.load(Ordering::Relaxed) {
anyhow::bail!(
"{}x{} is not in the advertised mode set (UPDATE_MODES latched futile — the \
OS pins settable modes at monitor arrival; the re-arrival teaches this size \
to the identity's history)",
mode.width,
mode.height
);
}
tracing::info!(
old = format!(
"{}x{}@{}",
mon.mode.width, mon.mode.height, mon.mode.refresh_hz
),
new = format!("{}x{}@{}", mode.width, mode.height, mode.refresh_hz),
target = mon.target_id,
"virtual-display: updating the live monitor's modes for an in-place resize"
);
// SAFETY: `dev` is the live control handle (this fn's contract); `update_modes`
// forwards it to a synchronous IOCTL with owned/borrowed locals only.
unsafe { self.driver.update_modes(dev, &mon.key, mode) }?;
// SAFETY: CCD query/apply FFI under the held `state` lock (this fn's contract).
unsafe { crate::win_display::force_mode_reenumeration() };
if !crate::win_display::wait_mode_advertised(&gdi, mode, Duration::from_millis(800)) {
self.update_modes_futile.store(true, Ordering::Relaxed);
anyhow::bail!(
"OS did not advertise {}x{} within {}ms of the driver mode-list update \
(offers: {:?}) — latching UPDATE_MODES off for this process",
mode.width,
mode.height,
t0.elapsed().as_millis(),
crate::win_display::advertised_resolutions(&gdi)
);
}
}
let advertised_ms = t0.elapsed().as_millis() as u64;
set_active_mode(&gdi, mode);
// Verified-state settle (P0.2): the same committed-state predicate as the create paths. A
// mode set that did not commit within the ceiling routes to the re-arrival fallback.
let settle_start = Instant::now();
// SAFETY: CCD/GDI query FFI over a `Copy` target id, under the held `state` lock.
let settled =
unsafe { wait_mode_settled(mon.target_id, mode, Duration::from_millis(1500)) };
if !settled {
anyhow::bail!(
"in-place mode set did not commit within 1.5s (advertised after {advertised_ms} ms)"
);
}
tracing::info!(
advertised_ms,
settle_ms = settle_start.elapsed().as_millis() as u64,
"in-place resize committed (verified-state wait)"
);
mon.mode = mode;
Ok(())
}
/// Mid-stream resize by monitor RE-ARRIVAL (`design/midstream-resolution-resize.md` Fix 1).
///
/// The pf-vdisplay driver freezes a monitor's advertised mode list at `IOCTL_ADD` time (the
@@ -1013,9 +1210,17 @@ impl VirtualDisplayManager {
);
}
// Let the OS finish the ASYNC monitor departure before the ADD — a back-to-back REMOVE→ADD
// races the teardown and the ADD is rejected under churn (same 400 ms settle as the reconnect
// preempt path).
thread::sleep(Duration::from_millis(400));
// races the teardown and the ADD is rejected under churn. Verified departure wait, ceiling =
// the old fixed 400 ms settle (latency plan P0.3); the driver's ghost-reap ADD retry remains
// the backstop for a departure the CCD reports early.
let depart_start = std::time::Instant::now();
// SAFETY: CCD query FFI over a `Copy` target id, under the held `state` lock.
let departed = unsafe { wait_target_departed(old.target_id, Duration::from_millis(400)) };
tracing::info!(
depart_ms = depart_start.elapsed().as_millis() as u64,
verified = departed,
"re-arrival: old monitor departure settle"
);
// 2. ADD a fresh monitor at the NEW mode, reusing the slot as the preferred (stable) id.
let render_pin = resolve_render_pin();
// SAFETY: `dev` is the live control handle; `render_pin`/`client_hdr` are owned `Copy`/`Option`
@@ -1042,7 +1247,18 @@ impl VirtualDisplayManager {
// the group's first-member restore snapshot.
// SAFETY: CCD FFI over borrowed Copy target ids, under the `state` lock.
unsafe { self.reisolate_after_swap(inner, added.target_id) };
thread::sleep(Duration::from_millis(1500)); // let the topology settle before capture reopens
// Topology settle before capture reopens: verified-state wait, ceiling = the old
// fixed 1500 ms sleep (latency plan P0.2 — the re-arrival twin).
let settle_start = std::time::Instant::now();
// SAFETY: CCD/GDI query FFI over a `Copy` target id, under the held `state` lock.
let settled = unsafe {
wait_mode_settled(added.target_id, mode, Duration::from_millis(1500))
};
tracing::info!(
settle_ms = settle_start.elapsed().as_millis() as u64,
verified = settled,
"re-arrival topology settle (verified-state wait)"
);
}
None => tracing::warn!(
"re-arrival target {} not yet an active display path (auto-activate, EXTEND preset \
@@ -341,7 +341,7 @@ impl VdisplayDriver for PfVdisplayDriver {
"pf-vdisplay"
}
unsafe fn open(&self, reap_orphans: bool) -> Result<(OwnedHandle, u32)> {
unsafe fn open(&self, reap_orphans: bool) -> Result<(OwnedHandle, u32, u32)> {
// SAFETY: `open_device` is `unsafe` only because it issues SetupAPI enumeration + `CreateFileW`
// FFI; it takes no arguments and returns an owned raw `HANDLE` (or `Err`). Called here on the
// backend-init thread, with no precondition beyond a valid thread context.
@@ -397,27 +397,43 @@ impl VdisplayDriver for PfVdisplayDriver {
}
let info: control::InfoReply =
bytemuck::pod_read_unaligned(&info_buf[..size_of::<control::InfoReply>()]);
if info.protocol_version != pf_driver_proto::PROTOCOL_VERSION {
// HARD floor/ceiling instead of strict equality since v4: v4 is ADDITIVE over v3
// (IOCTL_UPDATE_MODES — the in-place resize), so this host still drives a v3 driver and
// simply gates the in-place path on the reported version (re-arrival fallback). Anything
// below the floor or ABOVE this host's own version stays a loud failure.
if info.protocol_version < pf_driver_proto::MIN_DRIVER_PROTOCOL_VERSION
|| info.protocol_version > pf_driver_proto::PROTOCOL_VERSION
{
anyhow::bail!(
"pf-vdisplay protocol mismatch: host expects {}, driver reports {} — install matching \
host + driver",
"pf-vdisplay protocol mismatch: host drives {}..={}, driver reports {} — install \
matching host + driver",
pf_driver_proto::MIN_DRIVER_PROTOCOL_VERSION,
pf_driver_proto::PROTOCOL_VERSION,
info.protocol_version
);
}
let watchdog_s = info.watchdog_timeout_s.max(1);
tracing::info!(
"pf-vdisplay protocol {} (watchdog timeout {}s)",
info.protocol_version,
watchdog_s
);
if info.protocol_version < pf_driver_proto::PROTOCOL_VERSION {
tracing::warn!(
"pf-vdisplay protocol {} (host supports {}): driver lacks the in-place resize — \
mid-stream resizes use the monitor re-arrival path until the driver is updated",
info.protocol_version,
pf_driver_proto::PROTOCOL_VERSION
);
} else {
tracing::info!(
"pf-vdisplay protocol {} (watchdog timeout {}s)",
info.protocol_version,
watchdog_s
);
}
// Reap monitors orphaned by a crashed previous host — a FIRST-CLASS op (driver returns
// SUCCESS). FIRST open of the process only: a REOPEN (the manager retired a dead handle after
// a driver upgrade / WUDFHost restart) can race sessions that still believe they are live, and
// an unconditional CLEAR_ALL there would raze them.
if !reap_orphans {
reap_ghost_monitors();
return Ok((device, watchdog_s));
return Ok((device, watchdog_s, info.protocol_version));
}
let mut none: [u8; 0] = [];
// SAFETY: `raw` borrows the live `OwnedHandle` above. `IOCTL_CLEAR_ALL` has no input and no
@@ -434,7 +450,7 @@ impl VdisplayDriver for PfVdisplayDriver {
// monitor-slot budget — prevents the 0x80070490 slot-exhaustion wedge from carrying across
// restarts (the reason a restart's CLEAR_ALL alone never recovered it before).
reap_ghost_monitors();
Ok((device, watchdog_s))
Ok((device, watchdog_s, info.protocol_version))
}
unsafe fn add_monitor(
@@ -592,6 +608,38 @@ impl VdisplayDriver for PfVdisplayDriver {
})
}
unsafe fn update_modes(&self, dev: HANDLE, key: &MonitorKey, mode: Mode) -> Result<()> {
let MonitorKey::Session(session_id) = key else {
anyhow::bail!("pf-vdisplay: unexpected monitor key kind");
};
let req = control::UpdateModesRequest {
session_id: *session_id,
width: mode.width,
height: mode.height,
refresh_hz: mode.refresh_hz,
_reserved: 0,
};
let mut none: [u8; 0] = [];
// SAFETY: per `update_modes`'s contract `dev` is the live control handle. `bytes_of(&req)`
// borrows the local `UpdateModesRequest` for the duration of this synchronous call as the
// input bytes; `none` is empty, so there is no output buffer.
unsafe {
ioctl(
dev,
control::IOCTL_UPDATE_MODES,
bytemuck::bytes_of(&req),
&mut none,
)
}
.map(|_| ())
.with_context(|| {
format!(
"pf-vdisplay UPDATE_MODES {}x{}@{}",
mode.width, mode.height, mode.refresh_hz
)
})
}
unsafe fn remove_monitor(&self, dev: HANDLE, key: &MonitorKey) -> Result<()> {
let MonitorKey::Session(session_id) = key else {
anyhow::bail!("pf-vdisplay: unexpected monitor key kind");
@@ -740,4 +788,80 @@ mod tests {
thread::sleep(Duration::from_secs(3));
drop(vout); // triggers REMOVE + stops the pinger
}
/// Live in-place resize spike — skipped unless `PUNKTFUNK_PF_VDISPLAY_LIVE=1` (needs a v4
/// pf-vdisplay driver installed + the host service STOPPED, single-instance guard). Answers the
/// P2 open questions on real glass with no streaming client: create at one mode, then acquire
/// the SAME session's slot at a DIFFERENT mode — the manager's resize branch runs UPDATE_MODES
/// → mode-advertised wait → set_active_mode → verified settle. In-place success is visible as
/// the SAME OS target id on the second output (a re-arrival fallback mints a new one) plus the
/// committed active resolution; the test reports which path ran and asserts the mode landed.
#[test]
fn live_inplace_resize() {
if std::env::var("PUNKTFUNK_PF_VDISPLAY_LIVE").is_err() {
return;
}
// Live-run diagnostics: surface the manager/backend tracing (activation ladder, settle
// waits, UPDATE_MODES) on stdout — a bare test harness has no subscriber, which made the
// first on-glass run blind.
let _ = tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "debug".into()),
)
.try_init();
// Context probe: can this process see the CCD active-path set at all? (`None` = the query
// itself fails in this session/window-station — the whole ladder would be blind, and a
// "monitor never activated" verdict would be an artifact of the test context.)
// SAFETY: CCD query over an owned empty slice (test-only diagnostics).
let active0 = unsafe { crate::win_display::count_other_active(&[]) };
println!("spike: CCD active paths visible before create: {active0:?}");
let mut vd = PfVdisplayDisplay::new().expect("open pf-vdisplay");
let first = vd
.create(Mode {
width: 1920,
height: 1080,
refresh_hz: 60,
})
.expect("create virtual display");
let t1 = first
.win_capture
.as_ref()
.expect("no capture target")
.target_id;
thread::sleep(Duration::from_secs(2)); // let the activation/settle fully quiesce
// A deliberately arbitrary (window-drag-shaped) mode the ADD never advertised.
let t0 = std::time::Instant::now();
let second = vd
.create(Mode {
width: 2356,
height: 1332,
refresh_hz: 60,
})
.expect("in-place resize acquire");
let resize_ms = t0.elapsed().as_millis();
let t2 = second
.win_capture
.as_ref()
.expect("no capture target")
.target_id;
let in_place = t1 == t2;
// SAFETY: CCD query over a Copy target id (test-only diagnostics).
let active = unsafe { crate::win_display::active_resolution(t2) };
println!(
"in-place resize spike: in_place={in_place} (target {t1} -> {t2}) took {resize_ms} ms, \
active resolution now {active:?}"
);
assert_eq!(
active,
Some((2356, 1332)),
"the new mode did not become the active resolution"
);
assert!(
in_place,
"the resize fell back to re-arrival (target id changed) — UPDATE_MODES path not taken"
);
drop(second);
drop(first);
}
}