mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-04 22:00:08 +02:00
Steam Frame native build: patched Dawn for Linux, local-build VR options, docs
Launcher/build-dawn-linux.sh builds the pinned Dawn with Aurora's Vulkan hook and density map patches into a package local-build.sh takes through the new --dawn-package option, together with --openxr, --headset steam_frame and --cpu. docs/steam-frame.md now leads with the native SteamOS build (building in a podman container on the Frame, running it, the log lines to expect); OPENXR.md's backend table records the Linux Vulkan backend and why the Lepton flavour cannot present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3
This commit is contained in:
5 files changed
+327
-41
No files matched your search
Executable
+174
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
# Builds the pinned Dawn for desktop Linux with Aurora's patches (aurora-main/patches/dawn): the
|
||||
# Vulkan hooks through which the OpenXR runtime creates Dawn's own instance and device (the
|
||||
# same-device OpenXR backend, runtime/src/vr/openxr_vulkan_win32.cpp) and fragment density maps for
|
||||
# foveated rendering. The stock prebuilt package has neither. This is the Linux counterpart of
|
||||
# android/Build-QuestDawn.ps1, for the Steam Frame's native SteamOS build (docs/steam-frame.md).
|
||||
#
|
||||
# Launcher/build-dawn-linux.sh [--work-dir DIR] [--cc PATH --cxx PATH] [--cmake PATH]
|
||||
# [--ninja PATH] [--python PATH] [--jobs N] [--force]
|
||||
#
|
||||
# It builds for the machine it runs on (the Frame's aarch64, in a container there). Pass the same
|
||||
# --cc/--cxx as Launcher/local-build.sh gets: the archive is static and carries C++ objects, so it
|
||||
# must be built against the same C++ standard library as the game.
|
||||
#
|
||||
# The result is an install tree in the stock package's layout under WORK_DIR/package, with an
|
||||
# aurora-dawn.json declaring the two ABIs (AuroraVulkanAbi, AuroraFdmAbi) that
|
||||
# aurora-main/cmake/AuroraDawnProvider.cmake reads. local-build.sh --dawn-package takes it. A later
|
||||
# run with the same inputs reuses it.
|
||||
#
|
||||
# Prerequisites: git, python3, curl, tar, CMake 3.25+, Ninja, a C/C++ compiler, and the X11, XCB and
|
||||
# Wayland development headers Dawn's Vulkan surfaces need. The first build compiles all of Dawn and
|
||||
# Tint and takes a while.
|
||||
set -euo pipefail
|
||||
|
||||
fail() {
|
||||
echo "build-dawn-linux.sh: error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
repo=$(cd "$script_dir/.." && pwd)
|
||||
work_dir="$repo/.scratch/linux-dawn"
|
||||
cc_bin=${CC:-cc}
|
||||
cxx_bin=${CXX:-c++}
|
||||
cmake_bin=cmake
|
||||
ninja_bin=ninja
|
||||
python_bin=python3
|
||||
jobs=$(nproc)
|
||||
force=0
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--work-dir) work_dir=$2; shift 2 ;;
|
||||
--cc) cc_bin=$2; shift 2 ;;
|
||||
--cxx) cxx_bin=$2; shift 2 ;;
|
||||
--cmake) cmake_bin=$2; shift 2 ;;
|
||||
--ninja) ninja_bin=$2; shift 2 ;;
|
||||
--python) python_bin=$2; shift 2 ;;
|
||||
--jobs) jobs=$2; shift 2 ;;
|
||||
--force) force=1; shift ;;
|
||||
-h|--help) sed -n '2,24p' "$0"; exit 0 ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
for tool in "$cc_bin" "$cxx_bin" "$cmake_bin" "$ninja_bin" "$python_bin" git curl tar sha256sum; do
|
||||
command -v "$tool" >/dev/null 2>&1 || fail "required tool '$tool' was not found"
|
||||
done
|
||||
mkdir -p "$work_dir"
|
||||
work_dir=$(cd "$work_dir" && pwd)
|
||||
cc_path=$(command -v "$cc_bin")
|
||||
cxx_path=$(command -v "$cxx_bin")
|
||||
|
||||
# The revision the stock packages, the Windows Vulkan DLL (Launcher/Build-DawnVulkan.ps1) and the
|
||||
# Quest's Dawn (android/Build-QuestDawn.ps1) are built from.
|
||||
revision=13abc3bc8ea2d3c2050f9e77a12d012108ceee24
|
||||
archive_hash=713bea5b92d4f6c5175752fd7cbf1c3c5ce36598ff5dd98685d8a1216614ebba
|
||||
flags=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
|
||||
-DDAWN_FETCH_DEPENDENCIES=ON
|
||||
-DDAWN_BUILD_MONOLITHIC_LIBRARY=STATIC
|
||||
-DBUILD_SHARED_LIBS=OFF
|
||||
-DDAWN_ENABLE_INSTALL=ON
|
||||
-DDAWN_BUILD_SAMPLES=OFF
|
||||
-DDAWN_BUILD_TESTS=OFF
|
||||
-DDAWN_BUILD_BENCHMARKS=OFF
|
||||
-DDAWN_USE_GLFW=OFF
|
||||
-DDAWN_USE_WAYLAND=ON
|
||||
-DDAWN_ENABLE_DESKTOP_GL=OFF
|
||||
-DDAWN_ENABLE_OPENGLES=OFF
|
||||
-DTINT_BUILD_TESTS=OFF
|
||||
-DTINT_BUILD_CMD_TOOLS=OFF
|
||||
-DTINT_BUILD_IR_BINARY=OFF
|
||||
-DDAWN_BUILD_PROTOBUF=OFF
|
||||
)
|
||||
|
||||
patch_dir="$repo/aurora-main/patches/dawn"
|
||||
patch_files=(
|
||||
"$patch_dir/apply.py"
|
||||
"$patch_dir/aurora_vulkan_hooks.h"
|
||||
"$patch_dir/aurora_vulkan_interop.inc"
|
||||
"$patch_dir/aurora_fdm.h"
|
||||
"$patch_dir/aurora_fdm.inc"
|
||||
"$repo/aurora-main/include/aurora/dawn_vulkan_abi.h"
|
||||
"$repo/aurora-main/include/aurora/dawn_fdm_abi.h"
|
||||
)
|
||||
# Hashed with LF line endings and each file's name, as Build-QuestDawn.ps1 does.
|
||||
patch_hash=$(for file in "${patch_files[@]}"; do
|
||||
printf '%s\n' "$(basename "$file")"
|
||||
tr -d '\r' < "$file"
|
||||
done | sha256sum | awk '{print $1}')
|
||||
compiler_id=$("$cxx_path" --version 2>/dev/null | head -n 1 | tr -d '"\\')
|
||||
cache_key=$(printf '%s|%s|%s|%s|%s|%s' "$revision" "$archive_hash" "$patch_hash" "$(uname -m)" \
|
||||
"$compiler_id" "${flags[*]}" | sha256sum | awk '{print $1}')
|
||||
|
||||
package="$work_dir/package"
|
||||
manifest="$package/aurora-dawn.json"
|
||||
library="$package/lib/libwebgpu_dawn.a"
|
||||
[[ -f "$library" ]] || library="$package/lib64/libwebgpu_dawn.a"
|
||||
if [[ "$force" -eq 0 && -f "$manifest" && -f "$library" ]]; then
|
||||
library_hash=$(sha256sum "$library" | awk '{print $1}')
|
||||
if grep -q "\"CacheKey\": \"$cache_key\"" "$manifest" &&
|
||||
grep -q "\"ArchiveSha256\": \"$library_hash\"" "$manifest"; then
|
||||
echo "Patched Dawn for Linux is up to date: $package"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
archive="$work_dir/dawn-source.tar.gz"
|
||||
if [[ ! -f "$archive" ]]; then
|
||||
curl -fL --retry 3 -o "$archive.partial" "https://github.com/google/dawn/archive/$revision.tar.gz"
|
||||
mv "$archive.partial" "$archive"
|
||||
fi
|
||||
[[ "$(sha256sum "$archive" | awk '{print $1}')" == "$archive_hash" ]] ||
|
||||
fail "Dawn source archive does not match the pinned SHA-256; delete $archive and try again"
|
||||
|
||||
# The patches are applied to pristine sources: src/ is extracted again whenever the patches changed,
|
||||
# while third_party/, which DAWN_FETCH_DEPENDENCIES fills, is kept.
|
||||
source="$work_dir/dawn-$revision"
|
||||
patch_marker="$source/aurora-patches.sha256"
|
||||
if [[ ! -f "$patch_marker" || "$(cat "$patch_marker")" != "$patch_hash" ]]; then
|
||||
if [[ -d "$source" ]]; then
|
||||
rm -rf "$source/src"
|
||||
tar -xzf "$archive" -C "$work_dir" "dawn-$revision/src"
|
||||
else
|
||||
tar -xzf "$archive" -C "$work_dir"
|
||||
fi
|
||||
"$python_bin" "$patch_dir/apply.py" "$source"
|
||||
printf '%s' "$patch_hash" > "$patch_marker"
|
||||
fi
|
||||
|
||||
build="$work_dir/build"
|
||||
"$cmake_bin" -S "$source" -B "$build" -G Ninja \
|
||||
-DCMAKE_MAKE_PROGRAM="$(command -v "$ninja_bin")" \
|
||||
-DCMAKE_C_COMPILER="$cc_path" -DCMAKE_CXX_COMPILER="$cxx_path" \
|
||||
-DPython3_EXECUTABLE="$(command -v "$python_bin")" \
|
||||
"${flags[@]}" -DCMAKE_INSTALL_PREFIX="$package"
|
||||
"$cmake_bin" --build "$build" --parallel "$jobs"
|
||||
rm -rf "$package"
|
||||
"$cmake_bin" --install "$build"
|
||||
library="$package/lib/libwebgpu_dawn.a"
|
||||
[[ -f "$library" ]] || library="$package/lib64/libwebgpu_dawn.a"
|
||||
[[ -f "$library" ]] || fail "Dawn archive missing under $package"
|
||||
# As the stock package: debug info would only make the archive several times larger.
|
||||
strip_bin=$(dirname "$cc_path")/llvm-strip
|
||||
[[ -x "$strip_bin" ]] || strip_bin=strip
|
||||
"$strip_bin" --strip-debug "$library"
|
||||
|
||||
cat > "$manifest" <<EOF
|
||||
{
|
||||
"SourceRevision": "$revision",
|
||||
"SourceSha256": "$archive_hash",
|
||||
"PatchSha256": "$patch_hash",
|
||||
"AuroraVulkanAbi": 1,
|
||||
"AuroraFdmAbi": 1,
|
||||
"Platform": "linux-$(uname -m)",
|
||||
"Compiler": "$compiler_id",
|
||||
"Flags": "${flags[*]}",
|
||||
"CacheKey": "$cache_key",
|
||||
"ArchiveSha256": "$(sha256sum "$library" | awk '{print $1}')"
|
||||
}
|
||||
EOF
|
||||
echo "Patched Dawn for Linux ready: $package"
|
||||
@@ -66,6 +66,10 @@ translator_bin_override=""
|
||||
fuse_ld_override=""
|
||||
native_prebuilt_dir=""
|
||||
sysroot=""
|
||||
openxr=0
|
||||
dawn_package_dir=""
|
||||
headset=""
|
||||
linux_cpu=""
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
@@ -90,6 +94,14 @@ Usage: local-build.sh --output-dir DIR [options]
|
||||
skips compiling aurora-main from source entirely
|
||||
--sysroot PATH Passed to CMake as -DCMAKE_SYSROOT: where the compiler resolves
|
||||
standard headers/startup files
|
||||
--openxr Build the OpenXR VR support (the same-device Vulkan backend); needs
|
||||
--dawn-package, since the stock Dawn has no Vulkan hooks
|
||||
--dawn-package DIR A Dawn built with Aurora's patches (Launcher/build-dawn-linux.sh's
|
||||
WORK_DIR/package); build it with the same --cc/--cxx
|
||||
--headset NAME steam_frame: the Steam Frame's native SteamOS build and its defaults
|
||||
(docs/steam-frame.md); empty for any other PC headset
|
||||
--cpu NAME AArch64 -mcpu target (default: cortex-x4 with --headset steam_frame,
|
||||
else native)
|
||||
EOF
|
||||
}
|
||||
|
||||
@@ -114,6 +126,10 @@ while [[ $# -gt 0 ]]; do
|
||||
--translator-bin) translator_bin_override=$2; shift 2 ;;
|
||||
--native-prebuilt-dir) native_prebuilt_dir=$2; shift 2 ;;
|
||||
--sysroot) sysroot=$2; shift 2 ;;
|
||||
--openxr) openxr=1; shift ;;
|
||||
--dawn-package) dawn_package_dir=$(cd "$2" && pwd); shift 2 ;;
|
||||
--headset) headset=$2; shift 2 ;;
|
||||
--cpu) linux_cpu=$2; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
@@ -172,6 +188,18 @@ require_command "$cxx_bin" cxx
|
||||
if [[ -n "$native_prebuilt_dir" ]]; then
|
||||
assert_file "$native_prebuilt_dir/native_prebuilt.cmake" "Native prebuilt package"
|
||||
fi
|
||||
case "$headset" in
|
||||
""|steam_frame) ;;
|
||||
*) fail "--headset must be steam_frame or left out" ;;
|
||||
esac
|
||||
if [[ -n "$dawn_package_dir" ]]; then
|
||||
assert_file "$dawn_package_dir/aurora-dawn.json" "Patched Dawn package manifest (Launcher/build-dawn-linux.sh)"
|
||||
[[ -z "$native_prebuilt_dir" ]] ||
|
||||
fail "--dawn-package and --native-prebuilt-dir exclude each other: the prebuilt package carries its own Dawn"
|
||||
fi
|
||||
if [[ "$openxr" -eq 1 && -z "$dawn_package_dir" ]]; then
|
||||
fail "--openxr needs --dawn-package: the Linux OpenXR backend binds Dawn's own Vulkan device through Aurora's patches"
|
||||
fi
|
||||
|
||||
project=$workspace/projects/mkwii/recomp.yml
|
||||
assets=$workspace/Assets
|
||||
@@ -418,6 +446,24 @@ fi
|
||||
if [[ -n "$native_prebuilt_dir" ]]; then
|
||||
configure_args+=(-DMKW_NATIVE_PREBUILT_DIR="$native_prebuilt_dir")
|
||||
fi
|
||||
# VR and the headset are passed on every configure, so an incremental build never keeps a choice
|
||||
# from an earlier run.
|
||||
if [[ "$openxr" -eq 1 ]]; then
|
||||
configure_args+=(-DMKW_ENABLE_OPENXR=ON)
|
||||
else
|
||||
configure_args+=(-DMKW_ENABLE_OPENXR=OFF)
|
||||
fi
|
||||
configure_args+=(-DMKW_HEADSET="$headset")
|
||||
if [[ -n "$linux_cpu" ]]; then
|
||||
configure_args+=(-DMKW_LINUX_CPU="$linux_cpu")
|
||||
else
|
||||
configure_args+=(-UMKW_LINUX_CPU)
|
||||
fi
|
||||
if [[ -n "$dawn_package_dir" ]]; then
|
||||
configure_args+=(-DAURORA_DAWN_PROVIDER=package -DFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT="$dawn_package_dir")
|
||||
else
|
||||
configure_args+=(-UAURORA_DAWN_PROVIDER -UFETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT)
|
||||
fi
|
||||
if [[ -n "$sysroot" ]]; then
|
||||
configure_args+=(-DCMAKE_SYSROOT="$sysroot")
|
||||
else
|
||||
|
||||
@@ -1276,8 +1276,8 @@ custom DLL's ABI through three borrowed-image copy/readback cycles; run it with
|
||||
| Windows D3D12 | Implemented: same-adapter, same-device asynchronous OpenXR submission. |
|
||||
| Windows Vulkan | Implemented, opt-in (`video.graphics_api = "vulkan"`): the runtime creates Dawn's Vulkan instance and device through `XR_KHR_vulkan_enable2`, eyes are copied on the same queue, and Dawn's device guard is held around the four queue-touching OpenXR calls. Needs the custom Dawn from `Launcher/Build-DawnVulkan.ps1`. Raced on SteamVR/PSVR2 at the headset's full rate; other runtimes unexercised. See [Windows Vulkan](#windows-vulkan). |
|
||||
| Android Vulkan (Meta Quest) | Implemented and running on a Quest 3: the OpenXR side owns its own Vulkan device (`XR_KHR_vulkan_enable2`, `XR_KHR_vulkan_enable` fallback) and shares eyes with Dawn through `AHardwareBuffer`s ordered by sync-fd fences. Controllers arrive through OpenXR actions as a virtual SDL gamepad. See `docs/quest-port.md`. |
|
||||
| Android Vulkan (Steam Frame) | The same backend in the `steamFrame` flavour, for SteamVR's Android runtime under Lepton: Frame controller profile, 120 Hz request, eye-tracked foveation. Built and unit-tested, not yet run on the headset. See `docs/steam-frame.md`. |
|
||||
| Linux Vulkan | Not wired. The pinned Dawn package does not expose a native Vulkan device, and the AHardwareBuffer bridge is Android-only; a dma-buf/opaque-fd variant of the same design would cover desktop Linux. |
|
||||
| Android Vulkan (Steam Frame) | The same backend in the `steamFrame` flavour, for SteamVR's Android runtime under Lepton: Frame controller profile, 120 Hz request, eye-tracked foveation. Blocked on the headset: Lepton's Turnip exposes no AHardwareBuffer or fd external memory, so the eyes cannot cross devices. The native build below is the supported route. See `docs/steam-frame.md`. |
|
||||
| Linux Vulkan (Steam Frame, SteamOS) | Implemented, not yet run on the headset: the Windows Vulkan design compiled for Linux, so the runtime creates Dawn's own instance and device and the eyes are copied on Dawn's queue with no sharing. Adds the Frame controller profile, 120 Hz and gaze-centred foveation. Needs a Dawn built with Aurora's patches (`Launcher/build-dawn-linux.sh`), then `Launcher/local-build.sh --openxr --dawn-package <dir> --headset steam_frame`. See `docs/steam-frame.md`. |
|
||||
| Other platforms | Not wired yet. |
|
||||
|
||||
Both bindings share `openxr_integration.cpp`: the pacing thread, policy evaluation, the
|
||||
|
||||
@@ -57,7 +57,7 @@ to immersive stereo rendering. VR is opt-in and falls back to the normal desktop
|
||||
runtime or headset is unavailable. In first person you sit in the cockpit, where the steering wheel
|
||||
or handlebar turns with your steering, and hand steering by heurazy lets you grab it with the
|
||||
tracked controllers and turn it. On a Quest the hands can follow the headset's own hand tracking.
|
||||
A Steam Frame build of the Android app (not yet tested on the headset) adds the Frame controllers'
|
||||
A native SteamOS build for the Steam Frame (not yet tested on the headset) adds the Frame controllers'
|
||||
D-pad, a 120 Hz display for the game's 60 FPS, and foveation that follows your eyes; see
|
||||
[`docs/steam-frame.md`](docs/steam-frame.md).
|
||||
See [`OPENXR.md`](OPENXR.md) for setup, configuration, and the current limitations.
|
||||
|
||||
+104
-38
@@ -1,23 +1,112 @@
|
||||
# WiiCompiled VR on the Steam Frame
|
||||
|
||||
Valve's Steam Frame runs SteamOS on a Snapdragon 8 Gen 3 (Cortex-X4, A720 and A520 cores, Adreno 750),
|
||||
with 2160x2160 panels per eye at 72 to 144 Hz, eye tracking, and SteamVR as its OpenXR runtime. It runs
|
||||
Android apps through Lepton, SteamOS's Android layer, where SteamVR provides an Android OpenXR runtime
|
||||
(OpenXR 1.0, through the Khronos loader's runtime broker). The Steam Frame build is therefore a third
|
||||
flavour of the Quest app, `steamFrame`: everything in `docs/quest-port.md` below the app shell (the
|
||||
Vulkan backend, the game kit, `.wcgame` packages, the on-headset build) applies unchanged, and this
|
||||
document covers what differs.
|
||||
with 2160x2160 panels per eye at 72 to 144 Hz, eye tracking, and SteamVR as its OpenXR runtime. A game
|
||||
can run on it two ways, and this project has both:
|
||||
|
||||
A native SteamOS ARM64 build is a separate, later piece of work: Linux has no OpenXR graphics backend
|
||||
yet (see [A native SteamOS build](#a-native-steamos-build)).
|
||||
- **Natively on SteamOS** (Linux ARM64), with SteamVR's own OpenXR runtime. This is the Frame's build:
|
||||
[The native SteamOS build](#the-native-steamos-build) says how to make and run it.
|
||||
- **As an Android app in Lepton**, SteamOS's Android layer, as a third flavour of the Quest app
|
||||
(`steamFrame`). It is built, but it cannot show a picture there: Lepton's Vulkan driver has no
|
||||
external memory or sync fd extensions, and the Quest backend's two-device eye handoff needs them
|
||||
(see [What the Frame reported](#what-the-frame-reported)).
|
||||
|
||||
**Status: not yet run on a Steam Frame, and the Android backend as it stands cannot present under
|
||||
Lepton**: Lepton's Vulkan driver has no external memory or sync fd extensions, which the Quest
|
||||
backend's two-device design needs (see [What the Frame reported](#what-the-frame-reported)). The
|
||||
flavour, controller, refresh rate and foveation work below stays valid; the eye handoff has to move
|
||||
to a single shared device first.
|
||||
Most of what this document describes is shared by both: the Frame controller profile, the 120 Hz
|
||||
request, eye-tracked foveation and the Frame's defaults. The native build gets them through
|
||||
`MKW_HEADSET=steam_frame` (`MKW_HEADSET_STEAM_FRAME`), as the Android flavour does.
|
||||
|
||||
## What the flavour changes
|
||||
**Status: not yet run on a Steam Frame.** The native build's VR code compiles and the unit tests
|
||||
pass; building it on the Frame and the device checks are still to do.
|
||||
|
||||
## The native SteamOS build
|
||||
|
||||
The backend is the PC's same-device Vulkan backend (`openxr_vulkan_win32.cpp`, on Linux too): the
|
||||
OpenXR runtime creates Dawn's own Vulkan instance and device through Aurora's patches to Dawn, and
|
||||
each eye is copied into SteamVR's swapchain on Dawn's queue, so nothing is shared between devices.
|
||||
On Linux, Dawn links statically, so the patched Dawn is built once on the build machine
|
||||
(`Launcher/build-dawn-linux.sh`); `aurora-dawn.json` in its package declares the Vulkan hook and
|
||||
density map ABIs, and only against such a package does Aurora compile the bridge
|
||||
(`AURORA_DAWN_VULKAN_HOOKS`) and the density maps (`AURORA_DAWN_FDM`). Against a stock Dawn the
|
||||
build still links, and VR falls back to the desktop.
|
||||
|
||||
What the Frame build changes, beyond the Android flavour's settings:
|
||||
|
||||
- `-mcpu=cortex-x4` (`MKW_LINUX_CPU`, which `--cpu` overrides).
|
||||
- `AuroraConfig::xrHeadsetOnly`: Aurora neither presents the desktop window nor renders it past the
|
||||
last pass the eyes sample, as on Android (4 to 6 ms of a 12 ms GPU frame on a Quest 3).
|
||||
- Fragment density maps are asked for on Linux as on the Quest; `AURORA_FDM=0` or `1` overrides the
|
||||
settings, as `debug.wiicompiled.fdm` does there.
|
||||
- Controller motion uses `XR_KHR_convert_timespec_time` when SteamVR offers it.
|
||||
|
||||
### Building it on the Frame
|
||||
|
||||
SteamOS's root file system is read-only, so the build runs in a Debian container on the Frame,
|
||||
started with the `podman` SteamOS already ships. Over SSH (`ssh steamos@<frame-ip>`):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/wiicompiled && cd ~/wiicompiled
|
||||
git clone -b claude/peaceful-keller-2ek99b https://github.com/mitch030504/Wiicompiled_VR_Frame.git
|
||||
podman run -it --name wiicompiled-build -v ~/wiicompiled:/work:Z docker.io/library/debian:trixie bash
|
||||
```
|
||||
|
||||
Inside the container (`podman start -ai wiicompiled-build` gets back into it later):
|
||||
|
||||
```bash
|
||||
apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates curl git python3 xz-utils unzip file pkg-config g++ binutils libicu-dev zlib1g-dev \
|
||||
libvulkan-dev libx11-dev libx11-xcb-dev libxcb1-dev libxext-dev libxrandr-dev libxinerama-dev \
|
||||
libxcursor-dev libxi-dev libxss-dev libxtst-dev libxkbcommon-dev libwayland-dev wayland-protocols \
|
||||
libdecor-0-dev libegl-dev libgl-dev libgles-dev libdrm-dev libgbm-dev libasound2-dev libpulse-dev \
|
||||
libpipewire-0.3-dev libudev-dev libdbus-1-dev libusb-1.0-0-dev
|
||||
cd /work/Wiicompiled_VR_Frame
|
||||
Launcher/prepare-portable-tools.sh --arch aarch64 --destination /work/tools # clang 22, CMake, Ninja
|
||||
T=/work/tools/toolchain-aarch64/bin
|
||||
curl -fsSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0 --install-dir /work/dotnet
|
||||
Launcher/build-dawn-linux.sh --work-dir /work/dawn --cc $T/clang --cxx $T/clang++ --cmake $T/cmake --ninja $T/ninja
|
||||
```
|
||||
|
||||
Then the game. `local-build.sh` translates your own disc, so it needs `main.dol` and `StaticR.rel` from
|
||||
your extracted PAL `RMCP01` disc in `Assets/` (the extracted disc's `sys/main.dol` and
|
||||
`files/rel/StaticR.rel`; `translator/README.md` explains):
|
||||
|
||||
```bash
|
||||
mkdir -p Assets && cp <DATA>/sys/main.dol <DATA>/files/rel/StaticR.rel Assets/
|
||||
Launcher/local-build.sh --output-dir /work/out --cc $T/clang --cxx $T/clang++ --fuse-ld lld \
|
||||
--cmake $T/cmake --ninja $T/ninja --dotnet /work/dotnet/dotnet \
|
||||
--openxr --dawn-package /work/dawn/package --headset steam_frame
|
||||
```
|
||||
|
||||
The game lands in `~/wiicompiled/out` on the Frame. Debian trixie's C library is not newer than
|
||||
SteamOS's, so the binary runs on SteamOS outside the container. If CMake reports a missing package,
|
||||
install its `-dev` package in the container and run the same command again; both scripts resume
|
||||
where they stopped.
|
||||
|
||||
### Running it
|
||||
|
||||
The game reads its `Config.toml` from `~/.local/share/WiiCompiled/` on SteamOS (it is created on the first start): set
|
||||
`[paths] dvd_root` there to your extracted disc (the directory holding `sys/` and `files/`). Start
|
||||
SteamVR on the Frame, then start `~/wiicompiled/out/WiiCompiled`, from Desktop Mode or as a
|
||||
non-Steam game added to the library. The run log is in `Logs/` next to `Config.toml`; it should show,
|
||||
in order:
|
||||
|
||||
1. `OpenXR runtime offers N extensions: ...`, and `OpenXR initialized: runtime 'SteamVR/OpenXR'`;
|
||||
2. `OpenXR Vulkan requirements: ... Dawn will create its device through the runtime`;
|
||||
3. `Fragment density maps: enabled` (the patched Dawn and Turnip's density maps);
|
||||
4. `OpenXR Vulkan swapchains ready ... same-queue native eye copies`;
|
||||
5. `display refresh rate 120 Hz requested`, the session reaching `FOCUSED`, and
|
||||
`OpenXR interaction profiles: left /interaction_profiles/valve/frame_controller_valve`;
|
||||
6. `OpenXR eye gaze: available`, then `tracking`.
|
||||
|
||||
`Linux Vulkan OpenXR requires a Dawn built with Aurora's patches` means the build used a stock Dawn:
|
||||
check that `--dawn-package` pointed at `build-dawn-linux.sh`'s `package` directory.
|
||||
|
||||
## The Android flavour in Lepton
|
||||
|
||||
Everything from here to [Building and installing](#building-and-installing) is the `steamFrame`
|
||||
flavour of the Quest app. Its controller, refresh rate and foveation work is shared with the native
|
||||
build; its launch and manifest are Lepton's.
|
||||
|
||||
### What the flavour changes
|
||||
|
||||
| | Quest flavours | `steamFrame` |
|
||||
| --- | --- | --- |
|
||||
@@ -185,7 +274,7 @@ What follows from them:
|
||||
through exactly those, so it cannot present under Lepton. What can: binding Dawn's own device to
|
||||
the session, as the Windows Vulkan backend (`openxr_vulkan_win32.cpp`) does, so the eyes are
|
||||
copied into the swapchain on Dawn's queue with no sharing at all. That backend is also the core
|
||||
of a native SteamOS build ([below](#a-native-steamos-build)).
|
||||
of a native SteamOS build ([above](#the-native-steamos-build)).
|
||||
- **Finding the runtime.** An app inside Lepton reaches SteamVR's OpenXR runtime through the system
|
||||
runtime file, not a broker. The Khronos loader the game links statically (`DYNAMIC_LOADER OFF`)
|
||||
tries the runtime brokers first, then reads `/{product,odm,oem,vendor,system}/etc/openxr/1/active_runtime.json`,
|
||||
@@ -315,26 +404,3 @@ Open questions only the device can answer:
|
||||
- Whether the gaze needs an Android permission under Lepton.
|
||||
- Whether "Build on this headset" can run its toolchain through `/system/bin/linker64` inside
|
||||
Lepton. A game built on the PC does not depend on it.
|
||||
|
||||
## A native SteamOS build
|
||||
|
||||
Valve recommends native Linux ARM64 builds for the Frame, and one would avoid Lepton and the
|
||||
two-device copy. The pieces:
|
||||
|
||||
- **Backend.** The Windows Vulkan backend (`openxr_vulkan_win32.cpp`), where OpenXR creates Dawn's
|
||||
own device and eyes are copied on Dawn's queue, ports almost as it is. Only its `_WIN32` guards are
|
||||
platform-specific.
|
||||
- **Interop.** Aurora's `vulkan_win32_interop.cpp` finds the patched Dawn's exports with
|
||||
`GetModuleHandleW`. A static Linux Dawn would reference them directly, and `aurora_core.cmake`
|
||||
compiles that file on Windows only.
|
||||
- **Dawn.** A linux-aarch64 Dawn built with `aurora-main/patches/dawn` (the hook ABI and density
|
||||
maps), as `android/Build-QuestDawn.ps1` already does for Android.
|
||||
- **`openxr_integration.cpp`.** It needs a Linux branch asking for `XR_KHR_vulkan_enable2` and
|
||||
`XR_KHR_convert_timespec_time`. Today its `#else` is Android's and requires
|
||||
`XR_KHR_android_create_instance`.
|
||||
- **Controller timing.** `openxr_input.cpp` needs a `__linux__` branch for the input clock.
|
||||
- **CPU target.** An `MKW_LINUX_CPU` knob in place of `-mcpu=native`, for cross-builds.
|
||||
- **Android-gated fixes.** The Adreno vertex padding, `headset_owns_display` and the
|
||||
`last_pass_feeding_replay` saving are gated on `__ANDROID__`. They would follow the GPU or the
|
||||
headset instead.
|
||||
- **Packaging.** SteamOS packaging, and a way to build the player's game for it.
|
||||
Reference in new issue
Block a user