feat(windows-host): pf-vdisplay — fix the ADD/REMOVE wedge + per-client display-config persistence
Two phases of pf-vdisplay (IddCx virtual display) lifecycle work, both validated on-glass on the RTX box.
Phase 1 — fix the long-standing IOCTL_ADD 0x80070490 (ERROR_NOT_FOUND) wedge that ghost-monitor
slot-budget exhaustion produced under ADD/REMOVE churn (the reset-script/reboot recurring failure).
Validated: 43 reconnect-churn cycles, 0 wedges, monitor-node count flat at 1.
* driver: on IddCxMonitorArrival failure, tear the created-but-not-arrived monitor down with
WdfObjectDelete + reclaim its id — the asymmetric-with-the-create-failure-path leak that exhausted
the 16-monitor MaxMonitorsSupported budget; recover MONITOR_MODES from lock poisoning instead of
failing closed (defensive; the driver builds panic=abort).
* host: collapse the build-retry churn — hold ONE monitor lease across all build attempts and preempt
only on Lingering (not Active), so a cold start does 1 ADD not 8; reap not-present "punktfunk"
monitor PDOs on startup (the reset-script step-2 logic, in-process) and self-heal a detected
0x80070490 by reaping + retrying ADD; force-preempt a stuck-Active prior monitor on the
begin_idd_setup timeout (the safety net the Lingering-only preempt would otherwise drop).
Phase 2 — give each client (keyed by its cert FINGERPRINT) a STABLE virtual-monitor id (1..=15) so
Windows reapplies that client's saved per-monitor config (DPI SCALING) across reconnects, and two
clients never share/bleed config. Validated: distinct clients -> distinct ids (1, 2); the driver
honors the host's id (echoed resolved == preferred).
* proto: rename AddRequest._reserved -> preferred_monitor_id (offset 20) and AddReply._reserved ->
resolved_monitor_id (offset 12) — byte-compatible (offset asserts), NO PROTOCOL_VERSION bump, so a
pre-Phase-2 driver degrades gracefully to auto-id (the host detects it via the resolved echo).
* driver: create_monitor honors a host-supplied preferred id via resolve_id (range 1..=15, never
collides with a live monitor) and seeds the EDID serial + IddCx ConnectorIndex + ContainerId from it.
* host: a persisted LRU fingerprint->id map (%ProgramData%\punktfunk\pf-vdisplay-identity.json),
threaded to add_monitor via a set_client_identity no-op trait method (Linux/GameStream unaffected).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -133,9 +133,13 @@ unsafe fn add(request: WDFREQUEST) {
|
||||
complete(request, STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
let Some((target_id, luid_low, luid_high)) =
|
||||
crate::monitor::create_monitor(req.session_id, req.width, req.height, req.refresh_hz)
|
||||
else {
|
||||
let Some((monitor_id, target_id, luid_low, luid_high)) = crate::monitor::create_monitor(
|
||||
req.session_id,
|
||||
req.width,
|
||||
req.height,
|
||||
req.refresh_hz,
|
||||
req.preferred_monitor_id,
|
||||
) else {
|
||||
complete(request, STATUS_NOT_FOUND);
|
||||
return;
|
||||
};
|
||||
@@ -143,7 +147,7 @@ unsafe fn add(request: WDFREQUEST) {
|
||||
adapter_luid_low: luid_low,
|
||||
adapter_luid_high: luid_high,
|
||||
target_id,
|
||||
_reserved: 0,
|
||||
resolved_monitor_id: monitor_id,
|
||||
};
|
||||
// SAFETY: `request` is the framework WDFREQUEST.
|
||||
unsafe { write_output_complete(request, &reply) };
|
||||
|
||||
Reference in New Issue
Block a user