From c13e03e004dc518ca5ba65061c08582c2c25f972 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 05:31:12 +0000 Subject: [PATCH] Steam Frame beta: README, device findings, release notes and workflow The README and docs/steam-frame.md now describe the Frame build as a beta that runs on the headset: what works, the recommended settings (render_scale 1.25 is the panels' native 2160x2160), the known issues (doubled images, right-eye foveation), building with Docker on another machine (including registering qemu on hosts whose binfmt_misc is per container), and installing with Frame Control. A frame-* tag now publishes a source-only pre-release with the notes in docs/releases/.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3 --- .github/workflows/frame-release.yml | 30 +++++++++ README.md | 100 +++++++++++++++++++++------- docs/releases/frame-beta-1.md | 43 ++++++++++++ docs/steam-frame.md | 89 ++++++++++++++++++++++++- 4 files changed, 237 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/frame-release.yml create mode 100644 docs/releases/frame-beta-1.md diff --git a/.github/workflows/frame-release.yml b/.github/workflows/frame-release.yml new file mode 100644 index 0000000..c303721 --- /dev/null +++ b/.github/workflows/frame-release.yml @@ -0,0 +1,30 @@ +name: Steam Frame release +# A tag named frame- publishes a GitHub pre-release with the notes in +# docs/releases/.md. Source only: the game is built from the player's own disc and nothing +# built from it is distributed (README, Requirements). The v* tags stay with package.yml, which +# packages upstream's Windows installer. +on: + push: + tags: ['frame-*'] +permissions: + contents: write +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + persist-credentials: false + - name: Publish the pre-release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.ref_name }} + REPOSITORY: ${{ github.repository }} + run: | + notes="docs/releases/${TAG}.md" + if [ ! -f "$notes" ]; then + echo "::error::No release notes at $notes" + exit 1 + fi + gh release create "$TAG" --repo "$REPOSITORY" --verify-tag --prerelease \ + --title "WiiCompiled VR for the Steam Frame ${TAG#frame-}" --notes-file "$notes" diff --git a/README.md b/README.md index 02516c8..1f4be52 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

Steam Frame, SteamOS ARM64 - Status: untested on the headset + Status: beta Fork of WiiCompiled OpenXR VR License: GPLv3

@@ -21,9 +21,11 @@ C++ and compiled for the Frame's ARM64 CPU, and it renders through SteamVR's Ope > against your disc image, and nothing is uploaded. > [!WARNING] -> **Not yet run on a Steam Frame.** The Frame build compiles and its unit tests pass, but nobody -> has played it on the headset yet. Expect it to fail in ways only the device shows; reports with -> the run log are what moves it forward (see [Reporting problems](#reporting-problems)). +> **Beta.** It runs on a Steam Frame: SteamVR, both eyes at the panels' 2160x2160, the Frame's +> controllers, 120 Hz with every game frame shown, and foveation that follows your eyes. It is not +> finished: images still double in races and on the HUD, and the foveation tracks the right eye +> less well than the left (see [Known issues](#known-issues)). Reports with the run log move it +> forward (see [Reporting problems](#reporting-problems)). --- @@ -42,11 +44,17 @@ readings it is based on. button pauses and the left shoulder opens the settings panel. - **120 Hz.** The headset is asked for 120 Hz, exactly two display refreshes per game frame at the game's 60 FPS, so motion is even. `[vr] refresh_rate` changes it. +- **Every refresh from the game.** SteamVR halved the app's rate and filled every other refresh + itself. The game now submits its last frame again, at the pose it was rendered for, on each + refresh it has no new frame for (`[vr] repeat_frames`), so SteamVR runs it at the full 120 Hz. - **Eye-tracked foveation.** Variable-resolution rendering whose sharp centre follows your gaze through the Frame's eye tracking, instead of staying fixed straight ahead. `[vr] foveation` sets the strength and `[vr] eye_tracked_foveation` turns the tracking off. -- **Standalone defaults**: 0.8 render scale, the game's own object culling and medium foveation, - as on the Quest, sized for a mobile GPU driving 2160x2160 per eye. +- **Standalone defaults**: the game's own object culling and medium foveation, as on the Quest. + The render scale defaults to 0.8; on the Frame 1.0 is SteamVR's recommended 1728x1728 and **1.25 + is the panels' native 2160x2160**, which the Frame renders with time to spare. +- **Crash diagnostics on Linux.** A native crash logs the faulting thread, its pc and a backtrace, + which is how a crash on race restart was traced to the density maps sharing memory Dawn unmaps. - **Build tooling.** `Launcher/build-dawn-linux.sh` builds the patched Dawn (Aurora's WebGPU layer) the VR backend needs, and `Launcher/local-build.sh` gained `--openxr`, `--dawn-package`, `--headset steam_frame` and `--cpu`. @@ -57,41 +65,85 @@ the memory-sharing extensions the Android backend needs. The native build is the ## Requirements -- A Steam Frame with SteamVR, reachable over SSH (`ssh steamos@`). +- A Steam Frame with Developer Mode on and SSH set up (Steam Settings → System → Enable Developer + Mode, then set a user password). [Frame Control](https://github.com/saphid/frame-control) makes the + rest easier: it sets up an SSH key and installs the game into your Steam library. - A clean, unmodified **PAL `RMCP01`** disc image of Mario Kart Wii, dumped by you. ISO, GCM, GCZ, CISO, WBFS, WIA and RVZ can all be extracted. Other regions and patched executables are rejected. -- Somewhere to build. Either: - - **an x86_64 Linux PC** with podman and qemu: it builds in an emulated ARM64 container, which is - slow (the first build takes hours) but spares the Frame; or +- Somewhere to build, all of them running an ARM64 Debian container: + - **an x86_64 Linux PC** with podman and qemu (emulated, so slow: the first build takes hours); + - **a stronger Linux machine or server** with Docker, the same way and faster; - **the Frame itself**, in a podman container there. -- Several GB of free disk space for the toolchain, Dawn and the game. +- About 20 GB of free disk space on the build machine for the toolchain, Dawn and the game. > [!NOTE] > Nobody here will tell you where to get the game. Dumping your own disc is on you, and links to -> game files won't be provided or tolerated. +> game files won't be provided or tolerated. For the same reason there is no ready-built game to +> download: releases hold the source, and the game is always built from your own disc. ## Building and installing -The commands are in [`docs/steam-frame.md`](docs/steam-frame.md): [Building it on a Linux -PC](docs/steam-frame.md#building-it-on-a-linux-pc) or [Building it on the +The commands are in [`docs/steam-frame.md`](docs/steam-frame.md): [on a Linux +PC](docs/steam-frame.md#building-it-on-a-linux-pc), [with Docker on another +machine](docs/steam-frame.md#building-it-with-docker-on-another-machine) or [on the Frame](docs/steam-frame.md#building-it-on-the-frame). In short: 1. Extract your disc with [nodtool](https://github.com/encounter/nod) and copy `sys/main.dol` and - `files/rel/StaticR.rel` into `Assets/`. + `files/rel/StaticR.rel` into `Assets/`. Keep the extracted disc: the game reads it at run time. 2. Start a Debian trixie ARM64 container and install the build packages, the bundled clang 22, CMake and Ninja (`Launcher/prepare-portable-tools.sh --arch aarch64`), and .NET 8. -3. Build the patched Dawn: `Launcher/build-dawn-linux.sh`. -4. Build the game: `Launcher/local-build.sh ... --openxr --dawn-package /package --headset steam_frame`. -5. Copy the output and the extracted disc to the Frame, set `[paths] dvd_root` in - `~/.local/share/WiiCompiled/Config.toml`, start SteamVR, then start `WiiCompiled`. +3. Build the patched Dawn once: `Launcher/build-dawn-linux.sh`. Under emulation give it `--jobs 4` + on a 16 GB machine; more parallel jobs can run it out of memory. +4. Build the game: `Launcher/local-build.sh ... --openxr --dawn-package /package --headset + steam_frame`, with `--parallel` sized to the machine's memory (8 for 32 GB). +5. Copy the extracted disc to the Frame, and either send the `out` folder to the Frame with + [Frame Control](docs/steam-frame.md#installing-it-with-frame-control), which adds it to your + Steam library, or copy it over with `scp`. +6. Write `~/.local/share/WiiCompiled/Config.toml` on the Frame with your disc's path, then start + the game from the library in the headset: + + ```toml + [paths] + dvd_root = "/home/steamos/wiicompiled/disc" + ``` + +### Recommended settings + +All of them are in the headset's settings panel (left shoulder button, **VR** tab) as well as in +`Config.toml`: + +| Setting | Value | Why | +| --- | --- | --- | +| `[vr] render_scale` | `1.25` | The panels' native 2160x2160 per eye. | +| `[vr] foveation` | `medium` | `off` costs the most GPU time. | +| `[vr] repeat_frames` | `true` (default) | Keeps SteamVR at 120 Hz. | +| `[vr] frame_interpolation_fps` | `0` | Interpolation made things worse on the Frame. | +| `[video] resolution_multiplier` | `2` | The game's own frame; 4x is too heavy for the Frame's GPU. | + +Keep SteamVR's own refresh rate at 120 Hz. Motion Smoothing makes no difference here. + +## Known issues + +- **Doubled images** in races and on the HUD, worst while racing, sometimes in the right eye only. + The suspect is foveation on the Frame's graphics driver. If it bothers you, try foveation **Off** + in the panel (it costs GPU time), and report whether it helped. +- **Foveation follows the right eye less well** than the left, and its sharp area may feel small + on Low and Medium. +- **VR frame interpolation** is not recommended on the Frame. +- **The Quest app's `steamFrame` flavour** (an Android build for the Frame's Lepton layer) cannot + show a picture: Lepton's graphics driver lacks the memory sharing it needs. Use the native build. ## Reporting problems -Open an issue on this repository with the run log from `~/.local/share/WiiCompiled/Logs/` on the -Frame, or the last lines of the failing build step. [Running -it](docs/steam-frame.md#running-it) lists the log lines a working start shows, in order; the -first one missing says where it stopped. +Open an issue on this repository with: +- what you did and what you saw (which eye, where in the picture, racing or menus); +- the run log: each run has a folder under `~/.local/share/WiiCompiled/Logs/` on the Frame, with + `console.log` and, after a crash, `crash_sigsegv.txt`; +- or, for a build problem, the last lines of the failing step. + +[Running it](docs/steam-frame.md#running-it) lists the log lines a working start shows, in order; +the first one missing says where it stopped. Problems that also happen on a PC or a Quest belong upstream, in [WiiCompiled OpenXR VR](https://github.com/iChris4/Wiicompiled_VR). @@ -170,6 +222,8 @@ All translated output is verified against real hardware behavior and most import - **[nod](https://github.com/encounter/nod)** - nodtool, the disc image extractor. - **[DolphinXR](https://github.com/iChris4/dolphinXR)** - the Steam Frame controller profile's input paths. +- **[Frame Control](https://github.com/saphid/frame-control)** by saphid - installing the game into + the Frame's Steam library, and its notes on how the Frame's software fits together. - Everyone in the static recompilation community. Bundled third-party components and their licenses live in diff --git a/docs/releases/frame-beta-1.md b/docs/releases/frame-beta-1.md new file mode 100644 index 0000000..df2794b --- /dev/null +++ b/docs/releases/frame-beta-1.md @@ -0,0 +1,43 @@ +The first beta of WiiCompiled VR for the Steam Frame: Mario Kart Wii, statically recompiled to native +ARM64 code, running in VR on SteamOS through SteamVR. + +**This release is source only.** The game is always built from your own clean PAL `RMCP01` disc, +and nothing built from it may be distributed, so there is no ready-built game here. Follow +[Building and installing](https://github.com/mitch030504/Wiicompiled_VR_Frame#building-and-installing) +in the README; the full commands are in +[`docs/steam-frame.md`](https://github.com/mitch030504/Wiicompiled_VR_Frame/blob/frame-beta-1/docs/steam-frame.md). + +## What works on the Frame + +- Starts in VR from the Steam library (installed with Frame Control) with SteamVR's OpenXR runtime. + The runtime creates the GPU device the game renders with, so the eyes go straight into the + headset's swapchain. +- Both eyes at the panels' native 2160x2160 (`render_scale = 1.25`), 120 Hz, every game frame + shown: SteamVR reports 120 Hz with 60 new frames and 60 repeats a second and no late frames. +- The Frame's own controllers: left D-pad as the Wii Remote's D-pad, View to pause, left shoulder + for the settings panel. +- Fragment density map foveation that follows your eyes through the Frame's eye tracking. + +## Fixed during device testing + +- A crash on race restart inside the Frame's Vulkan driver: density maps shared memory that Dawn + unmaps after buffer uploads. Each map now has its own memory block (Dawn patch, so rebuild Dawn). +- SteamVR halving the game's rate and filling every other refresh itself: + `[vr] repeat_frames` (on by default for the Frame) resubmits the last frame for those refreshes. +- Native crashes on Linux now log the faulting thread, pc and backtrace. +- The eye-tracked foveation region is 8 degrees wider and each eye keeps 128 maps. + +## Known issues + +- Images double in races and on the HUD, sometimes in the right eye only. Foveation is the main + suspect; try foveation Off if it bothers you, and report the result. +- Foveation follows the right eye less well than the left. +- VR frame interpolation is not recommended on the Frame. +- The Android (`steamFrame`) flavour cannot show a picture in Lepton; use the native build. + +## Recommended settings + +`render_scale = 1.25`, `foveation = "medium"`, `repeat_frames = true`, `frame_interpolation_fps = 0` +under `[vr]`, and `resolution_multiplier = 2` under `[video]`. SteamVR at 120 Hz. + +Reports with the run log from `~/.local/share/WiiCompiled/Logs/` are welcome as issues. diff --git a/docs/steam-frame.md b/docs/steam-frame.md index 663b59f..86e710f 100644 --- a/docs/steam-frame.md +++ b/docs/steam-frame.md @@ -15,8 +15,14 @@ Most of what this document describes is shared by both: the Frame controller pro 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. -**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. +**Status: beta, played on a Steam Frame.** The native build starts in VR under SteamVR, renders +both eyes on the device Dawn shares with the runtime, binds the Frame's controllers, runs at 120 Hz +with every game frame shown (`new=60 repeat=60` a second, no late frames, at `render_scale = 1.25`, +the panels' 2160x2160), and follows the eyes with its foveation. Two device runs found and fixed a +crash on race restart (see [Eye-tracked foveation](#eye-tracked-foveation)) and SteamVR halving the +app's rate (see [Refresh rate](#refresh-rate)). Still open, in [Known issues](#known-issues): doubled +images in races and on the HUD, sometimes in one eye only, and foveation that follows the right eye +less well than the left. ## The native SteamOS build @@ -122,6 +128,56 @@ scp -r ~/wiicompiled/out steamos@:wiicompiled/ scp -r ~/wiicompiled/disc-extract steamos@:wiicompiled/disc ``` +### Building it with Docker on another machine + +A faster x86_64 machine helps most with the game itself (the translated code is a few thousand large +files). Docker works as podman does, with one difference on hosts whose `binfmt_misc` registrations +are per container (Unraid 7 with kernel 6.18): `tonistiigi/binfmt --install arm64` then succeeds but +only inside its own container, and Debian answers `exec format error`. Register the emulator on the +host instead, with the `P` flag the tonistiigi build of qemu expects (without it every program loses +its first argument: `uname -m` prints `Linux`): + +```bash +docker create --name qemu-src tonistiigi/binfmt +docker cp qemu-src:/usr/bin/qemu-aarch64 /usr/local/bin/qemu-aarch64 +docker rm qemu-src +echo ':qemu-aarch64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-aarch64:POCF' > /proc/sys/fs/binfmt_misc/register +docker run --rm --platform linux/arm64 debian:trixie uname -m # aarch64 +``` + +Unraid keeps `/usr/local/bin` in memory, so this is repeated after a reboot. Copy the work directory +over, without Dawn's build tree (the package is what the game links), and run the build detached so +that a closed SSH session does not stop it: + +```bash +rsync -a --exclude dawn/build --exclude 'dawn/dawn-*' --exclude disc-extract \ + ~/wiicompiled/ root@:/mnt/user/appdata/wiicompiled/ # from the PC +docker run -d --name wiicompiled-frame --platform linux/arm64 \ + -v /mnt/user/appdata/wiicompiled:/work debian:trixie \ + bash -c 'bash /work/build-game.sh >> /work/game.log 2>&1' +``` + +`build-game.sh` holds the `apt-get` line of [Building it on the Frame](#building-it-on-the-frame) +and the `local-build.sh` command, with `--parallel 8` for 32 GB of memory (compiles take more memory +under emulation: Dawn's build at 16 jobs froze a 16 GB laptop, and finished at 4). `docker start +wiicompiled-frame` runs it again after a change: the translation is reused and only what changed +is compiled. + +### Installing it with Frame Control + +[Frame Control](https://github.com/saphid/frame-control) adds a folder to the Frame's Steam library as +a Devkit Game: drop the `out` folder on **Send to Frame** and keep **Launches** on `WiiCompiled`. +It picks `SteamLinuxRuntime_4-arm64` for an ARM64 program, but Steam starts such a title natively, +which this build needs (it uses the system's `libpng16`, `libstdc++` and `libz`). The game then lands +in `~/devkit-game//` and starts from the library inside the headset, where SteamVR is already +running. An update only replaces the executable; copy it under another name and move it into place, +which also works while an old copy is open: + +```bash +scp WiiCompiled frame:devkit-game/WiiCompiled/WiiCompiled.new +ssh frame 'cd ~/devkit-game/WiiCompiled && chmod 755 WiiCompiled.new && mv -f WiiCompiled.new WiiCompiled' +``` + ### Running it The game reads its `Config.toml` from `~/.local/share/WiiCompiled/` on SteamOS (it is created on the first start): set @@ -142,6 +198,35 @@ in order: `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 game only writes a `Config.toml` when there is none, so a file holding just `[paths]` and +`dvd_root` can be written before the first start. Each run gets its own folder under `Logs/`; a +native crash leaves `crash_sigsegv.txt` there and, in `console.log`, the faulting thread, its pc and +lr and a backtrace as module + offset, which `addr2line -f -C -e native-build/WiiCompiled ` +turns into functions on the build machine (the executable is not stripped). + +### Settings that matter on the Frame + +| Setting | Recommended | Why | +| --- | --- | --- | +| `[vr] render_scale` | `1.25` | Scales SteamVR's recommended eye size, 1728x1728 on the Frame; 1.25 is the panels' 2160x2160. The eye passes took 9 to 11 ms a game frame there, with medium foveation. | +| `[vr] foveation` | `medium` | `off` shades every pixel and costs the most. See [Known issues](#known-issues) if images double. | +| `[vr] repeat_frames` | `true` (default) | Without it SteamVR halves the app's rate and fills refreshes itself. | +| `[vr] frame_interpolation_fps` | `0` | Rendering in-between frames needs 120 eye pairs a second; at these resolutions it made things worse. | +| `[video] resolution_multiplier` | `2` | The game's own frame, which the eyes are made from, at 2x the Wii's. 4x is far too heavy for the Adreno 750. | + +## Known issues + +- **Doubled images.** Images double in races and on the HUD, worst while racing, at first in the + right eye only and later in both. Both eyes get the same frames and repeats, so a one-eyed doubling + is not the 60 FPS cadence. The suspect is foveation: Turnip draws a coarse bin at lower resolution + and scales it back up, and each eye's density maps change with its gaze. Comparing foveation off, + on without eye tracking, and on with it is the next test. +- **Foveation and the right eye.** The full-density region follows the left eye better than the + right. Each eye already gets its own gaze direction; convergence on near content (the HUD screen at + 2 m, the cockpit) is not yet corrected for. +- **VR frame interpolation** is not recommended on the Frame (see the table above). +- **The Android flavour** cannot show a picture in Lepton (below). + ## The Android flavour in Lepton Everything from here to [Building and installing](#building-and-installing) is the `steamFrame`