Commit Graph

10 Commits

Author SHA1 Message Date
enricobuehler 0f798d62b6 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>
2026-06-30 09:09:26 +02:00
enricobuehler bf577044f1 refactor(windows-drivers): pod_init! macro — 27 unsafe { mem::zeroed() } POD inits -> 1 (Goal-3 #3)
The driver zero-initialised C POD structs (IddCx/WDF descriptors) with 27
scattered `let mut x: T = unsafe { core::mem::zeroed() };`, each carrying its own
`// SAFETY` about the all-zero bit pattern being valid + the caller setting `.Size`
etc. right after.

Replace with one `pod_init!(T)` macro (in log.rs, reachable everywhere via the
existing `#[macro_use] mod log;` — same mechanism as `dbglog!`) that owns the
single `unsafe { zeroed::<T>() }` + the SAFETY rationale. All 27 sites
(adapter 6, callbacks 3, entry 4, monitor 10, swap_chain_processor 4) now read
`let mut x = pod_init!(T)`. Zero behavior change (mem::zeroed semantics identical);
the type is passed explicitly so no inference depends on the removed annotation.

27 `unsafe` blocks → 1. Driver still `deny(unsafe_op_in_unsafe_fn)`-clean (the
macro expands to an explicit `unsafe {}`; the one nested-in-user-unsafe site is
fine — no `unused_unsafe` for macro-generated blocks). Driver-only (CI-gated);
adversarially reviewed (macro scoping, all sites, no leftover raw zeroed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 06:01:02 +00:00
enricobuehler 00cf51d610 refactor: rename pf-vdisplay-proto -> pf-driver-proto (it spans all drivers)
The shared host<->driver ABI crate already contains more than the virtual
display: the IDD-push frame ring + control plane AND the gamepad shared-memory
layouts (XusbShm / PadShm). "pf-vdisplay-proto" was a misnomer — the name now
represents all the drivers it serves.

Mechanical rename, no behavior change:
- git mv crates/pf-vdisplay-proto -> crates/pf-driver-proto (package name +
  path-deps in the host crate and the driver workspace).
- pf_vdisplay_proto -> pf_driver_proto across host + driver Rust, both Cargo.lock
  files, the workspace members, the CI path triggers (windows-drivers.yml), and
  the docs/INF comments. The runtime Global\pfvd-* shared-object names are a
  SEPARATE contract and are deliberately untouched (host<->driver name matching).
- The pf-vdisplay DRIVER crate + its INF service name (Root\pf_vdisplay,
  UmdfService=pf_vdisplay, pf_vdisplay.dll) are unchanged — only the full
  `pf_vdisplay_proto` token was replaced, never the `pf_vdisplay` driver name.

Linux-verified: cargo test -p pf-driver-proto (const size-asserts compile) +
cargo clippy -p punktfunk-host -D warnings clean; Cargo.lock regenerated. The
driver-workspace side (path-dep + imports + its Cargo.lock) is Windows-CI-gated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 05:38:21 +00:00
enricobuehler 8cde8621ce fix(windows-drivers): reclaim pf-vdisplay monitor ids on REMOVE (P1, slot-reclaim)
The driver assigned each virtual monitor a monotonically-increasing NEXT_ID used
as the EDID serial / IddCx ConnectorIndex / container GUID, and never reclaimed
it on REMOVE. Under sustained ADD/REMOVE churn the connector index kept climbing,
so IddCx/PnP allocated a NEW OS target slot every cycle and orphaned the old one
(ghost "Generic Monitor (punktfunk)" nodes) until the adapter's target capacity
was exhausted and ADD failed 0x80070490 ERROR_NOT_FOUND.

Fix: `create_monitor` now allocates the LOWEST free id (`alloc_monitor_id`,
computed under the MONITOR_MODES lock with the push) instead of a counter, so a
departed monitor's id is reclaimed and a fresh ADD reuses its target slot rather
than orphaning it. With <= N live monitors the id stays bounded to 1..=N+1.
Deleted the now-unused NEXT_ID + AtomicU32/Ordering import.

CI-compile-gated only — the wedge reproduces solely under sustained churn on the
RTX box, so this needs an on-glass reconnect-storm A/B to confirm (box is
ephemeral/down). Marked on-glass-pending in windows-host-rewrite.md §4; keep
reset-pf-vdisplay.ps1 as the recovery until validated. NOT to be relied on (or
merged to main) until that A/B passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 22:11:36 +00:00
enricobuehler cd591514ad feat(windows-drivers): EvtCleanupCallback + single-identity dedup; document state ownership (E1)
EvtCleanupCallback on the WDFDEVICE (entry.rs + callbacks::device_cleanup): on device removal (PnP/unload) drop every monitor's swap-chain worker via monitor::cleanup_for_device_removal (joins threads, IddCx-free — the framework tears the monitors down with the device). Worker threads no longer linger into teardown.

Single identity per session (create_monitor): a re-ADD of a still-live session_id departs the stale monitor first, so one session maps to exactly one monitor (no duplicate EDID/target).

DeviceContext-owned state (audit §2.5): documented decision NOT to migrate the globals to a Box/AtomicPtr device-owned allocation. The IddCx monitor/mode DDIs receive only an IddCx handle (never the WDFDEVICE/context), so the state MUST be globally reachable (upstream virtual-display-rs is a process-static for the same reason); the globals are already module-encapsulated; and with one devnode + UmdfHostProcessSharing=ProcessSharingDisabled they die with the host process on removal anyway. A pointer variant would only add a host-gone-watchdog-race use-after-free for zero benefit.

Verified: driver workspace builds clean on the RTX box (.173).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:48:23 +00:00
enricobuehler 0a7ae5ef09 feat(windows-drivers): host-gone watchdog, SET_RENDER_ADAPTER, log gate, mode bounds
Audit §4.1: implement the host-gone watchdog — it was dead code (WATCHDOG_PINGS bumped but never sampled, no thread). Every IOCTL now bumps a liveness counter; a watchdog thread reap_orphaned()s monitors (created_at grace) if no IOCTL arrives within WATCHDOG_TIMEOUT_S, so a crashed/TerminateProcess'd host no longer leaves its virtual monitor + swap-chain worker + pooled D3D device wedged until the next CLEAR_ALL. Removes the false 'watchdog thread' comments.

Audit §4.2: implement SET_RENDER_ADAPTER (was STATUS_NOT_IMPLEMENTED) via IddCxAdapterSetRenderAdapter, so the host can pin the IDD render to the NVENC GPU on a hybrid iGPU+dGPU box (else the OS-picked iGPU makes the host ring textures un-openable -> DRV_STATUS_TEX_FAIL).

Audit §4.4: gate the world-writable C:\Users\Public\pfvd-driver.log behind debug builds / PFVD_DEBUG_LOG (a release build never writes it).

Audit §4.5: bounds-check the requested mode in IOCTL_ADD; compute display_info clock_rate in u64 + saturate (the old u32 refresh*(h+4)^2 overflowed/aborted the mode DDI for large modes).

Verified: driver workspace builds clean on the RTX box (WDK 26100 + LLVM 21.1.2, MSVC). On-glass functional validation of the watchdog/render-pin is a follow-up (needs a driver reinstall + session).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:49:49 +00:00
enricobuehler 83d3d6384a refactor(windows-drivers): STEP 8 (1/n) — unsafe-reduction pass (per-site // SAFETY)
windows-drivers / probe-and-proto (push) Successful in 19s
apple / swift (push) Successful in 1m7s
ci / rust (push) Successful in 1m14s
windows-drivers / driver-build (push) Successful in 1m8s
ci / web (push) Successful in 40s
ci / docs-site (push) Successful in 1m1s
android / android (push) Successful in 3m13s
apple / screenshots (push) Successful in 3m14s
deb / build-publish (push) Successful in 2m38s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
windows-host / package (push) Successful in 5m18s
ci / bench (push) Successful in 4m35s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m26s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m16s
docker / deploy-docs (push) Successful in 31s
Audit pass over the new pf-vdisplay driver's unsafe surface: 92 per-site // SAFETY comments added
across adapter.rs / monitor.rs / entry.rs / callbacks.rs / swap_chain_processor.rs /
frame_transport.rs / direct_3d_device.rs (control.rs already had full coverage). COMMENTS ONLY — zero
logic, signature, or control-flow change (verified via git diff: every added line is a // SAFETY
comment or blank).

The dominant gap was the pervasive `core::mem::zeroed()` FFI-struct builds (IDDCX_*/WDF_*/
DISPLAYCONFIG_* C PODs whose all-zero bit pattern is a valid uninitialized/Invalid state, with the
required .Size/fields set immediately after) — each now carries a one-line // SAFETY. Plus explicit
notes on the two stack/local-pointer-into-FFI hazards (adapter.rs `version` ptr into
IddCxAdapterInitAsync; monitor.rs `edid` Vec ptr into IddCxMonitorCreate — both read synchronously
before the local drops) and the frame_transport.rs raw-HANDLE / mapped-header derefs + cleanup paths.
The already-justified Send/Sync wrappers (SendAdapter, CtxTypeInfo/DevCtxInfo, MonitorObject,
Sendable, FramePublisher) were audited — each already carried a // SAFETY. No site needed a code
change.

First slice of STEP 8 (the SudoVDA drop). Comments-only ⇒ build-neutral; windows-drivers.yml verifies
on the next runner build. Remaining STEP 8: re-vendor the installer's driver binary from the new
drivers/ tree (the shipping packaging/windows/pf-vdisplay/ binary is still built from the OLD oracle
tree with the SudoVDA-compat GUID — ABI-mismatched with the host's proto GUID), add an .inx to the
new tree, re-point scripts/README from vdisplay-driver/ to drivers/, flip the selector default to
pf-vdisplay, then delete the old oracle tree. Keep sudovda.rs (the runtime fallback + the
backend-neutral CCD helpers pf_vdisplay.rs reuses) and the WGC-relay/DDA secure path (the
secure-desktop gate is not yet passed on glass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:00:55 +00:00
enricobuehler 6399d2817d feat(windows-drivers): STEP 7 — HDR/FP16 (validated on-glass: Mac connects WITH HDR)
apple / swift (push) Failing after 4s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 18s
ci / rust (push) Successful in 1m13s
windows-drivers / driver-build (push) Successful in 1m9s
ci / web (push) Successful in 42s
ci / docs-site (push) Successful in 59s
android / android (push) Successful in 3m16s
deb / build-publish (push) Successful in 2m37s
decky / build-publish (push) Successful in 10s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 5s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
windows-host / package (push) Successful in 5m25s
ci / bench (push) Successful in 4m39s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m29s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m12s
The pf-vdisplay driver now advertises HDR/FP16 and the full glass-to-glass HDR path works
end-to-end — validated LIVE: the Mac client connected to the .173 host WITH HDR (display_hdr=true,
FP16 ring -> NVENC P010). The STEP-3 assumption that FP16 needs a higher UmdfExtensions was WRONG:
IddCx0102 + CAN_PROCESS_FP16 + the *2 DDIs works (the oracle proved it; confirmed on-glass
IddCxAdapterInitAsync -> 0x0 WITH the FP16 cap set). Driver-only change — the host FP16-ring ->
NVENC-P010 path and the HDR EDID were already in place.

- adapter.rs: caps.Flags = IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16.
- entry.rs: register the 6 *2/HDR callbacks (ParseMonitorDescription2, MonitorQueryTargetModes2,
  AdapterCommitModes2, AdapterQueryTargetInfo, MonitorSetDefaultHdrMetaData, MonitorSetGammaRamp)
  ALONGSIDE the v1 set (matching the oracle — CAN_PROCESS_FP16 OBLIGATES the *2 DDIs or the
  framework rejects the adapter at init; STEP 3 rejected FP16 only because they weren't registered).
- callbacks.rs: parse_monitor_description2 + monitor_query_modes2 now fill IDDCX_MONITOR_MODE2 /
  IDDCX_TARGET_MODE2 with BitsPerComponent (8|10 bpc RGB); query_target_info already reports
  IDDCX_TARGET_CAPS_HIGH_COLOR_SPACE; set_default_hdr_metadata + set_gamma_ramp accept (the gamma
  one is mandatory under FP16).
- monitor.rs: wire_bits() (Rgb 8|10, no YCbCr) + target_mode2().
- EDID + INF UNCHANGED (the EDID already carries the CTA-861.3 BT.2020 + ST.2084/PQ block; the INF
  stays UmdfExtensions=IddCx0102).

Built via the ultracode flow (STEP-7 map workflow -> agent-implement -> box build [driver green] ->
deploy -> on-glass HDR). OPERATIONAL NOTE: do NOT Disable/Enable the IddCx devnode to reload it —
that leaves the adapter STOPPED in the persisted WUDFHost process (ADAPTER OnceLock survives), so
monitor-create then fails with 0xc00002b6 (INDIRECT_DISPLAY_DEVICE_STOPPED). Kill the pf_vdisplay
WUDFHost process (or reboot) for a clean adapter re-init.

This completes the pf-vdisplay rewrite STEP 0-7, all on-glass validated (loads, adapter inits,
monitor appears, swap-chain drain, IDD-push frames at ~235fps, and HDR). Remaining: STEP 8 (unsafe-
reduction + delete the old vdisplay-driver tree + the vendored SudoVDA driver + unbundle from the
installer = the SudoVDA drop).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 11:31:28 +00:00
enricobuehler d8a453f6ca feat(windows-drivers): STEP 5 — SwapChainProcessor + Direct3DDevice (swap-chain drain)
apple / swift (push) Failing after 1s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 18s
ci / rust (push) Successful in 1m14s
windows-drivers / driver-build (push) Successful in 1m11s
ci / web (push) Successful in 41s
ci / docs-site (push) Successful in 1m1s
android / android (push) Successful in 3m22s
deb / build-publish (push) Successful in 2m37s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 4s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 6s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
windows-host / package (push) Successful in 5m52s
ci / bench (push) Successful in 4m47s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m28s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 17s
The pf-vdisplay driver now consumes the OS swap-chain so a virtual monitor is a usable
display rather than a stalled one. Compiles + loads on-glass (no regression: adapter still
inits, Status=OK); adversarially reviewed — no blockers, the leak/deadlock invariants preserved.

- new swap_chain_processor.rs: a worker thread (MMCSS "Distribution") that binds the render D3D
  device (IddCxSwapChainSetDevice, single-borrow 60x@50ms retry) then drains the swap-chain
  (ReleaseAndAcquireBuffer2 -> FinishedProcessingFrame; E_PENDING waits 16ms on the surface
  event). NO frame publisher yet (STEP 6). RAII terminate+join Drop; the load-bearing
  top-of-loop terminate check (the oracle's reconnect-leak fix). Fixed a Rust-2021 disjoint-
  capture bug: `.0` field access bypassed the Sendable Send wrapper -> rebind the whole wrappers.
- new direct_3d_device.rs: CreateDXGIFactory2 -> EnumAdapterByLuid(render LUID) -> D3D11CreateDevice;
  a DEVICE_POOL of one Arc<Direct3DDevice> per render LUID (the NVIDIA-UMD-worker-thread leak fix).
- monitor.rs: MonitorObject gains swap_chain_processor; set/take helpers return it for the caller
  to drop OUTSIDE the MONITOR_MODES lock (dropping joins the worker — must never happen under the
  lock); remove_monitor/clear_all drop it before IddCxMonitorDeparture.
- callbacks.rs: assign_swap_chain spawns the processor (pooled device per RenderAdapterLuid;
  WdfObjectDelete on D3D-init failure so the OS retries); unassign_swap_chain drops it. Fixed the
  stale `panic = "abort"` doc (workspace is unwind; the extern "C" boundary aborts on unwind).
- Cargo.toml: windows 0.58 + thiserror (both already resolved in the driver lock). The 3 needed
  swap-chain DDIs were already wrapped in wdk-iddcx; their HRESULT-shaped NTSTATUS is classified
  by hand (hr>=0 success, 0x8000000A E_PENDING).
- Also rustfmt'd the whole driver workspace (it had never been driver-fmt'd).

Built via the ultracode flow: STEP-5 map workflow -> agent-implement -> box build (caught the
Send-capture bug) -> adversarial-verify-agent -> deploy (loads). Session-1 on-glass validation
(the drain loop servicing an ACTIVE monitor) is the next gate — assign_swap_chain only fires
under an interactive session. Note for STEP 6: target_id_for_object uses the MONITOR_MODES handle
lookup the oracle moved to a WDF context; revisit before target_id keys the shared frame ring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 09:29:20 +00:00
enricobuehler bbc891e50a feat(windows-drivers): STEP 4 (2/n) — create_monitor + real mode DDIs + ADD/REMOVE
windows-drivers / probe-and-proto (push) Successful in 33s
windows-drivers / driver-build (push) Successful in 1m10s
android / android (push) Successful in 4m2s
ci / rust (push) Successful in 4m39s
ci / web (push) Successful in 44s
ci / docs-site (push) Successful in 52s
deb / build-publish (push) Successful in 2m17s
windows-host / package (push) Successful in 6m16s
decky / build-publish (push) Successful in 25s
ci / bench (push) Successful in 4m44s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 27s
apple / swift (push) Successful in 1m13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m51s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m51s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m18s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 47s
apple / screenshots (push) Successful in 5m45s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m49s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m47s
docker / deploy-docs (push) Successful in 21s
The virtual-monitor lifecycle is now code-complete on the driver side (CI-green;
deployed — no load/adapter-init regression, Status=OK):

- new monitor.rs: the monitor/mode model (Mode/MonitorObject/MONITOR_MODES), ported from
  upstream virtual-display-rs with guid:u128 -> session_id:u64. create_monitor builds an
  EDID (serial=id) -> IddCxMonitorCreate -> IddCxMonitorArrival, stores the monitor, and
  returns the OS target id + adapter LUID for AddReply. remove_monitor / clear_all depart
  + drop. display_info/target_mode build the DISPLAYCONFIG timing (the union videoStandard
  u32 set directly — bindgen-API-agnostic, vs the oracle new_bitfield_1 transmute).
- callbacks.rs: parse_monitor_description (EDID-serial lookup -> count-then-fill
  IDDCX_MONITOR_MODE) + monitor_query_modes (pointer-match -> IDDCX_TARGET_MODE) are real.
- control.rs: IOCTL_ADD -> create_monitor + AddReply, REMOVE -> remove_monitor, CLEAR_ALL
  -> clear_all, via read_input/write_output_complete WDF buffer helpers. SET_RENDER_ADAPTER
  still stubbed (hybrid-GPU pin, next) + the watchdog thread (next).
- DISPLAYCONFIG_* resolve at the wdk_sys root (pub use types::*), not iddcx.

Warnings are the STEP-7 *2/HDR stubs + created_at (read by the watchdog, next). The
on-glass "monitor appears at WxH@Hz" gate awaits the host switch to pf_vdisplay_proto.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 07:19:39 +00:00