Skip to content

feat(weave): v13 XrWeaveSubmitMonoIn2DDXR — one flat view while the panel is held 2D (#1796) - #1797

Merged
dfattal merged 2 commits into
mainfrom
feat/weave-mono-in-2d-mode
Oct 2, 2026
Merged

dfattal merged 2 commits into
mainfrom
feat/weave-mono-in-2d-mode

Conversation

@dfattal

@dfattal dfattal commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #1796.

What

XR_DXR_weave v13 adds XrWeaveSubmitMonoIn2DDXR (type 1004999249, the last value of the 240–249 decade). It is chained per submit. When monoIn2D is set and the session's confirmed hardware state is 2D, the desktop-Linux weave engine:

  • skips process_atlas;
  • paints the whole output as one off-panel band. The band is the centre view: for a batch rect, its left half unsqueezed; for v6, the centre tile. It is drawn at full output resolution;
  • applies flat regions and the v4 overlay on top, as before.

Other rules:

  • In 3D the flag has no effect.
  • There is no latch: a submit without the struct is pre-v13 behaviour.
  • The session gets no events.
  • Windows, macOS and Android accept the flag and ignore it.
  • The default contract of xrRequestDisplayModeDXR is unchanged: 2D keeps the weave. Apps rely on that for fade-to-flat.

The consumer is the DisplayXR Browser's Linux menu hold (browser-pvt 0344). While a menu is open over inline 3D, the page's content is now flat and sharp instead of soft and doubled.

Why a weave flag and not a 2D rendering mode

See #1796. In short:

  • Windows: a rendering-mode request is display-global. It is broadcast to every session. Reading the code, the D3D11 service would also force a 3D mode back for a weave client that keeps submitting.
  • Linux: the engine never reads the content mode, and the mode is seeded at xrBeginSession from the head device.
  • The DPs: neither Linux DP presents one view for a 2-view atlas when the lens is off.

Changes

  • XR_DXR_weave.h: the new struct, SPEC_VERSION 13. Also the registry README, the spec docs (§5f + version table), and a pointer from XR_DXR_display_info.md.
  • oxr_weave.c: parses the chain and passes it to the IPC client.
  • ipc_arg_weave_submit::mono_in_2d: appended. The dma-buf call is 968 of 1024 B. Both client submit paths fill it.
  • The Linux server handlers pass it to comp_multi_weave_linux_set_mono_in_2d per submit.
  • weave_run_frame: when the flag is set and the session is confirmed 2D, the whole output becomes one band. One weave(v13) WARN per edge.
  • One flat-view rule. u_weave_flat_view_index (u_weave_span2d.h) picks the view for every flat path: off-panel bands, non-batch flat regions, and mono. The paths are therefore always in register.
    • 1–2 views: view 0, the LEFT view (a batch rect's left half, unsqueezed). This is what the bands always used. It is deterministic so it doesn't flip with the head.
    • N > 2: the view whose eye is nearest the display axis (smallest |x| of the DP's per-view eye offset).
    • No offsets available: (N−1)/2.
    • For ≤ 2 views the bands are byte-identical to before.
  • Spec §5f: mono follows the DP-confirmed hardware-2D state for the session, not the request. It starts on the first submit after confirmation and ends on the first submit after the confirmed state is 3D again.
  • weave_present_vk_linux --test-hold-flicker (implies --mono-in-2d): frames 10–49 in six-frame cycles. Each cycle has a 1-frame hold, a 2-frame hold, and a 2D+3D pair inside one frame. Every frame is read back and must be mono exactly when the last request before its submit was 2D.
  • tests_aux_weave_span2d: unit test for the view selection (stereo invariance, 2×2 / 8-view nearest-axis, fallbacks). The test app cannot submit an N-view grid.
  • weave_present_vk_linux: new options --mono-in-2d, --hold-2d-at=N, --release-3d-at=M, --expect-mono. --expect-mono requires woven == left view unsqueezed and woven ≠ anaglyph. With the flag chained, --expect-anaglyph also requires woven ≠ mono.

Verification (headless, sim_display anaglyph)

Setup:

  • build_linux.sh --hybrid --apps.
  • Dev service in a private XDG_RUNTIME_DIR, with DISPLAY and WAYLAND_DISPLAY unset.
  • DXR_PLUGIN_EXCLUSIVE=sim-display, SIM_DISPLAY_FAKE_TRACKING=1, SIM_DISPLAY_FAKE_LENS=1.
  • --headless 60 --service-pid=…. Every run below PASSED.

Errors are mean |woven − reference| per channel.

run anaglyph err left-view err verdict
A --mono-in-2d --expect-anaglyph (3D: flag ignored) 0.6 5.5 woven
B --mono-in-2d --hold-2d-at=10 --expect-mono 5.4 0.6 one view, no weave
C --hold-2d-at=10 --expect-anaglyph (2D without the opt-in) 0.6 5.6 still woven: existing contract
D --mono-in-2d --hold-2d-at=10 --release-3d-at=30 --expect-anaglyph 0.6 5.5 weave resumes
E --expect-anaglyph (regression) — — PASS
F --test-display-mode / G =deferred --mono-in-2d (event sequences) — — PASS
H --test-hold-flicker --expect-anaglyph 0.6 (final) 5.4 (final) 40 frames checked: 20 mono, 20 woven, 0 wrong, PASS

All runs also passed fd counts flat, HUD composited, and the v12 origin/serial checks.

Service log for B/D:

  • weave(v13): MONO — hardware 2D and the caller asked for one view …
  • weave(v13): weave resumed (the hardware is 3D again)

ctest with DXR_PLUGIN_EXCLUSIVE=sim-display: 74/76. tests_aux_weave_span2d passes: 42 assertions in 5 test cases.

  • tests_rig_composer and tests_oxr_view_space fail identically on the main build (v2.22.2), so they predate this PR.
  • git clang-format was run on src/.

Follow-up

Not verified

  • No panel run, and nothing with the Leia DP. The DP is skipped on the mono path, so no plug-in change is needed.
  • The N > 2 view choice is unit-tested only; no engine run submits an N-view grid.
  • No Windows or macOS build in this box. The client-side change is one extra argument, and the D3D11 handler ignores the field. CI covers it.

🤖 Generated with Claude Code

…anel is held 2D (#1796)

A desktop-Linux present-owner that drops the lens for a reason of its own (the
browser holding the panel 2D while a menu is open over inline 3D) got its
content woven through no lens: both views interlaced, soft and doubled.
xrRequestDisplayModeDXR is hardware-only by contract, and apps rely on that for
fade-to-flat transitions, so the default stays.

XR_DXR_weave v13 adds a per-submit opt-in. With XrWeaveSubmitMonoIn2DDXR chained
and the session's CONFIRMED hardware state 2D (mc->weave.hw_2d_confirmed), the
Linux weave engine skips process_atlas and paints the whole output as one
off-panel band: the centre view (batch: each rect's left half unsqueezed; v6:
the centre tile) at full output resolution, flat regions and the v4 overlay on
top as usual. No effect in 3D, no latch, no session events. Windows, macOS and
Android accept and ignore it. No vendor plug-in change: the engine paints the
band itself, the DP is not called.

Wire: ipc_arg_weave_submit::mono_in_2d (appended; the dma-buf call is 968 of
1024 B). The Linux handlers hand it to the engine per submit
(comp_multi_weave_linux_set_mono_in_2d).

Test: weave_present_vk_linux gains --mono-in-2d, --hold-2d-at=N,
--release-3d-at=M and --expect-mono (woven == the left view unsqueezed, and
NOT the anaglyph).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dfattal
dfattal requested a review from a team as a code owner October 2, 2026 17:33
@dfattal

dfattal commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Consumer: DisplayXR/displayxr-browser-pvt#225 (patches 0345/0346) chains this struct during the Linux menu hold.

@dfattal

dfattal commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator Author

Cross-session review (from the session that wrote #1785 and reviewed #1775). No blocking findings. The direction is right: xrRequestDisplayModeDXR keeps its hardware-only contract, and the present-owner's own reason to go flat is a per-submit opt-in. That is better than overloading the rendering-mode channel.

Checked:

Your three questions:

  1. Left view vs centre view. The header says centre view, but your note and the commit say left ("left/centre"). Make them agree: the header is the contract. For N-view DPs, use the centre view: index (N-1)/2 for odd N; for even N, the view nearest the optical axis (N/2 - 1 or N/2, picked by the per-view eye offset, not by index). With N=2 that is "left or right". Prefer the one the off-panel bands already use, so the two flat paths never disagree in register. If the bands use left today, document it as "the band source view" rather than "centre", and note it for N>2.
  2. D3D11 service parity. Yes, later, as its own issue: the Windows browser has the same menu-over-3D case. The header already states "ignored elsewhere", so v13 is honest today. File it now, so the spec doesn't read as Linux-only forever.
  3. Spec text: docs/specs/extensions/XR_DXR_weave.md should get the same "confirmed state, not the request" sentence the header has. It's the part a second implementer would get wrong.

One edge to test before merge: toggle 2D↔3D quickly while monoIn2D is chained. The first 3D frame after the lens confirms ON must be woven, not one stale mono frame (and the reverse). Since hw_2d_confirmed flips only after the DP confirms, it should hold, but a panel run with a fast menu open/close would prove it.

🤖 Generated with Claude Code

…ate wording, fast hold test (#1796)

- VIEW CHOICE. One helper, u_weave_flat_view_index (u_weave_span2d.h), now
  picks the view for EVERY flat path of the Linux engine: the off-panel
  bands, non-batch flat regions and v13 mono. All three are therefore in
  register.
  - 1-2 views: view 0, the LEFT view (a batch rect's left half), for every
    batch submit. This is what the bands always used. It is deterministic,
    because both eyes are about equidistant from the axis, so a nearest-axis
    rule would flip with the head.
  - N > 2: the view whose eye is nearest the display axis (smallest |x| of
    the DP's per-view eye offset; a tie goes to the lower index).
  - N > 2 with no offsets: the centre index, (N-1)/2.
  The header and spec no longer say "centre view". Unit-tested in
  tests_aux_weave_span2d (stereo invariance, 2x2 and 8-view nearest-axis,
  fallbacks). The test app cannot submit an N-view grid.
- SPEC. §5f states that mono follows the DP-CONFIRMED hardware-2D state for
  the session, not the request. It starts on the first submit after the
  confirmation and ends on the first submit after the confirmed state is 3D
  again. It also gains the view table.
- TEST. weave_present_vk_linux --test-hold-flicker (implies --mono-in-2d)
  runs frames 10..49 in six-frame cycles: a 1-frame hold, a 2-frame hold,
  and a hold opened and closed inside one frame. Every frame is read back.
  Each frame must be mono exactly when the last request before its submit
  was 2D: no woven frame while held, no stale mono after release.
- D3D11-service parity: #1798.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dfattal
dfattal merged commit c2587cd into main Oct 2, 2026
42 of 43 checks passed
@dfattal
dfattal deleted the feat/weave-mono-in-2d-mode branch October 2, 2026 17:55
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.

Linux weave engine: a present-owner's 2D hold should show one flat view, not the woven atlas (XR_DXR_weave v13)

1 participant