| Bundle, then vendor platform runtime |
The plug-in DLL statically imports the platform DLLs, found only via the machine PATH. Without the platform: LoadLibrary err=126 → silent sim-display fallback (anaglyph, no tracking). After the platform is installed the running service keeps its old PATH, so every re-probe fails again until the service restarts. |
| Bundle on a box without the vendor platform |
The bundle pre-selects the vendor plug-in only if the platform's DLLs exist at a vendor path → a silent bundle never installs the plug-in; installing the platform later installs nothing. Violates C1. |
| Vendor platform, then bundle |
Works. The standalone plug-in installer restarts the service ELEVATED (plain Exec) → normal-integrity apps cannot reach it; the bundle uses explorer.exe (ok). |
| Platform present, platform service down at DisplayXR service start |
Plug-in declines; refresh re-probes on the next client connect / compositor create and adopts it (seen in a real log: 6 s later). Adoption is partial: weaving DP + geometry switch, the head device object stays sim-display's. |
| Vendor platform upgraded under a running service |
Mapped platform DLLs stale; D3D11 weaver reconnects, D3D12/GL/VK only detect; log says restart. |
| Vendor platform uninstalled while the service runs |
Untracked weave (DEGRADED); next restart → err=126 → sim-display, silently. |
| Screen not connected at start, connected later |
With the platform present and no EDID match the probe BLOCKS up to 20 s, then declines. Re-probe only on the next client connect (no WM_DISPLAYCHANGE / WM_DEVICECHANGE anywhere); each retry can stall 20 s again. |
| Screen disconnected while running |
Nothing invalidates the cached geometry; the plug-in then claims the PRIMARY monitor as VERIFIED → weave on a normal monitor. |
| Vendor conversion runtime installed after the bundle |
Lift "absent" state is permanent per process; registry never re-read → no lift until service restart. |
| Conversion runtime upgrade/uninstall while loaded |
Files locked by the service. Fix in flight: Restart-Manager-aware service (PR #1793) + the vendor installer must call RmShutdown(RmForceShutdown). |
| Runtime uninstall |
Kills the service, runs each plug-in's UninstallString (ExecWait without _?= → probably not awaited), then deletes the whole DisplayProcessors key (installer/DisplayXRInstaller.nsi:1281-1325, :1335). If the plug-in uninstall fails its files + ARP entry survive UNREGISTERED and a later bundle version-skips it. |
| Plug-in before runtime |
Plug-in installer exits 4 (runtime absent) / 5 (runtime below MIN_RUNTIME_VERSION). |
| Any degraded state |
No tray / Control Panel signal; only displayxr-cli selftest (exit 8 VENDOR_DP_REJECTED) and logs. |
Goal
The DisplayXR stack must install and uninstall in any order, with or without the 3D display connected:
XR_DXR_lift),Design approved 2026-10-02.
Hard constraints
Current behaviour (verified by code reading + box logs, 2026-10-02)
LoadLibraryerr=126 → silent sim-display fallback (anaglyph, no tracking). After the platform is installed the running service keeps its old PATH, so every re-probe fails again until the service restarts.Exec) → normal-integrity apps cannot reach it; the bundle usesexplorer.exe(ok).WM_DISPLAYCHANGE/WM_DEVICECHANGEanywhere); each retry can stall 20 s again.RmShutdown(RmForceShutdown).UninstallString(ExecWaitwithout_?=→ probably not awaited), then deletes the wholeDisplayProcessorskey (installer/DisplayXRInstaller.nsi:1281-1325,:1335). If the plug-in uninstall fails its files + ARP entry survive UNREGISTERED and a later bundle version-skips it.MIN_RUNTIME_VERSION).displayxr-cli selftest(exit 8VENDOR_DP_REJECTED) and logs.Root causes
probe()may block ~20 s.Target contract
Runtime (vendor-agnostic)
DisplayProcessors\sim-displaysubkey and/ifemptythe parent; it never runs vendor uninstallers and never deletes vendor entries. Orphan entries (Binarymissing) are skipped with one WARN.READY | PLATFORM_ABSENT | PLATFORM_NOT_RUNNING | NO_DISPLAY | INCOMPATIBLE+ a short vendor-provided hint string. The runtime never interprets vendor specifics; it only displays the hint.probe()must return within ~100 ms and never block on the platform (documented indocs/specs/runtime/plugin-discovery.md).WM_DISPLAYCHANGE/WM_DEVICECHANGE(DBT_DEVNODES_CHANGED) received by the service's hidden session window (DisplayXRServiceSession, PR feat(service): Restart Manager support so installers can close and restart the service #1793),RegNotifyChangeKeyValueonHKLM\Software\DisplayXR\DisplayProcessors, and a slow timer (10 s) while the active DP is the fallback. Adoption must be COMPLETE (head device, display info, eye tracking, weaving DP).NO_DISPLAYthe runtime keeps it, surfaces the state, and the DP passes pixels through unwoven. Adopt a better plug-in only when the active one is the fallback (sim-display).displayxr-cli selftest/info, e.g. "Vendor plug-in '' installed — platform missing: ".explorer.exealways (never elevated); a failed child in the bundle must not skip the final service restart; never a modal under/S(/SD).Bundle (knows the component list, not vendor paths)
/SDon every abortMessageBox; a child failure still runs the finalize section (service restart viaexplorer.exe) and records the failure.Vendor plug-in (P-a … P-e)
Delay-load + self-resolve its platform DLLs (P-a), cheap non-blocking
probe()reporting state + hint (P-b), display-change invalidation (P-c), conversion-runtime re-probe (P-d), an installer with no runtime/platform prerequisite and Restart-Manager service handling (P-e). Tracked in the vendor plug-in repo — see the task list.Vendor asks (vendor platform + vendor conversion runtime installers — know nothing about DisplayXR)
RmStartSession/RmRegisterResources/RmGetList/RmShutdown(RmForceShutdown)/RmRestart) to close and restart whatever holds their files, instead of move-aside + delete-at-reboot. The DisplayXR service registers for restart and exits on the close query (PR feat(service): Restart Manager support so installers can close and restart the service #1793).Decisions taken (2026-10-02)
NO_DISPLAY.Prerequisite (merged 2026-10-02, main 74022ab)
Task list
Runtime (this repo):
DisplayProcessors; loader skips orphans (R-a, R-f)Bundle:
/SD, finalize after child failure (B-a, B-b)Vendor plug-in:
/S(P-e)Not part of this epic (box hygiene, found during investigation)
.bak/.devttDLL copies in Program Files.