diff --git a/android/Build-Quest.ps1 b/android/Build-Quest.ps1 index 340796e..432a109 100644 --- a/android/Build-Quest.ps1 +++ b/android/Build-Quest.ps1 @@ -86,7 +86,7 @@ $variant = (Get-Culture).TextInfo.ToTitleCase($Configuration) # The Gradle flavour and the -mcpu target its kit must record (headsetCpus in app/build.gradle.kts). $flavourDir, $expectedCpu = switch ($Headset) { 'quest1' { 'quest1', 'kryo' } - 'frame' { 'steamFrame', 'cortex-x4+nosve' } + 'frame' { 'steamFrame', 'cortex-x4' } default { 'modernQuest', 'cortex-a77' } } $flavour = $flavourDir.Substring(0, 1).ToUpperInvariant() + $flavourDir.Substring(1) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index e71493b..b2c42d6 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -61,9 +61,9 @@ val headsetCpus = mapOf( "modernQuest" to "cortex-a77", // Snapdragon 835. cortex-a77 binaries terminate with SIGILL on Quest 1. "quest1" to "kryo", - // Snapdragon 8 Gen 3 (Cortex-X4, A720 and A520, all ARMv9.2). Its firmware does not expose SVE, - // which clang would otherwise auto-vectorise with for a cortex-x4. - "steamFrame" to "cortex-x4+nosve", + // Steam Frame: Snapdragon 8 Gen 3 (Cortex-X4, A720 and A520, all ARMv9.2). Its kernel exposes + // SVE and SVE2 (HWCAP, inside Lepton too), so the whole cortex-x4 feature set is safe. + "steamFrame" to "cortex-x4", ) // android/nod-jni: nod, the disc image library the PC installer runs as nodtool, diff --git a/docs/steam-frame.md b/docs/steam-frame.md index eb1f082..1a093b6 100644 --- a/docs/steam-frame.md +++ b/docs/steam-frame.md @@ -18,7 +18,7 @@ device checks at the end are still to do. | | Quest flavours | `steamFrame` | | --- | --- | --- | -| CPU target (`kit.json` `androidCpu`) | `cortex-a77` (`kryo` on Quest 1) | `cortex-x4+nosve` | +| CPU target (`kit.json` `androidCpu`) | `cortex-a77` (`kryo` on Quest 1) | `cortex-x4` | | `MKW_ANDROID_HEADSET` | `quest` | `steam_frame` (defines `MKW_HEADSET_STEAM_FRAME`) | | Library entry | `LauncherActivity` (Quest 1: `QuestActivity`) | `FrameEntryActivity` | | Horizon OS manifest entries | present | removed | @@ -31,11 +31,12 @@ as they are. The kit's CPU string differs from the Quest ones, which gives the F fingerprint: a game built for a Quest is refused on the Frame and the other way round, by the same checks that keep Quest 1 and modern Quest games apart. -**CPU.** Every core of the 8 Gen 3 implements ARMv9.2, so the products are tuned for the Cortex-X4. -`+nosve` matters: clang auto-vectorises with SVE for a `cortex-x4` (a simple loop compiled with -`-O3` used SVE registers ten times), and Qualcomm's firmware does not expose SVE on this chip, so -those instructions would end the game with `SIGILL`. With `+nosve` the target features read -`-sve -sve2 -sve2-bitperm` and the same loop uses NEON only. The flavour-to-CPU map lives once in +**CPU.** Every core of the 8 Gen 3 implements ARMv9.2, so the products target the Cortex-X4 with +its whole feature set. That includes SVE and SVE2, which clang auto-vectorises with (a simple loop +compiled with `-O3` used SVE registers ten times). Phones with this chip do not expose SVE, but the +Frame's kernel does: `/proc/cpuinfo` lists `sve`, `sve2`, `svei8mm`, `svebf16` and the SVE2 crypto +extensions, on SteamOS and inside Lepton alike. A build for a device without SVE would need +`cortex-x4+nosve`. The flavour-to-CPU map lives once in `android/app/build.gradle.kts` (`headsetCpus`), which the kit export also reads now instead of guessing from the variant name. @@ -131,7 +132,7 @@ the device's extension list. On the Windows build host described in `docs/quest-port.md`: ```powershell -powershell -ExecutionPolicy Bypass -File android/Build-Quest.ps1 -Headset frame # the steamFrame APK; checks kit.json says cortex-x4+nosve +powershell -ExecutionPolicy Bypass -File android/Build-Quest.ps1 -Headset frame # the steamFrame APK; checks kit.json says cortex-x4 powershell -ExecutionPolicy Bypass -File android/Build-QuestGame.ps1 -Headset frame -Product base -Data # a .wcgame for the Frame's kit ``` @@ -145,6 +146,33 @@ network. With an Android app running on the Frame, `adb connect :5555` build PC. How the APK reaches the Steam library (adb into a Lepton instance, frame-control, or Steam's own sideloading) is to be confirmed on the device. +## What the Frame reported + +Read on 2026-10-04 from a Steam Frame running SteamOS (`holo`), kernel 6.18.0, with the commands +below: + +| Reading | SteamOS | Lepton | +| --- | --- | --- | +| Page size | 4096 | 4096 | +| CPU | 8 cores; `sve sve2 svei8mm svebf16 sveaes svepmull svebitperm svesha3 svesm4 i8mm bf16 bti paca pacg ...` | the same | +| Android | — | 11 (API 30), `ro.product.model` Lepton, device `lepton_arm64_only`, platform `waydroid` | +| Vulkan driver | — | `ro.hardware.vulkan=freedreno`: Mesa's Turnip, not Qualcomm's driver | +| OpenXR runtime | SteamVR, `bin/linuxarm64/vrclient.so` (`~/.config/openxr/1/active_runtime.json`) | no package named for XR, Valve, Steam or Khronos | + +What follows from them: + +- **Fast memory path.** 4 KB pages keep the translated code's flat memory path. A 16 KB kernel + would have sent it through the checked path. +- **CPU target.** The Frame exposes SVE, so the build targets the whole `cortex-x4` (above). +- **Android version.** API 30 meets the app's minimum of 29. +- **Driver workarounds.** Lepton is a Waydroid container, and its Vulkan driver is Turnip. The + Adreno workarounds in `docs/quest-port.md` were found on Qualcomm's own driver. The vertex padding + stays on (it is correct either way); `debug.wiicompiled.vtxpad 0` can check whether Turnip needs it. +- **Open:** whether Turnip in Lepton imports AHardwareBuffers and sync fds is in the `vkjson` + extension list, still to read. +- **Open:** how an app inside Lepton reaches SteamVR's OpenXR runtime. No broker package shows up, + so the Khronos loader's runtime broker may be provided some other way. + ## Device checklist Information to collect first, from any PC over Lepton's adb port (the commands work in bash, zsh and