Skip to content

feat(d3d11): multi-screen M3 on Windows — per-segment views in the in-process D3D11 compositor - #1863

Merged
dfattal merged 2 commits into
mainfrom
feat/win-m3-segment-views
Oct 8, 2026
Merged

dfattal merged 2 commits into
mainfrom
feat/win-m3-segment-views

Conversation

@dfattal

@dfattal dfattal commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Multi-screen M3 on Windows: per-segment views in the in-process D3D11 compositor

Stacked on #1857 (M6 half 1). With #1857 alone a window straddling two monitors is woven per monitor, but the second monitor's segment is woven from the primary screen's views — rendered from the tracked panel's eyes, so with nobody tracked both eyes collapse and the second panel is 2D by construction (and with a viewer it shows the wrong panel's parallax). This PR ports M3 (ADR-047 D3) so each segment is rendered from its own viewer: on a Leia panel without its own tracker, the plug-in's pinned nominal viewer.

What changes

  • Compositor (comp_d3d11_compositor): publishes the segment table each weave took (seg_pub, generation-bumped on change) under a small lock of its own; comp_d3d11_compositor_get_segment_metrics returns it with each segment's eyes predicted per query (primary from the session DP, others from their segment DP); comp_d3d11_compositor_set_view_routing takes what the app's last xrLocateViews handed out; d3d11_route_effective_layout turns it into per-segment tile rects on the frame's effective layout with the Vulkan drop-on-inconsistency rule; a routed frame is never zero-copy.
  • Renderer: comp_d3d11_eff_layout gains route[]; draw_projection_pass paints segment k's local view j (layer view first_view + j) at the segment's rect inside tile j (the mosaic) for projection layers, and quads / equirect2 once per segment with that segment's camera; zones are untouched; the blend mode is decided once per tile and shared by its segments (same rules as vk_native).
  • Segments: comp_d3d11_segments_get_metrics (geometry, per-screen size + nominal viewer from the registry, woven/has_dp), eyes query requires valid.
  • State tracker: oxr_system counts the registry's D3D11 factories for the PRIMARY_MULTIVIEW_DXR view-set capacity on Windows (same DXR_SEGMENTS=0 / service-mode gates as Linux); locate_get_segment_metrics and the xrEndFrame routing hand-off get their D3D11 branches. The capacity is per system, so a D3D12/GL/VK session on the same box sees the doubled count and never splits (its tail views repeat view 0, as the contract allows).
  • cube_handle_d3d11_win: chains XrViewActivityStateDXR + XrViewDisplayBindingsDXR, renders every routed view, places each binding's local view j in tile j at the binding's segment rect (the cube_handle_vk_linux recipe). Tiled layout only.
  • Docs: comp-segments.md § Windows / D3D11, roadmap M6 row; stale "Vulkan, desktop Linux" comments updated.

Verification

  • tests_oxr_segment_views (143 assertions) and tests_comp_segments (198) pass; Windows build clean.
  • Rig run pending: the DS1 was unplugged from the win box tonight (lent to a Mac). The acceptance when it is back: cube_handle_d3d11_win straddling AL | DS1 logs view sets: routed [display 0x… views 0..1 …] [display 0x… views 2..3 …], the pre-weave atlas's DS1 segment has L ≠ R tiles, and the captured DS1 segment passes the woven oracle (adjacent/two-apart ≈ 1.0) — that is the pixel proof feat(d3d11): multi-screen M6 half 1 — in-process D3D11 segments, two appended plug-in slots #1857 could not give.

🤖 Generated with Claude Code

@dfattal
dfattal requested a review from a team as a code owner October 8, 2026 07:19
@dfattal
dfattal force-pushed the feat/win-m3-segment-views branch from b6f1bae to 148f782 Compare October 8, 2026 07:29
@dfattal
dfattal changed the base branch from feat/win-m6-d3d11-segments to main October 8, 2026 07:46
dfattal and others added 2 commits October 8, 2026 00:46
The in-process D3D11 compositor publishes the segment table each weave took (comp_d3d11_compositor_get_segment_metrics, with each segment's eyes predicted per query: the primary from the session's DP, the other screen from its own segment DP), takes the routing xrLocateViews handed out (comp_d3d11_compositor_set_view_routing) and paints each segment's views at that segment's rect inside every tile (the mosaic): projection layers per routed view, quads and equirect2 once per segment with that segment's camera, zones untouched. A routed frame is never zero-copy. The state tracker counts the registry's D3D11 factories for the PRIMARY_MULTIVIEW_DXR view-set capacity on Windows and hands metrics/routing to the D3D11 compositor like it does for vk_native on Linux. This is what makes a straddling window's second panel render from its own viewer instead of the tracked panel's.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…its segment rect (multi-screen M3)

Chains XrViewActivityStateDXR + XrViewDisplayBindingsDXR on the locate, renders all routed views (eyeCount = the sum), and places each binding's local view j into tile j at the binding's segment rect scaled into the tile — the same recipe as cube_handle_vk_linux. Tiled layout only; the array layout keeps its two slices. One INFO line when the bindings change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@dfattal
dfattal force-pushed the feat/win-m3-segment-views branch from 148f782 to 53c2023 Compare October 8, 2026 07:46
@dfattal
dfattal merged commit a4d76d0 into main Oct 8, 2026
40 checks passed
@dfattal
dfattal deleted the feat/win-m3-segment-views branch October 8, 2026 08:05
dfattal added a commit that referenced this pull request Oct 9, 2026
…plit (multi-screen M6)

The segment path bailed whenever the #918 output-device split was
engaged, and ADR-039 makes the split the default on every hybrid box
(and keeps it on one adapter), so the shipping configuration never wove
a window per screen without DXR_D3D_FORCE_GPU=scanout +
DXR_SPLIT_SAME_ADAPTER=0.

Nothing in the path actually needed the gate: d3d11_dp_weave is the
weave site on both sides of the split, the segment manager is already
created on d3d11_out_device() and hands its DPs d3d11_out_context() (the
plug-in's create_dp_d3d11_for_screen is given the output device), and
atlas_srv there is the egress slot being woven, the output-side copy of
the composed atlas cropped to the box that slot was painted at. With the
flat-2D fill on the output composite unit (previous commit) the gate is
removed: one segment path, per-segment crop / viewport / scissor /
present origin unchanged, #1863 routing unchanged (the mosaic is painted
on the app device and crosses the bridge like any atlas).

A window on one screen is still the single-DP split weave, byte for
byte: comp_d3d11_segments_update returns false and process_atlas runs
with the arguments it always had. A split session logs one WARN when its
segment manager is made, naming the output device it lives on (the rig
check's proof).

Test: a split egress slot one frame behind a resizing window (its own
tile size, the live canvas) still partitions its tile exactly, the seam
where the live window puts it.

Co-Authored-By: Claude Opus 5.5 <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