On-glass diagnosis narrowed decisively. PROVEN it is the driver, NOT the box:
enabling the installed SudoVDA devnode -> Status=OK (the box inits a self-signed
IddCx adapter right now). SudoVDA uses the IDENTICAL UmdfExtensions=IddCx0102 and is
built against IddCx 1.10 (DriverVer 1.10.9.289) — exactly our config.
Matched SudoVDA/the oracle on every inspectable dimension, none fixed the
IddCxAdapterInitAsync INVALID_PARAMETER: caps byte-perfect (offsets+sizes vs C +
framework table), minimal SDR adapter fails identically, dispatch byte-identical to
the oracle (IddFunctions[idx] + IddDriverGlobals), IddMinimumVersionRequired=4 (same
as oracle), version pointers, ObjectAttributes, init order, and now an adapter WDF
context type (this commit). The remaining difference is the Rust binary itself vs
SudoVDA C++. Next: capture IddCx ETW/WPP rejection reason (or kernel debugger), or
build the oracle (wdf-umdf Rust) on-glass to isolate Rust-wide vs wdk-sys-specific.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
wstr! used `const W; W.as_ptr()` which points to a temporary dropped at the end of
the statement (dangling) — fixed to `static W` (stable address). On-glass it did NOT
change the IddCxAdapterInitAsync INVALID_PARAMETER, and a minimal SDR adapter
(Flags=NONE + required callbacks only) fails identically, so the caps content +
callbacks are NOT the blocker (offsets are byte-perfect vs C; sizes match the
framework table; dispatch + device are correct). Config restored to FP16 + full HDR
callbacks. Remaining suspects: IDARG_IN_ADAPTER_INIT layout, the missing DeviceContext
(oracle always sets one), or a box/framework regression.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
IddCxAdapterInitAsync still INVALID_PARAMETER. Logged offset_of! for every
IDDCX_ADAPTER_CAPS + IDDCX_ENDPOINT_DIAGNOSTIC_INFO field on the box: ALL match the
expected C x64 layout exactly (caps Flags=4 MaxRate=8 MaxMon=16 Diag=24 Static=80;
diag Trans=4 Friendly=8 Model=16 Manuf=24 HwVer=32 FwVer=40 Gamma=48). So the wdk-sys
bindgen lays the struct out correctly — NOT a layout bug. The caps are byte-identical
to C + match the framework size table + the oracle, yet rejected. Next: runtime
compare vs the oracle (does it init an adapter on this box now?) + WDK-docs deep-dive.
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>
adapter.rs: init_adapter(device) builds IDDCX_ADAPTER_CAPS (CAN_PROCESS_FP16,
MaxMonitorsSupported=16, endpoint diagnostics with wstr! PCWSTR names) +
IDARG_IN_ADAPTER_INIT and calls IddCxAdapterInitAsync; EvtDeviceD0Entry triggers it
(idempotent), EvtIddCxAdapterInitFinished stashes the adapter in a OnceLock for
later DDIs. zeroed()+named-field construction dodges the Default-derive +
field-order questions. Compiles + links clean on the box (pf_vdisplay.dll 268KB).
CI gate = compile+link; the on-glass load/enumerate gate needs the box + an INF +
SwDeviceCreate (next).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The versioned IDD_STRUCTURE_SIZE path referenced IddClientVersionHigherThanFramework/
IddStructureCount/IddStructures — LNK2019 unresolved, because the WDK links the iddcx
1.0 IddCxStub which lacks those (they are >=1.4). We target 1.10 against a current
framework (higher==false) where size_of is exactly the versioned result, so use it
directly (the surface-assert refs linked only because they were DCE-eliminated).
pf-vdisplay now COMPILES + LINKS IddCxStub on the box (263,680B). Point
windows-drivers.yml at the whole workspace + clear FORCE_INTEGRITY on pf_vdisplay.dll;
drop the obsolete UINT diagnostic dump.
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>