Skip to content

Order-independent installation: runtime, vendor plug-in, vendor platform/conversion runtimes, any order, install and uninstall #1803

Description

@dfattal

Goal

The DisplayXR stack must install and uninstall in any order, with or without the 3D display connected:

  1. the vendor platform runtime (tracking/weaving platform),
  2. the vendor conversion runtime (2D→3D, consumed by XR_DXR_lift),
  3. the DisplayXR bundle = runtime + vendor plug-in + service start.

Design approved 2026-10-02.

Hard constraints

  • C1. The DisplayXR runtime (and the bundle) must not know about any vendor (no vendor paths, names, registry keys).
  • C2. The vendor platform runtime and the vendor conversion runtime must not know about DisplayXR.
  • C3. The vendor plug-in may know about its vendor platform and conversion runtimes.

Current behaviour (verified by code reading + box logs, 2026-10-02)

Order / state What happens today
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.

Root causes

  • (a) Load-time coupling of the vendor plug-in to its vendor platform.
  • (b) Selection re-evaluated only on client events; probe() may block ~20 s.
  • (c) Frozen process environment (PATH) in the long-lived service.
  • (d) Installers encode order (bundle sniffs vendor paths, plug-in requires the runtime, runtime uninstaller owns + destroys plug-in registrations).
  • (e) No state surfacing.

Target contract

Runtime (vendor-agnostic)

  • R-a. A registered plug-in is a fact, not a decision. The runtime uninstaller deletes only its own DisplayProcessors\sim-display subkey and /ifempty the parent; it never runs vendor uninstallers and never deletes vendor entries. Orphan entries (Binary missing) are skipped with one WARN.
  • R-b. Every plug-in must be LOADABLE without its platform, and reports a generic state through a new append-only ADR-020 slot: 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 in docs/specs/runtime/plugin-discovery.md).
  • R-c. Selection is re-evaluated on WORLD events, not client events: 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), RegNotifyChangeKeyValue on HKLM\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).
  • R-d. No live swap: while a vendor DP is active and reports NO_DISPLAY the 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).
  • R-e. Surface the state: tray tooltip/icon, Control Panel, displayxr-cli selftest / info, e.g. "Vendor plug-in '' installed — platform missing: ".
  • R-f. Installers: start the service via explorer.exe always (never elevated); a failed child in the bundle must not skip the final service restart; never a modal under /S (/SD).
  • R-g. Resolve vendor dependency DLLs without relying on the service's PATH snapshot: the vendor plug-in resolves them itself; the runtime does nothing vendor-specific here.

Bundle (knows the component list, not vendor paths)

  • B-a. Always install the vendor plug-in (it is inert without its platform); remove the vendor-path sniffing and the "(… not detected)" label. Order inside the bundle stays runtime → plug-in but nothing depends on it.
  • B-b. /SD on every abort MessageBox; a child failure still runs the finalize section (service restart via explorer.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)

  • V-a. Vendor installers should use Windows Restart Manager (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).
  • V-b. The vendor conversion runtime should publish its version in its registry entry.
  • V-c. The vendor conversion runtime must not own a hidden top-level window on a non-pumping thread (it blocks non-forced RM shutdown of any host).

Decisions taken (2026-10-02)

  • No live DP swap while a vendor DP is active: adopt a better plug-in only when the active one is the fallback; otherwise surface NO_DISPLAY.
  • The vendor plug-in is installable without the runtime.
  • One epic here, mirrored items in the vendor plug-in repo, vendor asks for the platform/conversion installers, and a vendor-neutral ADR ("plug-ins are always loadable and report platform state").

Prerequisite (merged 2026-10-02, main 74022ab)

Task list

Runtime (this repo):

Bundle:

Vendor plug-in:

Not part of this epic (box hygiene, found during investigation)

  • The vendor plug-in ships a vendor Vulkan weaver DLL older than the installed vendor platform.
  • A vendor beta DLL lives in the runtime directory (ADR-019 violation).
  • ~15 hand-made .bak / .devtt DLL copies in Program Files.
  • Two orphaned old vendor conversion-runtime MSI entries + a leftover install directory.
  • The bundle's ARP entry reports a stale version (2.4.6).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicTracking epicwindowsWindows platform

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions