Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ former `displayxr-unity-test*` repos (history preserved via `git subtree`).

Samples:
- `samples/birp-multipass` — Built-in RP, multi-pass stereo. Key `BiRPMultiPass`.
- `samples/urp-singlepass-ui` — URP single-pass + `XrCompositionLayerWindowSpaceEXT` 2D UI. Key `URPSinglePassUI`.
- `samples/urp-singlepass-ui` — URP single-pass + `XrCompositionLayerWindowSpaceDXR` 2D UI. Key `URPSinglePassUI`.
- `samples/hdrp-singlepass-ui` — HDRP single-pass + 2D UI. Key `HDRPSinglePassUI`.
- `samples/desktop-avatar` — URP Desktop Avatar showcase (transparency, click-through, per-eye foreground clip, `XR_EXT_display_zones`). Key `DesktopAvatar`.
- `samples/desktop-avatar` — URP Desktop Avatar showcase (transparency, click-through, per-eye foreground clip, `XR_DXR_display_zones`). Key `DesktopAvatar`.

## The installer is shared — never fork it

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ Avatar** feature showcase.
| Sample | Folder | Render pipeline / mode | Highlights |
|---|---|---|---|
| **BiRP Multi-Pass** | `samples/birp-multipass` | Built-in RP, multi-pass stereo | Baseline cube + rig-switching demo |
| **URP Single-Pass + 2D UI** | `samples/urp-singlepass-ui` | URP, single-pass instanced | `XrCompositionLayerWindowSpaceEXT` 2D UI overlay |
| **URP Single-Pass + 2D UI** | `samples/urp-singlepass-ui` | URP, single-pass instanced | `XrCompositionLayerWindowSpaceDXR` 2D UI overlay |
| **HDRP Single-Pass + 2D UI** | `samples/hdrp-singlepass-ui` | HDRP, single-pass instanced | Same UI overlay as URP, on HDRP |
| **Desktop Avatar** | `samples/desktop-avatar` | URP | Alpha-native transparency, click-through, per-eye foreground clip, `XR_EXT_display_zones` (3D zone + Local2D) |
| **Desktop Avatar** | `samples/desktop-avatar` | URP | Alpha-native transparency, click-through, per-eye foreground clip, `XR_DXR_display_zones` (3D zone + Local2D) |

## Prerequisites

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ MonoBehaviour:
nameUi: DisplayXR
version: 0.1.0
featureIdInternal: com.displayxr.unity.feature
openxrExtensionStrings: XR_EXT_display_info XR_EXT_win32_window_binding XR_EXT_cocoa_window_binding
XR_EXT_atlas_capture
openxrExtensionStrings: XR_DXR_display_info XR_DXR_win32_window_binding XR_DXR_cocoa_window_binding
XR_DXR_atlas_capture
company: DisplayXR
priority: 0
targetOpenXRApiVersion:
Expand Down
2 changes: 1 addition & 1 deletion samples/desktop-avatar/Assets/TigerHudMouseRouter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// Input router for TigerTuningHUD's window-space-layer canvas.
//
// XrCompositionLayerWindowSpaceEXT submits pixels; it doesn't carry input.
// XrCompositionLayerWindowSpaceDXR submits pixels; it doesn't carry input.
// The wsui canvas is a private WorldSpace canvas on a hidden layer at
// (0, 100000, 0), so Unity's EventSystem can't naturally see clicks on it.
//
Expand Down
4 changes: 2 additions & 2 deletions samples/desktop-avatar/Assets/TigerSpeechBubble.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/// simple-window mode), split into two horizontal bands by
/// <see cref="bubbleBandFraction"/> (default 0.25 = avatar's top-25% bubble /
/// bottom-75% tiger):
/// - 3D tiger zone = the bottom band → pushed as the XR_EXT_display_zones
/// - 3D tiger zone = the bottom band → pushed as the XR_DXR_display_zones
/// 3D-zone rect (and the legacy canvas sub-rect, for older runtimes /
/// the silhouette mapping). The runtime Kooima-frames the tiger into it.
/// - 2D bubble band = the top band → a DisplayXRLocal2D layer composited
Expand Down Expand Up @@ -376,7 +376,7 @@ void ApplyLayout()
private void PushCanvasRect(int x, int y, int w, int h)
{
if (w <= 0 || h <= 0) return;
// XR_EXT_display_zones: push the 3D-zone rect so the runtime Kooima-frames
// XR_DXR_display_zones: push the 3D-zone rect so the runtime Kooima-frames
// the tiger INTO this rect (the rect IS the canvas). The provider drives the
// zone; the silhouette/click-through separately reads the canvas rect, so
// push both.
Expand Down
4 changes: 2 additions & 2 deletions samples/desktop-avatar/Assets/TransparentAutoSetup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
public static class TransparentAutoSetup
{
// Must run BEFORE the OpenXR session is created — that's when the runtime
// reads transparentBackgroundEnabled off XrWin32WindowBindingCreateInfoEXT
// (Windows) / XrCocoaWindowBindingCreateInfoEXT (macOS) and decides
// reads transparentBackgroundEnabled off XrWin32WindowBindingCreateInfoDXR
// (Windows) / XrCocoaWindowBindingCreateInfoDXR (macOS) and decides
// whether to use the transparent-capable swapchain path. AfterSceneLoad
// is too late; SubsystemRegistration fires earlier than the XR loader init.
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ MonoBehaviour:
nameUi: DisplayXR
version: 0.1.0
featureIdInternal: com.displayxr.unity.feature
openxrExtensionStrings: XR_EXT_display_info XR_EXT_win32_window_binding XR_EXT_cocoa_window_binding
XR_EXT_atlas_capture XR_EXT_view_rig XR_EXT_local_3d_zone XR_EXT_display_zones
openxrExtensionStrings: XR_DXR_display_info XR_DXR_win32_window_binding XR_DXR_cocoa_window_binding
XR_DXR_atlas_capture XR_DXR_view_rig XR_DXR_local_3d_zone XR_DXR_display_zones
company: DisplayXR
priority: 0
targetOpenXRApiVersion:
Expand Down
2 changes: 1 addition & 1 deletion samples/desktop-avatar/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ All test-project components are runtime-wired by `TransparentAutoSetup` — ther

The mechanism splits across plugin (most of it) and test-project (small bootstrap):

1. **Transparent session** — `TransparentAutoSetup.RequestTransparentSession()` (called from `[RuntimeInitializeOnLoadMethod(SubsystemRegistration)]`) tells the plugin to ask for a transparent OpenXR session. The plugin sets `xsi.transparentBackgroundEnabled` on `XrWin32WindowBindingCreateInfoEXT` and opts the session into `XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND` so Unity emits per-pixel alpha into the swapchain.
1. **Transparent session** — `TransparentAutoSetup.RequestTransparentSession()` (called from `[RuntimeInitializeOnLoadMethod(SubsystemRegistration)]`) tells the plugin to ask for a transparent OpenXR session. The plugin sets `xsi.transparentBackgroundEnabled` on `XrWin32WindowBindingCreateInfoDXR` and opts the session into `XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND` so Unity emits per-pixel alpha into the swapchain.
2. **Alpha-native camera clear** — the overlay's `OnEnable` flips the camera to `CameraClearFlags.SolidColor` with `backgroundColor = (0,0,0,0)` so transparent regions emit `alpha=0` directly. No chroma color is involved anywhere. (Older plugin versions painted a gray chroma color and relied on a runtime post-weave conversion pass; that workaround was removed once the runtime's compose-under-bg + alpha-gate DP path shipped — tracked in `DisplayXR/displayxr-unity#103`.)
3. **Per-pixel-alpha overlay HWND** — the plugin creates the overlay as a top-level `WS_POPUP` with `WS_EX_NOREDIRECTIONBITMAP`, so DWM has no opaque redirection surface and composites the HWND purely from the runtime's DComp visuals (real per-pixel alpha against the desktop). The runtime DP composes the captured desktop content under each tile pre-weave and alpha-gates post-weave, so anti-aliased silhouettes carry true soft alpha. The plugin explicitly strips `WS_EX_LAYERED` off Unity's HWND and does **not** call `SetLayeredWindowAttributes` / `LWA_COLORKEY`.
4. **Per-pixel click-through** — `WM_NCHITTEST` in the native overlay reads `s_hit_active` (set by the C# polling code each frame). When the cyclopean ray hits the tiger silhouette → `s_hit_active=1` → `HTCLIENT` → overlay captures. Otherwise `HTTRANSPARENT` → click forwards to the underlying app via `forward_click_to_underlying_window` (`SetForegroundWindow` + `PostMessage`).
Expand Down
2 changes: 1 addition & 1 deletion samples/desktop-avatar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ see-through desktop avatar (cartoon tiger) rendered over the live screen on
- **Alpha-native transparency** (the avatar composites over whatever is behind it)
- **Click-through** — input passes to the apps beneath the transparent regions
- **Per-eye foreground clipping**
- **`XR_EXT_display_zones`** layout — the avatar is Kooima-projected into a 3D
- **`XR_DXR_display_zones`** layout — the avatar is Kooima-projected into a 3D
zone, with a **Local2D** speech-bubble zone alongside it

Part of the [displayxr-unity-samples](https://github.com/DisplayXR/displayxr-unity-samples)
Expand Down
2 changes: 1 addition & 1 deletion samples/desktop-avatar/URP_FOREGROUND_CLIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ a URP-guarded assembly) so every app gets per-eye URP foreground clip for free.
## Validation status (2026-06-14, Win64 / RTX 3080 / D3D12)

Headless build + run on this machine against the installed DisplayXR runtime
(active OpenXR runtime, advertises **`XR_EXT_view_rig` Version=2**):
(active OpenXR runtime, advertises **`XR_DXR_view_rig` Version=2**):

- ✅ C# + shader compile clean; `DisplayXR/ForegroundClipURP` is built into the Player.
- ✅ `URPSetupBootstrap` creates the URP pipeline (depth texture on); Built-in→URP
Expand Down
6 changes: 3 additions & 3 deletions samples/desktop-avatar/docs~/issue-82-hud.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ What we already know (from the v1.3.0 repro, see #82 for the full log tail):
- In transparent mode, the `FINALv2` projection log shows all-zero values
(FOV=0°, pos=0,0,0). Possibly a symptom of the same broken composition
path, possibly unrelated — worth checking either way.
- `xrCreateSession` injects `XrWin32WindowBindingCreateInfoEXT` with
- `xrCreateSession` injects `XrWin32WindowBindingCreateInfoDXR` with
`transparentBackgroundEnabled=1` and a non-zero `chromaKeyColor`. That
selects the runtime's BitBlt (D3D11) or DComp (D3D12) swapchain path.
- `wsui_hooked` separately calls `xrCreateSwapchain` for the overlay layer
with format 28 (`DXGI_FORMAT_R8G8B8A8_UNORM`) and usage `COLOR_ATTACHMENT
| SAMPLED`. That swapchain isn't part of the transparent BitBlt path.
- `hooked_xrEndFrame` extends the original layer array with the wsui layer
via `XrCompositionLayerWindowSpaceEXT` and forwards to the runtime's
via `XrCompositionLayerWindowSpaceDXR` and forwards to the runtime's
real `xrEndFrame`. The first such forwarded call is what dies.

Probable causes (in rough likelihood order):
Expand All @@ -57,7 +57,7 @@ Probable causes (in rough likelihood order):
transparent path leaves the main swapchain in. The `wsui_copy_to_swapchain_image`
path in `native~/displayxr_d3d12_backend.cpp` relies on D3D12 common-state
implicit promotion — may not hold under transparent compositor.
2. The runtime can't compose an `XrCompositionLayerWindowSpaceEXT` over a
2. The runtime can't compose an `XrCompositionLayerWindowSpaceDXR` over a
transparent-background main layer; the layer-mixer code path was only
exercised against opaque sessions. This would be a runtime-side bug —
investigation may need to touch `DisplayXR/displayxr-runtime`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
!define SAMPLE_PRODUCT_EXE "DisplayXR-DesktopAvatar"
!define SAMPLE_DISPLAY_NAME "DisplayXR Unity Sample - Desktop Avatar"
!define SAMPLE_SLUG "unity_desktop_avatar"
!define SAMPLE_DESCRIPTION "Desktop avatar showcase - alpha-native transparency, click-through, per-eye foreground clip, and XR_EXT_display_zones (3D zone + Local2D speech bubble)."
!define SAMPLE_DESCRIPTION "Desktop avatar showcase - alpha-native transparency, click-through, per-eye foreground clip, and XR_DXR_display_zones (3D zone + Local2D speech bubble)."

!ifndef VERSION
!define VERSION "1.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// Sample input router for DisplayXRWindowSpaceUI — NOT part of the plugin.
//
// `XrCompositionLayerWindowSpaceEXT` submits pixels and lets the runtime
// `XrCompositionLayerWindowSpaceDXR` submits pixels and lets the runtime
// composite them; it doesn't carry input. Unity's GraphicRaycaster works on
// screen-space mouse coords against canvases that live in the screen's
// coordinate space — but our wsui canvas is a private WorldSpace canvas
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,8 +295,8 @@ MonoBehaviour:
nameUi: DisplayXR
version: 0.1.0
featureIdInternal: com.displayxr.unity.feature
openxrExtensionStrings: XR_EXT_display_info XR_EXT_win32_window_binding XR_EXT_cocoa_window_binding
XR_EXT_atlas_capture XR_EXT_view_rig XR_EXT_local_3d_zone XR_EXT_display_zones
openxrExtensionStrings: XR_DXR_display_info XR_DXR_win32_window_binding XR_DXR_cocoa_window_binding
XR_DXR_atlas_capture XR_DXR_view_rig XR_DXR_local_3d_zone XR_DXR_display_zones
company: DisplayXR
priority: 0
targetOpenXRApiVersion:
Expand Down
2 changes: 1 addition & 1 deletion samples/hdrp-singlepass-ui/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Two test-project scripts plus an editor bootstrap. The plugin contributes the ri
The mechanism is shared between plugin and test-project:

1. **Layer build (`DisplayXRTuningUI.OnEnable`):** creates a `Canvas` (`ScreenSpaceOverlay` initially), attaches `DisplayXRWindowSpaceUI` with fractional placement (`panelX`, `panelY`, `panelWidth`, `panelHeight`) and a fixed RT resolution of 1024 × 1024. The wsui flips the canvas to `WorldSpace`, parks it at `(0, 100000, 0)` on a hidden layer, and spins up an `OverlayCamera` that renders the canvas into its private RT.
2. **Composition layer submission (plugin native):** each frame the plugin grabs the RT, hands it to the runtime as an `XrCompositionLayerWindowSpaceEXT` payload, and the runtime composes it on top of the stereo scene with the configured per-eye `disparity`.
2. **Composition layer submission (plugin native):** each frame the plugin grabs the RT, hands it to the runtime as an `XrCompositionLayerWindowSpaceDXR` payload, and the runtime composes it on top of the stereo scene with the configured per-eye `disparity`.
3. **Input bridge (`DisplayXRWsuiMouseRouter.Update`):** EventSystem can't see the wsui canvas because it's at world-space-far-away with no main-camera coverage. Router reads cursor coords from `DisplayXRPreviewInput` (editor) or `Input` (built), tests the wsui rect, maps to canvas-pixel coords, and dispatches `pointerDown` / `drag` / `pointerUp` / `pointerClick` directly via `ExecuteEvents`. It also strips any pre-existing `StandaloneInputModule` from `EventSystem.current` — that module throws every frame on the new Input System Package and corrupts EventSystem state for `GraphicRaycaster`.
4. **Render-mode enumeration:** `DisplayXRTuningUI.TryEnumerateModes` calls `displayxr_standalone_enumerate_rendering_modes` (DllImport on `displayxr_unity`) to populate the cycle button. Retried from `Update` until the standalone session is up. Names come from `displayxr_standalone_get_rendering_mode_name`; synthesized fallback for older runtimes.

Expand Down
2 changes: 1 addition & 1 deletion samples/hdrp-singlepass-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The **HDRP** counterpart of the URP Single-Pass + 2D UI sample for the
[DisplayXR Unity plugin](https://github.com/DisplayXR/displayxr-unity). Same
window-space 2D UI overlay (`DisplayXRWindowSpaceUI` via
`XrCompositionLayerWindowSpaceEXT`) and single-pass instanced stereo, rendered
`XrCompositionLayerWindowSpaceDXR`) and single-pass instanced stereo, rendered
through the High Definition Render Pipeline — used to catch HDRP-specific
off-axis / projection regressions.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//
// Sample input router for DisplayXRWindowSpaceUI — NOT part of the plugin.
//
// `XrCompositionLayerWindowSpaceEXT` submits pixels and lets the runtime
// `XrCompositionLayerWindowSpaceDXR` submits pixels and lets the runtime
// composite them; it doesn't carry input. Unity's GraphicRaycaster works on
// screen-space mouse coords against canvases that live in the screen's
// coordinate space — but our wsui canvas is a private WorldSpace canvas
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,8 +296,8 @@ MonoBehaviour:
nameUi: DisplayXR
version: 0.1.0
featureIdInternal: com.displayxr.unity.feature
openxrExtensionStrings: XR_EXT_display_info XR_EXT_win32_window_binding XR_EXT_cocoa_window_binding
XR_EXT_atlas_capture XR_EXT_view_rig XR_EXT_local_3d_zone XR_EXT_display_zones
openxrExtensionStrings: XR_DXR_display_info XR_DXR_win32_window_binding XR_DXR_cocoa_window_binding
XR_DXR_atlas_capture XR_DXR_view_rig XR_DXR_local_3d_zone XR_DXR_display_zones
company: DisplayXR
priority: 0
targetOpenXRApiVersion:
Expand Down
4 changes: 2 additions & 2 deletions samples/urp-singlepass-ui/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Guidance for Claude Code when working in this repository.

## Project Overview

This is the **window-space 2D UI test project** for the displayxr-unity plugin — exercises the `DisplayXRWindowSpaceUI` component, which submits a Unity `Canvas` as an `XrCompositionLayerWindowSpaceEXT` composition layer through the DisplayXR OpenXR runtime. Sibling Unity project that consumes the `com.displayxr.unity` UPM package.
This is the **window-space 2D UI test project** for the displayxr-unity plugin — exercises the `DisplayXRWindowSpaceUI` component, which submits a Unity `Canvas` as an `XrCompositionLayerWindowSpaceDXR` composition layer through the DisplayXR OpenXR runtime. Sibling Unity project that consumes the `com.displayxr.unity` UPM package.

The scene (`Assets/CubeTest.unity`) renders an animated cube on a tracked 3D display and overlays a **runtime-built tuning panel** (IPD slider, Scale slider, Render Mode cycle button) submitted as a window-space layer. The panel survives without Play Mode — `[ExecuteAlways]` keeps it alive under the editor's standalone preview window flow.

Expand Down Expand Up @@ -63,7 +63,7 @@ Two test-project scripts plus an editor bootstrap. The plugin contributes the ri
The mechanism is shared between plugin and test-project:

1. **Layer build (`DisplayXRTuningUI.OnEnable`):** creates a `Canvas` (`ScreenSpaceOverlay` initially), attaches `DisplayXRWindowSpaceUI` with fractional placement (`panelX`, `panelY`, `panelWidth`, `panelHeight`) and a fixed RT resolution of 1024 × 1024. The wsui flips the canvas to `WorldSpace`, parks it at `(0, 100000, 0)` on a hidden layer, and spins up an `OverlayCamera` that renders the canvas into its private RT.
2. **Composition layer submission (plugin native):** each frame the plugin grabs the RT, hands it to the runtime as an `XrCompositionLayerWindowSpaceEXT` payload, and the runtime composes it on top of the stereo scene with the configured per-eye `disparity`.
2. **Composition layer submission (plugin native):** each frame the plugin grabs the RT, hands it to the runtime as an `XrCompositionLayerWindowSpaceDXR` payload, and the runtime composes it on top of the stereo scene with the configured per-eye `disparity`.
3. **Input bridge (`DisplayXRWsuiMouseRouter.Update`):** EventSystem can't see the wsui canvas because it's at world-space-far-away with no main-camera coverage. Router reads cursor coords from `DisplayXRPreviewInput` (editor) or `Input` (built), tests the wsui rect, maps to canvas-pixel coords, and dispatches `pointerDown` / `drag` / `pointerUp` / `pointerClick` directly via `ExecuteEvents`. It also strips any pre-existing `StandaloneInputModule` from `EventSystem.current` — that module throws every frame on the new Input System Package and corrupts EventSystem state for `GraphicRaycaster`.
4. **Render-mode enumeration:** `DisplayXRTuningUI.TryEnumerateModes` calls `displayxr_standalone_enumerate_rendering_modes` (DllImport on `displayxr_unity`) to populate the cycle button. Retried from `Update` until the standalone session is up. Names come from `displayxr_standalone_get_rendering_mode_name`; synthesized fallback for older runtimes.

Expand Down
2 changes: 1 addition & 1 deletion samples/urp-singlepass-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Sample for the [DisplayXR Unity plugin](https://github.com/DisplayXR/displayxr-unity)
on **URP** (single-pass instanced stereo) that exercises the **window-space 2D UI
overlay** feature (`DisplayXRWindowSpaceUI`, plumbed through
`XrCompositionLayerWindowSpaceEXT` in the runtime). The scene renders a textured
`XrCompositionLayerWindowSpaceDXR` in the runtime). The scene renders a textured
cube on a tracked 3D display and overlays a runtime-built UI panel (IPD slider,
virtual-display-height slider, render-mode cycle button) as a window-space
composition layer.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
!define SAMPLE_PRODUCT_EXE "DisplayXR-URP-SinglePass-UI"
!define SAMPLE_DISPLAY_NAME "DisplayXR Unity Sample - URP Single-Pass + 2D UI"
!define SAMPLE_SLUG "unity_urp_singlepass_ui"
!define SAMPLE_DESCRIPTION "URP single-pass instanced stereo with an XrCompositionLayerWindowSpaceEXT 2D UI overlay - DisplayXR provider test."
!define SAMPLE_DESCRIPTION "URP single-pass instanced stereo with an XrCompositionLayerWindowSpaceDXR 2D UI overlay - DisplayXR provider test."

!ifndef VERSION
!define VERSION "1.0.0"
Expand Down