commit 781550dd9b63ecda54c4cfd18938b1f6e1b0c21a
parent f9e8de8a43182b5ecb9b11e6c9d0e3f413891a95
Author: umhau <umhau@example.invalid>
Date: Fri, 23 Oct 2026 12:00:01 +0000
Document native desktop bring-up alongside the stereo cube demo
Diffstat:
2 files changed, 54 insertions(+), 12 deletions(-)
diff --git a/SETUP.md b/SETUP.md
@@ -49,26 +49,63 @@ Side effect: HDCP-protected content (some streaming video to external displays)
3. macOS asks **"Allow accessory to connect?"**. Click **Allow**. Until you do, all HID calls fail with
`0xe00002cd` (kIOReturnNotOpen).
-### 4. Wake the headset over USB HID
+### 4. Build the two demonstrations
```sh
-cd tools && ./hmdwake # leave running; Ctrl-C to quit
+zsh tools/build.sh
```
-It sends (ported from Monado's `wmr_hmd_activate_reverb`):
+Run this from the repository root. It builds the stereo application, recovery helper,
+USB wake tool, and passive display observer using Apple's Command Line Tools.
+
+### 5. Native macOS desktop output
+
+Quit the stereo application first, then run:
+
+```sh
+.build/debug/hmdwake # leave running; Ctrl-C to quit
+```
+
+macOS treats the headset as an external display. In System Settings > Displays,
+choose the headset and use it as an extended display or select mirroring. Any
+windows placed on that display are sent directly to the headset by macOS.
+
+This reproduces the original desktop-output breakthrough. The operating system
+sends one desktop image across the headset's display surface: it does not duplicate
+the desktop for each eye or apply the demo renderer's lens correction. This is
+display bring-up, rather than a comfortable stereo desktop workspace.
+
+For a passive connection/mode check, run this in another terminal:
+
+```sh
+.build/debug/displaywatch # Ctrl-C to quit
+```
+
+It reports display connections and pixel modes without capturing desktop pixels.
+Its output includes display metadata and timestamps; review it before sharing logs.
+Seeing a connected display in software is separate from confirming illumination
+and the desktop image inside the headset. The standalone wake tool does not run
+the stereo application's automatic link recovery.
+
+The wake tool sends (ported from Monado's `wmr_hmd_activate_reverb`):
- To the QHMD control device `03f0:0c6a` (feature reports):
4x set `[0x50, 0x01]` + get `0x50`, then get `0x09`, `0x08`, `0x06`, then set `[0x04, 0x01]` (screen on).
- To the HoloLens Sensors device `045e:0659` (output report): `[0x02, 0x07]` + zero pad to 64 bytes (IMU on).
Within ~1.5 s the DP link trains (HBR3, 8.1 Gbps x 4 lanes), macOS adds the 4320x2160 display, and the headset
reports `05 01 01 01 01 ...` (panel on). (Drops can still occur later; see NOTES.md "Link reliability".)
-The app (step 5) does this wake itself; `hmdwake` is only for diagnostics. Don't run both.
+Stop `hmdwake` with Ctrl-C before starting the stereo demo. The application sends
+the wake sequence itself; the two programs must not own the HID devices together.
-### 5. Build and run the app (owns the headset, recovers it automatically)
+### 6. Stereo 3D demo (owns the headset, recovers it automatically)
```sh
-zsh tools/build.sh # builds the app + the signed recovery helper
-.build/debug/VRWorkstation --run-seconds 600 # run for 10 minutes (omit for indefinite)
+.build/debug/VRWorkstation --run-seconds 600 # run for 10 minutes; omit the option for indefinite
```
+Look for a rotating colored cube, a floor grid, and reference objects at several
+depths. Each eye receives its own rendered view through the factory lens correction.
+The Headset optics window on the Mac provides pattern/tuning controls and Quit.
+This demo uses a fixed viewpoint; head tracking is not connected to this scene.
+
- `tools/build.sh` builds the app with `swift build`, then compiles `tools/hpmctl.c` into the same directory as the app
- executable (`swift build --show-bin-path`) and ad-hoc signs it with `tools/hpmctl.entitlements`
+ executable (`.build/debug`) and ad-hoc signs it with `tools/hpmctl.entitlements`
(`com.apple.USBCEntitlement`).
- The app runs as a normal non-root user. When the headset display is lost and does not return within a 2 s
grace period, it runs that helper directly to send a USB-PD Data Reset to port 2's controller. No sudo, no password:
@@ -141,12 +178,12 @@ zsh tools/build.sh # builds the app + the signe
Judge the display by the native mode in use and actual Metal presentation counts, not by this byte.
## Tools (`tools/`)
-- `hmdwake`: wake sequence + IMU on; logs status reports. `passive` arg = listen only. SIGUSR1 = screen on.
-- `displaywatch`: passively logs display add/remove (CoreGraphics callbacks).
+- `hmdwake` (`.build/debug/hmdwake`): wake sequence + IMU on, exposing native desktop output. Feature/control payloads are omitted from logs. `passive` arg = listen only. SIGUSR1 = screen on.
+- `displaywatch` (`.build/debug/displaywatch`): passively logs display add/remove (CoreGraphics callbacks); does not capture screen pixels.
- Never poll `ioreg -c IOPortTransportStateDisplayPort` (the old `linkwatch.sh` did; removed).
- `testpattern`: red LEFT / blue RIGHT fullscreen pattern on the headset.
- `verify.sh`: passive one-shot check (boot-args + summaries of existing logs). No ioreg/system_profiler/HID. Launches nothing.
-- `build.sh`: builds the app and the signed `hpmctl` helper beside it (SETUP step 5).
+- `build.sh`: builds the app, signed `hpmctl` helper, `hmdwake`, and `displaywatch` together (step 4).
- `hpmctl` / `recovery_trials.py` / the app's LinkRecovery helper: see NOTES.md "Link reliability" (vr0 owns these).
### Optical tuning window
diff --git a/tools/build.sh b/tools/build.sh
@@ -3,8 +3,13 @@
set -euo pipefail
cd "$(dirname "$0")/.."
swift build
-vr_bin_dir=$(swift build --show-bin-path)
+# SwiftPM exposes the default configuration through this relative symlink.
+vr_bin_dir=".build/debug"
clang -Wall -Wextra -O2 -framework IOKit -framework CoreFoundation tools/hpmctl.c -o "$vr_bin_dir/hpmctl"
codesign --force --sign - --entitlements tools/hpmctl.entitlements "$vr_bin_dir/hpmctl"
+swiftc tools/hmdwake.swift -framework IOKit -o "$vr_bin_dir/hmdwake"
+swiftc tools/displaywatch.swift -o "$vr_bin_dir/displaywatch"
print "App: $vr_bin_dir/VRWorkstation"
print "Recovery helper: $vr_bin_dir/hpmctl"
+print "Native desktop: $vr_bin_dir/hmdwake"
+print "Passive display observer: $vr_bin_dir/displaywatch"