Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ Integrate your 3D display hardware into DisplayXR.
- [ADR-044](adr/ADR-044-colour-contract-per-backend.md) — The colour contract, per backend and swapchain format
- [ADR-045](adr/ADR-045-plugins-always-loadable-and-report-platform-state.md) — Plug-ins are always loadable and report their platform state
- [ADR-046](adr/ADR-046-depth-aware-cursor.md) — Depth-aware cursor — opt-in only; the app knows the depth, the runtime places the cursor
- [ADR-047](adr/ADR-047-multi-screen-segments-and-per-screen-views.md) — Multi-screen — segments and per-screen views
<!-- END ADR INDEX -->

---
Expand Down Expand Up @@ -184,6 +185,7 @@ Design docs, status trackers, and plans — some shipped, some in progress. Afte
- [Display Zones](roadmap/display-zones.md) — N 3D zones + 2D zones + wish mask: avatar migration + phased plan (ADR-027)
- [Android Transparency — Compose-Under-Background](roadmap/android-transparency-compose-under.md) — why Android weaves-then-gates instead of compositing a captured background under the views, the Android capture landscape, and the T0/T1/T2 plan (#1031)
- [Display Spatial Model](roadmap/display-spatial-model.md) — displays in the spatial graph (#46)
- [Multi-screen plan](roadmap/multi-screen.md) — N screens, one DP each, segments + per-screen views; joint runtime × LeiaSR milestones (#69)
- [Multi-Display Single Machine](roadmap/multi-display-single-machine.md) — multiple displays, one machine (#69)
- [Multi-Display Networked](roadmap/multi-display-networked.md) — displays across the network (#70)
- [XR_VIEW_CONFIGURATION_PRIMARY_MULTIVIEW](roadmap/XR_VIEW_CONFIGURATION_PRIMARY_MULTIVIEW.md) — Khronos multiview proposal (#80)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
---
status: Accepted
status: Accepted (§3–§4 superseded by ADR-047; §7 narrowed to Windows drag snapping)
date: 2026-04-02
source: "#69"
---
# ADR-015: DisplayXR Owns Multi-Display Vendor Routing

> **2026-10-07:** §3–§4 (one atlas split at the display boundary) are superseded by
> [ADR-047](ADR-047-multi-screen-segments-and-per-screen-views.md): a spanning window is
> split into per-screen *segments*, each rendered from its own views. §7's HWND rule now
> covers Windows drag snapping only. Plan: `docs/roadmap/multi-screen.md`.

## Context

The current system selects a single vendor driver globally via the builder priority system in `p_prober.c`. The winning builder populates one set of display processor (DP) factories on `xrt_system_compositor_info` — every compositor instance gets the same vendor DP regardless of which physical monitor its window is on.
Expand Down
74 changes: 74 additions & 0 deletions docs/adr/ADR-047-multi-screen-segments-and-per-screen-views.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
status: Accepted
date: 2026-10-07
source: "docs/roadmap/multi-screen.md, #69"
supersedes: "ADR-015 §3–§4 (per-compositor multi-DP over ONE atlas, split-weave at the display boundary)"
---
# ADR-047: Multi-screen — segments and per-screen views

## Context

ADR-015 made DisplayXR the owner of multi-display vendor routing and sketched the
mechanism: one compositor holds one display processor (DP) per display its window
overlaps, renders **one atlas**, splits it at the display boundary and hands each DP its
slice. That mechanism was never built (the registry it needs is empty on Linux, and
`u_multi_display_compute_slices` has no caller), and a fresh read in October 2026 found
two problems with it:

1. **One atlas is only correct when every screen shares the same eyes and geometry.**
Each DP owns its own eye tracker and its own panel geometry (ADR-015 §6 says so
itself). A tracked Leia panel next to an untracked laptop panel, or two Leia panels
with two cameras, need two different Kooima frusta. Slicing one atlas puts the wrong
perspective on one of them.
2. **The OpenXR surface was never addressed.** Every prior document keeps one
`XrSystem`, one view count, one `xrLocateViews` per frame. Per-display eye streams
stop inside each DP; nothing says how a second screen's eyes become app views.

Linux also changed the premises: the weaver is windowless and takes an explicit phase
origin per frame (ADR-033), so ADR-015 §7's primary/secondary HWND rule is a Windows
detail, not the model.

## Decision

1. **Screens are first-class runtime objects.** A screen is an OS monitor. The runtime
keeps a screen registry built from the OS monitor list joined with every loaded
plug-in's `probe_displays()` claims; each entry carries geometry, physical size,
identity (EDID ids, connector, vendor serial), the bound plug-in and its DP
factories, and the screen's own display info and eye-tracking capability. Several
plug-ins are resident at once. One head device remains (it is the pose source, not
display geometry); `xrt_system_compositor_info`'s display fields become a cached copy
of screen 0 for compatibility.
2. **A spanning window is split into segments, not atlas slices.** A segment is the
window's canvas intersected with one screen. Each segment has its own DP instance
(created from that screen's factory with a screen binding), its own present origin,
its own eye positions (that DP's tracker, or the screen's nominal viewer) and its
own Kooima frustum computed from the segment rect relative to its screen. The app
renders each segment's views; the compositor gives each DP its segment's tiles with
`canvas = segment rect` and composites the woven results into the one presented
surface. The slice math survives as segment-rect math. On Linux every segment DP is
windowless with an explicit origin; on Windows the real HWND goes to the
majority-area segment's DP only for drag phase-snapping.
3. **Per-screen views ride the existing multiview surface.** No new view-configuration
type. `PRIMARY_MULTIVIEW_DXR` already advertises a maximum view count and a per-frame
`activeViewCount` (ADR-041). `XR_DXR_display_info` gains display enumeration, a
DISPLAY reference space per display, an optional session→display binding, and a
per-view display binding chained on `XrViewState` (view → display id + segment rect
in window pixels). Views are contiguous per segment. `PRIMARY_STEREO` apps keep two
views from the majority segment and the shipped flat-2D treatment elsewhere
(#1654), so nothing that works today changes until an app opts in.

## Consequences

- ADR-015 §1–§2 (probe + registry), §5 (DP lifecycle), §6 (per-DP eye tracking) and §8
(vendor-owned phase snapping) stand. §3–§4 are superseded by Decision 2; §7 is
narrowed to Windows drag snapping.
- A spanning window costs one view pair per 3D segment. The single-segment case, which
is every window today, pays nothing.
- The DP factory ABI gains a screen binding (ABI bump, ADR-020 append rule); sim_display
moves its panel state from process globals to per-instance state.
- The vendor side needs, in order: an opt-in external-routing weaver mode (null window,
always weave, phase = origin + viewport, no lens vote), display enumeration with
identity, binding display/weaver/lens/tracker to a display id, and N trackers per
service. The first three shipped on the LeiaSR Linux line on 2026-10-07; the fourth
needs two panels.
- Milestones, gates and the SR work items: `docs/roadmap/multi-screen.md`.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@
- [ADR-044](ADR-044-colour-contract-per-backend.md) — The colour contract, per backend and swapchain format
- [ADR-045](ADR-045-plugins-always-loadable-and-report-platform-state.md) — Plug-ins are always loadable and report their platform state
- [ADR-046](ADR-046-depth-aware-cursor.md) — Depth-aware cursor — opt-in only; the app knows the depth, the runtime places the cursor
- [ADR-047](ADR-047-multi-screen-segments-and-per-screen-views.md) — Multi-screen — segments and per-screen views
Loading
Loading