You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Android single-app OOP path was fixed in #541 to decouple two independent concerns that were fused into one hardware_display_3d flag:
Hardware — the panel's lenticular weave state (2D flat ↔ 3D), a display-processor operation driven by xrRequestDisplayRenderingModeEXT → request_display_mode, gated on what display_info advertises.
Content — how the app draws: 1 high-res tile (2D) vs N lower-res tiles (3D), packed into the atlas the runtime hands to the DP.
While doing that I audited the other compositors. All five native compositors still conflate the two — a single hardware_display_3d flag drives both the DP weave and clamps the content tile-count:
This is harmless today because in-process (handle apps) the flag is set reliably by request_display_mode, and the D3D11 service is driven by the workspace controller via workspace_request_display_mode (which crosses IPC) — and each renderer knows its own tile layout. It only broke on Android OOP, where the request was a no-op over IPC (so the flag was inferred from content and latched) and tile_columns was the stale server mode. #541 fixed Android by making the hardware flag reliable (new compositor_request_display_mode IPC) and taking content purely from the submission.
Why this matters (not just consistency)
Developers need to switch hardware and content independently to author their own transitions. The hardware_3d ? N : 1 clamp removes that control: the hardware flag dictates the tile count, so the app can't, say, hold its 3D content while the panel goes flat, or run a custom cross-fade across the switch.
This is most important in MANUAL eye-tracking mode (#522): there, the app owns the tracking-loss lifecycle. On an XrEventDataEyeTrackingStateChangedEXT loss event the app should be free to craft its own response — e.g. drop the panel to 2D (flat, comfortable) immediately while it independently transitions its content (fade the parallax to zero over a few frames, then collapse to a single tile), or vice-versa. With hardware and content fused, none of that is expressible — the moment the app changes one, the runtime forces the other.
Proposed work
Apply the #541 model uniformly to D3D11, D3D12, GL, Metal, and VK-native:
Drive the DP's mode_3d (weave) from the hardware request (request_display_mode), recorded as a dedicated weave-state — not re-derived from the submitted view count.
Build the atlas tile-count/layout from the submission (view count + per-view imageRects), not from the hardware flag.
Remove the hardware_3d ? N : 1 clamp; let the DP weave (hardware-3D) or show the tiles flat (hardware-2D) regardless of how many tiles arrive — so a hardware/content mismatch during a custom transition renders predictably instead of being clamped away.
Reference implementation: comp_multi_system.c render path in #541 (hardware from multi_compositor_request_display_mode, content from layer->data.view_count, mono-blit removed, single atlas→DP path).
Notes / risk
Not a bug fix — these paths work today (reliable flag + known tiles). This is an architectural-consistency + developer-flexibility refactor, and future-proofs any OOP variant of these APIs against what Android hit.
Medium-sized, low-risk; do per-API with on-device 2D/3D + switch + a custom-transition test (hold 3D content while requesting hardware-2D, and the MANUAL loss-of-tracking case).
Background
The Android single-app OOP path was fixed in #541 to decouple two independent concerns that were fused into one
hardware_display_3dflag:xrRequestDisplayRenderingModeEXT→request_display_mode, gated on whatdisplay_infoadvertises.While doing that I audited the other compositors. All five native compositors still conflate the two — a single
hardware_display_3dflag drives both the DP weave and clamps the content tile-count:This is harmless today because in-process (handle apps) the flag is set reliably by
request_display_mode, and the D3D11 service is driven by the workspace controller viaworkspace_request_display_mode(which crosses IPC) — and each renderer knows its own tile layout. It only broke on Android OOP, where the request was a no-op over IPC (so the flag was inferred from content and latched) andtile_columnswas the stale server mode. #541 fixed Android by making the hardware flag reliable (newcompositor_request_display_modeIPC) and taking content purely from the submission.Why this matters (not just consistency)
Developers need to switch hardware and content independently to author their own transitions. The
hardware_3d ? N : 1clamp removes that control: the hardware flag dictates the tile count, so the app can't, say, hold its 3D content while the panel goes flat, or run a custom cross-fade across the switch.This is most important in MANUAL eye-tracking mode (#522): there, the app owns the tracking-loss lifecycle. On an
XrEventDataEyeTrackingStateChangedEXTloss event the app should be free to craft its own response — e.g. drop the panel to 2D (flat, comfortable) immediately while it independently transitions its content (fade the parallax to zero over a few frames, then collapse to a single tile), or vice-versa. With hardware and content fused, none of that is expressible — the moment the app changes one, the runtime forces the other.Proposed work
Apply the #541 model uniformly to D3D11, D3D12, GL, Metal, and VK-native:
mode_3d(weave) from the hardware request (request_display_mode), recorded as a dedicated weave-state — not re-derived from the submitted view count.imageRects), not from the hardware flag.hardware_3d ? N : 1clamp; let the DP weave (hardware-3D) or show the tiles flat (hardware-2D) regardless of how many tiles arrive — so a hardware/content mismatch during a custom transition renders predictably instead of being clamped away.Reference implementation:
comp_multi_system.crender path in #541 (hardware frommulti_compositor_request_display_mode, content fromlayer->data.view_count, mono-blit removed, single atlas→DP path).Notes / risk
Refs: #538, #541, DisplayXR/displayxr-leia-plugin#90 (MANUAL/MANAGED eye tracking).