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:
Claude committed 2026-10-04 09:56:46 +00:00
1 parent 0edf10b220
commit d8fc2a996c
5 files changed
+327 -41

No files matched your search

+174
View File
@@ -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"
+46
View File
@@ -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
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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.