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>
Verified on-glass after cleanup: adapter still inits (IddCxAdapterInitAsync 0x0,
Status OK) and WdfDeviceCreateDeviceInterface 0x0.
- RESTORE WdfDeviceCreateDeviceInterface (regression from debugging): the proto control
plane sends IOCTLs via EvtIddCxDeviceIoControl, which needs the device interface for the
host to open. Upstream omits it only because it uses a socket; ours is IOCTL-based.
- Drop the framework_struct_size / version-table machinery + size.rs: size_of suffices
(these are IddCx 1.10 structs on a 1.10 framework, matching upstream). The version-table
reads were added chasing a size mismatch that was never the bug (GammaSupport was).
- Drop /OPT:NOICF (ICF folding was a non-issue) + fix the stale stub-pick comment (the
1.10 stub is needed for the dispatch table, not size.rs symbols).
- Debug-wait/PID-file/go-file gate already removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DECISIVE: installed the pre-built UPSTREAM virtual-display-rs (Rust wdf-umdf IddCx)
driver on the SAME box -> Status=OK. So a Rust IddCx driver inits an adapter here,
self-signed, right now. My wdk-sys driver still fails ONLY at IddCxAdapterInitAsync
(0xc000000d) despite matching virtual-display-rs on EVERY inspectable dimension:
- same iddcx 1.10 headers+stub
- IDDCX_ADAPTER_CAPS + IDD_CX_CLIENT_CONFIG byte-perfect (offsets match C header)
- runtime pointers all valid/non-null (names .rdata, version stack, dev handle)
- identical IddFunctions[idx]+IddDriverGlobals dispatch; indices 0/1/2
- matched the minimal link (tested vendored wdk-build WITHOUT OneCoreUAP/
NODEFAULTLIB/OPT/INTEGRITYCHECK -> still fails; export pollution ruled out)
- device context, no device interface (control via EvtIddCxDeviceIoControl), init order
The IddCx ClassExtension ETW provider emits no decodable reason (WPP/kernel-debugger
only). The remaining difference is the wdk-sys IddCx binding itself, invisible to
inspection. This commit keeps the upstream-matching structure (device context, no
interface) + the on-glass instrumentation; vendored wdk-build reverted to pristine.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Major on-glass progress on the RTX box. The all-Rust wdk-sys IddCx driver now LOADS
under Secure Boot and runs the ENTIRE init chain: DriverEntry -> WdfDriverCreate ->
driver_add -> IddCxDeviceInitConfig(0x0) -> WdfDeviceCreate -> CreateDeviceInterface
-> IddCxDeviceInitialize -> D0Entry -> init_adapter. Findings:
- Signing was a RED HERRING (the driver loads); std works in WUDFHost (DualSense uses
it too).
- THE unblock: link the iddcx **1.10** IddCxStub (build.rs now picks the highest
version-aware), not 1.0 — the 1.0 stub lacks the version-table symbols AND its
dispatch table mismatched the 1.10 framework, which made IddCxDeviceInitConfig
return INVALID_PARAMETER. With 1.10 the whole chain runs.
- Added a file/OutputDebugString logger (log.rs, matches the DualSense driver) — the
driver was silent; this is how the chain was traced.
- size.rs: framework_struct_size() reads the frameworks authoritative struct sizes
from IddStructures[] (the config keeps size_of=208, validated working).
- adapter.rs: version ptrs + ObjectAttributes(InheritFromParent) + FP16 + framework
caps/diag/version sizes — matches the oracle.
KNOWN WIP: IddCxAdapterInitAsync still returns INVALID_PARAMETER though caps match
the framework size table (88/56/24) + the oracle exactly — likely a subtle wdk-sys
bindgen field-layout detail in IDDCX_ADAPTER_CAPS/IDDCX_ENDPOINT_DIAGNOSTIC_INFO.
CI gate (compile+link) stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DriverEntry -> driver_add builds the full IDD_CX_CLIENT_CONFIG (14 IddCx callbacks +
PnP EvtDeviceD0Entry, all stubs with correct PFN signatures) sized via the ported
IDD_STRUCTURE_SIZE! (size.rs), runs IddCxDeviceInitConfig -> WdfDeviceCreate ->
WdfDeviceCreateDeviceInterface(the owned pf-vdisplay GUID, not SudoVDA) ->
IddCxDeviceInitialize. callbacks.rs has all 14 + device_d0_entry; query_target_info
implements HIGH_COLOR_SPACE. edid.rs salvaged verbatim from the oracle. proto gains
interface_guid_fields() (u128 -> Windows GUID fields). Links IddCxStub (the CI gate);
adapter/monitor/swapchain/IDD-push fill the stubs in STEP 3-6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M1 step 2 begins. Add the wdk-iddcx (lib, re-exports wdk_sys::iddcx) + pf-vdisplay
(cdylib) workspace members. pf-vdisplay STEP 0 = DriverEntry + WdfDeviceCreate
skeleton + a #[used] _std_link_gate forcing std::thread + OwnedHandle to link, so
the build proves the std surface resolves under the wdk-build UMDF link settings
(kernel32 is /NODEFAULTLIB - std must come via OneCoreUAP). If std fails to link
here, the SwapChainProcessor worker-thread design needs a CreateThread shim before
any callback work (port-plan critique gap #9).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>