Repository navigation
feat(win): multi-screen M6 — one D3D11 DP per screen, bound EXTERNAL weaver; nominal viewer, bound lens (D3) and own tracker (D4) on the second panel - #315
Merged
Conversation
…rigin, nominal viewer on the untracked panel (multi-screen M6)
Implements the runtime's two appended slots: create_dp_d3d11_for_screen resolves the screen to an SR display id (the binding's, else the M0 per-monitor claim) and creates a weaver with SrWeaverRoutingInfo{EXTERNAL, KEEP_DRAG_SNAP iff a real HWND} + SrDisplayBindingInfo{id} chained on the create-info, with the Linux fallback order on a refusal; set_present_origin feeds srWeaverSetPresentOrigin before every weave of a windowless weaver; scissor = canvas alongside the viewport. A weaver bound to a display that is not the runtime's active one pins srWeaverSetSimulatedViewer to the nominal viewer (re-applied per weave), starts no senses, keeps late latching off and creates no lens (David 2026-10-07: an untracked screen renders from its own nominal viewer). The display query chains the binding so a bound DP's geometry describes its panel and reports srDisplayGetIdentifier. The plan is plain C (leia_sr_multi_win.h) with a host test in the Linux lane; an unbound DP gets an empty plan and stays byte-identical. The per-weave diagnostic becomes per-DP state (two alternating DPs made the shared statics WARN every frame). Gated by DXR_LEIA_HAS_SR_MULTI_WIN (SDK headers) and the runtime HAS macros, so the v2.27.0 CI pin still builds.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…-v2-1.38.0.2083 With LeiaSR 2079 (D3, lens per device) the runtime reports SrLensBindingCapabilities::lensPerDevice; a screen-bound D3D11 DP on a non-active display now creates a lens bound to ITS display (SrDisplayBindingInfo on SrLensCreateInfo) and drives it from the runtime's 2D/3D requests, since its EXTERNAL weaver never votes. The bound vote is context-owned and survives srDestroyLens, so it is disabled before destroy (a window leaving that screen hands the panel back to 2D). Pre-D3 runtimes keep leaving that screen's lens alone (gated on tag 27). Pin moves to sr-sdk-v2-1.38.0.2083 (headers add tag 27; dispatch table unchanged; the two Linux-only compose slots are placeholders, unused on Windows). Host test covers the plan. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ned + SR SDK pin sr-sdk-v2-1.38.0.2141 With LeiaSR 2141 (D4, tracker per device) the runtime reports SrEyeTrackerBindingCapabilities::eyeTrackerPerDevice; a weaver bound to a calibrated non-active display then tracks that display's own camera automatically (EXTERNAL included). The screen-bound D3D11 DP keys on it: tracked => no simulated viewer (a pin would override tracking), srInitialize on its instance, late latching on — the same as the active display; not tracked (gate off, older service) => the untracked-screen path stays (pinned nominal viewer, no senses). The bound lens (D3) is independent of tracking. Pin moves to sr-sdk-v2-1.38.0.2141 (tag 28 header only; dispatch table unchanged). Host test covers the gate. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dfattal
force-pushed
the
feat/win-m6-dp-segments
branch
from
October 8, 2026 18:08
fb21141 to
47b6b2a
Compare
dfattal
force-pushed
the
feat/win-m6-dp-segments
branch
from
October 8, 2026 22:31
a11cb7b to
1e7b63a
Compare
…ports its SR-calibrated size (multi-screen M1/M3) The runtime's per-segment views (runtime #1863, ADR-047 D3) refuse to lay out view sets while any segment's screen has no physical size, and on Windows the EDID path never yields millimetres — so a window straddling AL | DS1 got ONE view set from the AL tracker, and the DS1 half weaved correctly (D4) but looked around with the laptop's camera (David, 2026-10-08: "lookaround keeps responding using laptop camera"). The Windows arm now implements the per-monitor slot: for a monitor this plug-in claimed, the size comes from SR's own enumeration descriptor (physicalWidthCm/HeightCm, cached 2 s, non-blocking — the slot must be cheap and callable from any thread), pixel dims native, nominal viewer = the active panel's distance scaled by the height ratio, MANAGED eye tracking. False for an unclaimed monitor or one SR cannot size, so the runtime keeps its own defaults there. Rig (win, LeiaSR 1.38.0+2141, tracker_per_device=on): the locate now reports segments=2 -> total=4 (DS1 0.340x0.190 m), the atlas carries a distinct L/R pair per segment, both halves weave (column ratio 1.04/1.07) and each half looks around from its own camera — confirmed by eye. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
dfattal
force-pushed
the
feat/win-m6-dp-segments
branch
from
October 8, 2026 22:31
1e7b63a to
7db06e7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Multi-screen M6 (Windows): one D3D11 DP per screen, bound SR weaver, nominal viewer + bound lens on the untracked panel
Companion of displayxr-runtime #1857 and #1863, both merged and released in runtime v2.30.0. The runtime appended two slots (
xrt_plugin_iface::create_dp_d3d11_for_screen,xrt_display_processor_d3d11::set_present_origin, no ABI bump); this PR implements them in the Windows D3D11 DP.What changes
leia_dp_factory_d3d11_for_screen: resolves the screen to an SR display id — the binding's owndisplay_id, else this plug-in's per-monitor claim fromprobe_displays(M0,leia_win_claims_lookup) — and creates the weaver throughleiasr_d3d11_create_for_screen.Per-screen weaver plan (
leia_sr_multi_win.h, plain C, host-tested): fromsrGetRuntimeCapabilities(routing + binding + lens-binding caps) decideSrWeaverRoutingInfo{EXTERNAL, KEEP_DRAG_SNAP iff a real HWND}+SrDisplayBindingInfo{displayId}onSrWeaverCreateInfoDX11.pNext, with the Linux fallback order (drop the binding, then routing) on a refusal. An unbound DP (every pre-M6 caller) gets an empty plan: SDK routing, byte-identical to today.Display query by id:
leia_sr_v2_query_displaychains the binding onSrDisplayCreateInfoso a bound DP's geometry describes ITS panel; it also reportssrDisplayGetIdentifier, which for the unbound query is the runtime's active display.Untracked screen = nominal viewer (David, 2026-10-07): a weaver bound to a display that is not the runtime's active one pins
srWeaverSetSimulatedViewer(the SDK's own no-face viewer (0,100,600) mm split by 63 mm), re-applied before every weave; its instance is neversrInitialized and late latching stays off (nothing to latch from until SR D4 gives that screen a tracker).Bound lens (SR D3, LeiaSR 2079+): when the runtime reports
SrLensBindingCapabilities::lensPerDevice, that same DP creates a lens bound to ITS display and drives it from the runtime's 2D/3D requests — it must, since an EXTERNAL weaver never votes. The bound vote is context-owned and survivessrDestroyLens, so it is disabled before destroy (a window leaving that screen hands the panel back to 2D). On a pre-D3 runtime that screen's lens is left alone, as an unbound handle would switch the ACTIVE panel.set_present_origin→srWeaverSetPresentOriginbefore every weave on a windowless EXTERNAL weaver (device px relative to its screen; the effective phase is origin + viewport offset, as measured by the SR session). A weaver with the real HWND is left to the SDK.Scissor = canvas in
process_atlas, alongside the viewport (the runtime contract for segment DPs; the SR weaver reads both).The per-weave diagnostic in
process_atlasmoves from process-wide statics to per-DP state: with two DPs alternating viewports every frame it logged a WARN per frame.Tracker per device (SR D4, LeiaSR 2141+): when the runtime reports
SrEyeTrackerBindingCapabilities::eyeTrackerPerDevice, a weaver bound to a calibrated non-active display tracks that display's own camera automatically (EXTERNAL included). The screen-bound DP keys on it: tracked ⇒ no simulated viewer (a pin would override tracking),srInitializeon its instance, late latching on — the same as the active display; not tracked (gatetracker_per_deviceoff, older service) ⇒ the untracked-screen path above stands. The bound lens (D3) is independent of tracking. This is what makes a straddling window tracked on both halves once the service gate is on.SDK pin →
sr-sdk-v2-1.38.0.2141(tag 27 lens-binding + tag 28 tracker-binding headers; dispatch table unchanged; the two Linux-only compose slots are placeholders, unused on Windows). CMake gates:DXR_LEIA_HAS_SR_MULTI_WIN,DXR_LEIA_HAS_SR_LENS_BINDING,DXR_LEIA_HAS_SR_TRACKER_BINDING.Per-monitor display info (
get_display_info_for_monitor, multi-screen M1): every monitor this plug-in claimed reports its SR-calibrated physical size (the enumeration descriptor's cm, cached, non-blocking), native pixel dims, a nominal viewer scaled from the active panel's, and MANAGED eye tracking. Without it the runtime's per-segment views (#1863) refused the layout — the second screen had no metres on Windows (the EDID reader there never fills mm) — so a straddling window got ONE view set from the active panel's tracker: the DS1 half weaved from its own camera (D4) but looked around with the laptop's.New host test
tests/test_sr_multi_win.cin the Linux lane (plan, fallback order, bound-lens gate, tracker gate, simulated-viewer gate).Verified on the two-panel
winrigLeiaSR 1.38.0+2141,
tracker_per_device=on, runtime v2.30.0 (+ the change-gated locate diagnostic of runtime #1870):cube_handle_d3d11_winstraddling AL | DS1 — the DS1 DP is created formonitor 0xb72e… -> SR display 0x2withplan{external=1 keep_drag_snap=0 bind=1},tracked by its own camera, no simulated viewer, lens BOUND; the locate reportssegments=2 … -> total=4; [0] 0.344x0.194 m; [1] 0.340x0.190 m; the pre-weave atlas carries a distinct L/R pair per segment; both halves weave (adjacent-column ratio 1.04 / 1.07, 2D fallback reads ≈0.54); and David confirmed by eye (2026-10-08): "each half weaves and lookaround locally" — hiding the DS1 camera degrades only the DS1 half. The SR session independently verified EXTERNAL + binding + window=0 weaving with per-device calibration on DX11/DX12/GL/VK, a two-weaver pair in one process, and a bound lens driving the DS1's own FPC.Not in this PR: D3D12 / GL / Vulkan per-screen factories (D3D11 first per David), the service path, per-display trackers (SR D4, tag 28, a further SDK tag).
🤖 Generated with Claude Code