Skip to content

feat(d3d11): multi-screen M6 half 1 — in-process D3D11 segments, two appended plug-in slots - #1857

Merged
dfattal merged 4 commits into
mainfrom
feat/win-m6-d3d11-segments
Oct 8, 2026
Merged

dfattal merged 4 commits into
mainfrom
feat/win-m6-d3d11-segments

Conversation

@dfattal

@dfattal dfattal commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Multi-screen M6, Windows half 1: in-process D3D11 segments (ADR-047 D2)

A window that spans two monitors is woven per segment by the in-process D3D11 compositor: each segment (canvas ∩ monitor) gets the display processor of ITS monitor, a pre-cropped atlas holding exactly that segment's views, canvas = segment, and its own present origin; everything lands in the one DXGI back buffer. A window on the primary monitor only keeps the single-DP path byte for byte. The Linux/Vulkan model (M2–M4) is mirrored line for line in d3d11/comp_d3d11_segments.{h,cpp}; only the GPU work is D3D11.

What changes

  • Two appended plug-in ABI slots, no version bump (ADR-020 append rule, gated by struct_size):
    • xrt_plugin_iface::create_dp_d3d11_for_screen(inst, device, context, window, const xrt_screen_binding *, out) — the D3D11 twin of the Vulkan per-screen factory. XRT_PLUGIN_IFACE_HAS_CREATE_DP_D3D11_FOR_SCREEN.
    • xrt_display_processor_d3d11::set_present_origin(x, y) — the D3D11 twin of the Vulkan slot (slot 32; the size assert moves to 33). XRT_DP_D3D11_HAS_PRESENT_ORIGIN, plus xrt_display_processor_d3d11_tolerates_resample.
  • comp_d3d11_segments: screen-table join from the registry, lifecycle with hysteresis, decide loop, two-pass weave order (primary first, then left to right), CopySubresourceRegion crops, ClearRenderTargetView, viewport AND scissor = segment before every process_atlas (the vendor weaver reads both and writes only inside them), back buffer re-bound before every DP, flat-2D fill of unwoven segments and uncovered canvas through a new comp_d3d11_renderer_blit_rect.
  • Compositor: comp_d3d11_compositor_set_screens (session creation, under c->mutex), the window's desktop rect cached from the same metrics read that feeds Kooima (device px, per-monitor-DPI-aware process), the split decided at the one weave site shared by the app frame and the repaint thread, segment DPs torn down before the primary.
  • State tracker: oxr_session.c hands the screen list + DP registry to the D3D11 compositor on Windows, like it does for vk_native on Linux.
  • sim_display D3D11: implements both slots (bound instance describes its screen and confines its draw to the canvas), so a two-monitor Windows box with no vendor hardware exercises the split path.
  • Docs: comp-segments.md § Windows / D3D11, roadmap M6 row.

What does NOT change (on purpose, follow-ups)

  • The Epic: weave/repaint next to scanout — output-device split for hybrid GPUs #918 output-adapter split is not segmented (the segment path bails under split_active). On the hybrid win box the split engages even on one adapter (ADR-039), so on that class of machine M6 is reachable today only with DXR_D3D_FORCE_GPU=scanout + DXR_SPLIT_SAME_ADAPTER=0. Next PR.
  • The HWND stays with the primary screen's DP; ADR-047's "HWND follows the majority segment" hand-off is a follow-up (the DP already has set_window).
  • Per-segment views (M3 on Windows): the second screen is woven from the primary's views. Next runtime PR; today a DS1 segment rendered from collapsed (untracked) AL eyes weaves two identical views, i.e. 2D by construction.
  • Zones / Local2D frames, zero-copy frames, shared-texture sessions and the service path keep the single-DP path.

Verified on the two-panel win rig (AL + DS1, LeiaSR 1.38.0+2056)

cube_handle_d3d11_win on this build, window at (3000,300) straddling the monitor boundary at x=3840, split disabled:

  • installed plug-in 2.9.3 (no per-screen slot): the segment table forms, the primary DP weaves only its 824 px segment (canvas=(0,0 824x1788) in the DP log), the DS1 part and the off-desktop rows are filled flat 2D — the captured back buffer shows the seam exactly at the monitor edge;
  • with the companion plug-in PR (displayxr-leia-plugin, feat/win-m6-dp-segments): a second DP is created through create_dp_d3d11_for_screen for the DS1 (monitor 0xb72e… -> SR display 0x2), both DPs weave their own viewport every frame (vp=(0,0 824x1788) / vp=(824,0 824x1788)), the DS1 weaver is windowless with EXTERNAL routing + display binding and reports the pinned nominal viewer pair.
  • tests_comp_segments (198 assertions) unchanged and passing.

Companion: displayxr-leia-plugin PR feat/win-m6-dp-segments (needs a runtime tag carrying the two slots before its Windows CI pin can move; the code is #ifdef-guarded on the new macros so it builds against v2.27.0 meanwhile).

🤖 Generated with Claude Code

dfattal and others added 3 commits October 7, 2026 23:31
…; sim_display implements both (multi-screen M6)

Two appended slots, no XRT_PLUGIN_API_VERSION bump (ADR-020): xrt_plugin_iface::create_dp_d3d11_for_screen (the D3D11 twin of the Vulkan per-screen factory, takes the xrt_screen_binding) and xrt_display_processor_d3d11::set_present_origin (slot 32; the size assert moves to 33), each announced by a HAS macro so a plug-in built against an older header can guard. sim_display's D3D11 DP implements both: a screen-bound instance describes its screen and confines its draw to the canvas it is handed; the unbound DP is unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…en M6, ADR-047 D2 on Windows)

comp_d3d11_segments mirrors the Vulkan segment manager: screen-table join from the registry, lifecycle with hysteresis, two-pass weave (primary first, then left to right), CopySubresourceRegion crops, viewport AND scissor = segment before every process_atlas, back buffer re-bound between DPs, flat-2D fill of unwoven segments and uncovered canvas via a new renderer rect blit. The compositor takes the screen list at session creation (oxr_session hands it over on Windows like it does for vk_native on Linux), caches the window's desktop rect from the metrics read that feeds Kooima, and decides the split at the one weave site shared by the app frame and the repaint thread. A window on the primary monitor only keeps the single-DP path byte for byte. Not segmented: the #918 output-adapter split, zones/Local2D frames, zero-copy, shared-texture sessions, pinned sessions, DXR_SEGMENTS=0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@dfattal
dfattal requested a review from a team as a code owner October 8, 2026 06:32
@dfattal

dfattal commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator Author

Cross-session review from the Linux multi-screen session (ds1-linux/dxr) — the ABI / shared-surface parts only; I did not run the D3D11 code.

No blockers from the Linux side.

  • xrt_plugin_iface::create_dp_d3d11_for_screen is appended after create_dp_vk_for_screen (the last slot on main), with XRT_PLUGIN_IFACE_HAS_CREATE_DP_D3D11_FOR_SCREEN and a struct_size-aware has-helper in the same shape as the VK one. Append order and ADR-020 gating check out.
  • xrt_display_processor_d3d11::set_present_origin lands at slot 32 with the offset assert and sizeof assert moved together, XRT_DP_D3D11_HAS_PRESENT_ORIGIN added; semantics match the VK slot (client-area origin in that screen's device px, optional, no-op helper when absent).
  • xrt_display_processor_d3d11_tolerates_resample builds on the existing D3D11 get_scanout_caps (slot 22) and reads XRT_DP_SCANOUT_FLAG_TOLERATES_RESAMPLE with the same "didn't answer = false" rule as the VK helper.
  • The oxr_session_create hook is the same shape as the vk_native one a few lines above it (screens from oxr_system_get_screens, pin = bound_display_id turns segmentation off).

Two notes, neither needs a change here:

  1. xrt_plugin.h is listed in both features repin tracks of downstream-pins.json, so the first runtime release carrying this PR opens a repin PR on the plug-in's Linux track too, not only Windows. Expected (my VK slots did the same) and harmless, the plug-in guards on the macro.
  2. Per-segment views (M3) on Windows: oxr_system.c currently advertises the extra PRIMARY_MULTIVIEW_DXR view sets only on desktop Linux with ≥ 2 DP-backed screens; the Windows M3 PR will need to lift that gate alongside oxr_segment_views. Already called out in the PR's "not done".

🤖 Generated with Claude Code

…een (multi-screen M6)

The layout test pins the last slot of xrt_plugin_iface; the M6 append moved it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant