github NortheBridge/LuminalVGD v0.1.0-alpha.6
Build 17 Proto Driver (0.1.0.17)

3 hours ago

DriverVer 07/31/2026,0.1.0.17 · proto 0.5 · Authenticode-signed by NortheBridge Foundation, SSL.com timestamped.

Two features in one signing round. Install with scripts\install-driver.ps1 (elevated), or take it bundled with LuminalShine 26.08.0-rc.5.


1. Duck the device, not the display (the wedge fix)

When the GPU resets, the driver loses its D3D device. Builds 14 and 15 responded by calling IddCxMonitorDeparture — parking the virtual monitor to get out of Windows' way.

Under virtual_display_layout=exclusive the virtual display is the only active output, so parking it took the machine's active display count to zero. The 2026-07-30 incident shows the consequence, in order:

09:02:15.111  corrected PCIe AER on the GPU root port
09:02:18.337  driver: AcquireBuffer -> DEVICE_REMOVED, reason DEVICE_RESET   (+3.2 s)
09:02:18.421  Tier-1 duck-out PARKS the only active display
09:02:18.552  +131 ms — dwm.exe reports a BLACK SCREEN
09:02:18.514  QueryDisplayConfig starts answering SUCCESS with ZERO paths   (48 calls, 7.9 s)
09:02:26.569  QueryDisplayConfig itself -> ERROR_NOT_SUPPORTED, permanently
09:02:26.588  GTA5_Enhanced.exe dies 0xC000041D
~09:02:26     dwm is destroyed and recreated — the replacement inherits the wedge

Only a power cycle cleared it. Windows logged no Event 4101 — the OS never ran a TDR recovery cycle, because there was nothing left to recompose onto. The same departure also broadcasts DBT_DEVNODES_CHANGED, which is the documented GTA V Enhanced killer.

Build 17 keeps the monitor arrived. The D3D device and swapchain are torn down and the frame ring is marked REBUILDING, but the IddCx monitor and its OS display path stay alive. DESIGN.md §3.3 rule 2 already required this — builds 14/15 were the deviation.

Why the recovery signal is lock-free

frame_loop holds the ring mutex for a worker's entire lifetime. The first implementation read ring state through try_lock and treated WouldBlock as "not recovered" — so a ring that had fully recovered and was streaming always read as broken. The zero-modeset good exit was unreachable, and ~10 s later the requalify arm departed the display anyway, on a machine that had already healed itself. Two independent reviews found it; tdr::RingLive (an atomic mirror the frame worker publishes beside the mutex, never behind it) replaced it, and recovered_ring_settles_even_though_its_worker_pins_the_mutex pins the fix.

Escape hatch

LuminalVgdTdrDuckMode, REG_DWORD, under the devnode's Device Parameters key:

HKLM\SYSTEM\CurrentControlSet\Enum\ROOT\DISPLAY\000x\Device Parameters

Absent or 0 — duck the device (new default). 1 — the build-14/15 display duck-out. Applies with pnputil /restart-device; no reinstall. Deliberately not seeded from the INF, because an HKR AddReg would stomp an operator's override on every package update.


2. Dynamic target modes (proto 0.5, caps::DYNAMIC_MODES)

A monitor's advertised mode list is fixed at IddCxMonitorCreate. No IddCx DDI in 1.10 or 1.11 replaces a monitor description on an arrived monitor, and until now the only way to change the set was destroy + recreate — the exact monitor cycle feature 1 exists to avoid.

UPDATE_MODES (FN 0x809) republishes a target subset chosen from the create-time superset, through IddCxMonitorUpdateModes2 with Reason = IDDCX_UPDATE_REASON_CONFIGURATION_CONSTRAINTS. Windows selects from the monitor∩target intersection, so this steers what the OS may pick without any devnode event.

Contract: UPDATE_MODES steers what the OS may select; it never evicts what the OS has selected. A push that would gate out the committed mode is refused — the push only, never the session — with err::MODE_COMMITTED (-14, distinct from the retryable UPDATE_FAILED -13), update_status::BLOCKED, and the blocking mode's create-time index so a host can name it rather than guess. It fails open: a committed mode the superset cannot describe proceeds as before rather than silently disabling the feature.

IddCxMonitorUpdateModes (the non-2 variant) was bound for symmetry and has been deleted. Microsoft documents that drivers reporting IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16 "can only call IddCxMonitorUpdateModes2; calling IddCxMonitorUpdateModes is an error", and CAN_PROCESS_FP16 is this driver's only adapter flag — it is what makes HDR work.


Compatibility

Backward compatible in both directions. No shipped IOCTL value, struct size or field offset moved; UpdateModesReply stays 40 bytes; PROTO_VERSION_MINOR_REQUIRED stays 3 — raising it would fail the handshake against every alpha driver in the field, which surfaces as NOT_HANDSHAKEN on every session IOCTL, i.e. a refused session.

  • Hosts predating 0.5 are unaffected by construction — the new opcode is additive and gated on the capability bit.
  • A 0.5-aware host against an older driver degrades: the capability bit is absent, and an unknown opcode returns STATUS_INVALID_DEVICE_REQUEST, never a false success.

Review history

Five rounds before signing, each finding real defects. Confirmed and fixed: the recovery discriminator above; a gate flip that pnputil /restart-device silently ignored on a same-process device re-add; commit ordering that made a failed push an unretryable silent no-op; a TDR-parked patch that made a host's rescind permanently unreachable; and a superseded-but-successful push that left fully_in_force() asserting true for a mode the monitor was not offering.

The final pre-signing review raised 8 findings, refuted 6, and the survivor was reproduced with a standalone test before being fixed. 52/52 driver unit tests, 0 failures across the workspace.


What is not yet proven

Nothing here has run against a real GPU outage. Two questions are answerable only on hardware:

  1. Does an added target mode actually surface? IDARG_IN_UPDATEMODES2 carries target modes only, no IddCx entry point updates a monitor description, and the flag that would skip the monitor∩target intersection (REMOTE_ALL_TARGET_MODES_MONITOR_COMPATIBLE) is documented remote-drivers-only — a console-session driver cannot opt in. If the OS does not re-solicit ParseMonitorDescription2, feature 2 is inert; feature 1 still addresses the wedge.
  2. Does IddCxMonitorUpdateModes2 replace or append the target list? Undocumented — the Learn remarks say only "update the mode list previously reported". The design is safe either way, via an invariant re-checked under the lock immediately before the call: targets ⊆ superset.

When measuring: vgd-probe --target-mode against the currently-committed rate is refused by design. Gate out a rate the OS is not running.

🤖 Generated with Claude Code

Don't miss a new LuminalVGD release

NewReleases is sending notifications on new releases.