mirror of
https://github.com/daniel-lynch/ovrplugin-openxr-shim.git
synced 2026-10-06 01:00:05 +02:00
An independent reimplementation of Meta's libOVRPlugin ABI on top of OpenXR, so VrApi-era Meta Quest VR titles can run on non-Meta OpenXR runtimes (Monado, Steam Frame) instead of being locked to Meta hardware. Original code only — no Meta/Epic/Capcom binaries, headers, or assets. Includes a desktop harness that drives the shim against Monado headless. Scope/legal: interoperability; entitlement handling is out of scope. See README for the legal/scope section and docs/ for the research trail and design notes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D6sFYGXZPsq3v7xtcDES6g
63 lines
2.9 KiB
Bash
Executable File
63 lines
2.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# run.sh — launch the desktop harness against Monado's simulated HMD, headless.
|
|
#
|
|
# Brings up monado-service with the NULL compositor (no display needed -> works over SSH /
|
|
# in CI), points the OpenXR loader at Monado, then runs the harness which drives the shim's
|
|
# ovrp_* -> OpenXR path. Output: build/host/monado.log + build/host/harness.log.
|
|
#
|
|
# Prereqs (Debian/Ubuntu): sudo apt-get install monado-service libopenxr1-monado \
|
|
# libopenxr-loader1 libopenxr-dev
|
|
# Build first: shim/build_host.sh
|
|
set -uo pipefail
|
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
OUT="$ROOT/build/host"
|
|
FRAMES="${1:-300}"
|
|
|
|
[ -x "$OUT/harness" ] || { echo "no $OUT/harness — run shim/build_host.sh first"; exit 1; }
|
|
|
|
# Point the loader at Monado explicitly (in case another runtime is also registered).
|
|
MONADO_JSON="$(ls /usr/share/openxr/1/openxr_monado*.json 2>/dev/null | head -1 || true)"
|
|
[ -n "$MONADO_JSON" ] && export XR_RUNTIME_JSON="$MONADO_JSON"
|
|
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/tmp/re4vr-monado-rt}"
|
|
mkdir -p "$XDG_RUNTIME_DIR"
|
|
|
|
# Simulated HMD driver is auto-selected when no real hardware is present.
|
|
# Default = headless: NULL compositor renders to nothing, so it needs no X/Wayland (SSH/CI).
|
|
# VISIBLE=1 = windowed: the main compositor opens a mirror window + Monado's imgui debug GUI
|
|
# (swapchain preview), so you can WATCH the harness's animated eye fill. Needs a display, so
|
|
# run it from the physical desktop session, not over SSH, and give it a big frame count to
|
|
# watch, e.g. VISIBLE=1 tools/desktop-harness/run.sh 3600
|
|
if [ "${VISIBLE:-0}" = 1 ]; then
|
|
export XRT_DEBUG_GUI=1
|
|
echo "VISIBLE mode: main compositor + debug GUI (needs DISPLAY/WAYLAND — run locally)"
|
|
else
|
|
export XRT_COMPOSITOR_NULL=1
|
|
fi
|
|
export QWERTY_ENABLE=0
|
|
export U_PACING_APP_USE_MIN_FRAME_PERIOD=1
|
|
|
|
SOCK="$XDG_RUNTIME_DIR/monado_comp_ipc"
|
|
rm -f "$SOCK"
|
|
# monado-service adds stdin to its epoll loop (for its "press a key to quit" handler).
|
|
# A redirected /dev/null or regular file isn't epoll-able -> epoll_ctl fails -> the IPC
|
|
# loop dies. Feed it a real FIFO held open by a writer that never sends data.
|
|
FIFO="$XDG_RUNTIME_DIR/monado_stdin"
|
|
rm -f "$FIFO"; mkfifo "$FIFO"
|
|
sleep 100000 >"$FIFO" &
|
|
HOLD=$!
|
|
echo "== starting monado-service (headless, NULL compositor) =="
|
|
monado-service <"$FIFO" >"$OUT/monado.log" 2>&1 &
|
|
SVC=$!
|
|
trap 'kill $SVC $HOLD 2>/dev/null; wait $SVC 2>/dev/null; rm -f "$FIFO"' EXIT
|
|
|
|
# wait up to ~10s for the IPC socket
|
|
for _ in $(seq 1 100); do [ -S "$SOCK" ] && break; kill -0 $SVC 2>/dev/null || { echo "monado-service died:"; cat "$OUT/monado.log"; exit 1; }; sleep 0.1; done
|
|
[ -S "$SOCK" ] || { echo "monado-service IPC socket never appeared:"; tail -20 "$OUT/monado.log"; exit 1; }
|
|
echo "monado-service up (pid $SVC)"
|
|
|
|
echo "== running harness ($FRAMES frames) =="
|
|
XRRLOG_STDERR=1 "$OUT/harness" "$FRAMES" 2>&1 | tee "$OUT/harness.log"
|
|
rc=${PIPESTATUS[0]}
|
|
echo "== harness exit: $rc =="
|
|
exit $rc
|