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