Files
FrameAssistant/docs/STEAM-FRAME.md
T

6.6 KiB
Raw Blame History

Steam Frame

How to build, deploy and run dashboards on the Steam Frame, and what was learned on the device. Facts below were verified on a Frame with SteamOS holo 0.4.3 (system Qt 6.8.0, Adreno 750 GPU with Mesa Turnip).

Building

Frame builds run in a Debian container (Docker or Podman), either cross-compiled on an x86_64 PC (no emulation) or natively on the Frame:

scripts/container-build.sh cross           # on the PC → build/cross-arm64/stage
scripts/container-build.sh native          # on the Frame itself (podman/distrobox)
scripts/container-build.sh cross-bundle    # fallback variant, Qt bundled
scripts/container-build.sh cross shell     # a shell in the build container

System Qt (default). Builds use SteamOS's own Qt; packages are about 3 MB.

  • The container builds against Debian's Qt 6.8.2; at runtime the Frame's Qt 6.8.0 is used. Qt keeps binary compatibility within 6.8, as long as the program uses no Qt-internal API.
  • QML is compiled to bytecode only (VRDASH_QML_BYTECODE_ONLY), because Qt's QML-to-C++ compiler output is tied to the exact Qt version.
  • The binary then needs only the stable Qt API, qt_version_tag (Qt ≥ 6.8), and Qt's Vulkan wrapper functions. Verified with an Arch container frozen at Qt 6.8.0 and on the Frame.
  • After a SteamOS update with a different Qt, rebuild, or use the bundled variant.

Bundled Qt (fallback, -bundle modes, about 46 MB).

  • Qt, its plugins and QML modules, and their non-system dependencies are copied next to the program (cmake/BundleQt.cmake).
  • The GPU and display stack (GL/EGL, Vulkan loader, Wayland, X11, libffi, glibc) always comes from SteamOS; bundling it would break GPU access.
  • The Debian copyright files of all bundled libraries are included, as their licenses require.

Packaging and deploying

scripts/package-release.sh                 # → dist/<exe>-<version>-linux-arm64/ + .tar.gz
scripts/package-release.sh --bundle-qt     # → …-linux-arm64-bundled
scripts/deploy-to-frame.sh steamos@<frame> # rsync the newest package to ~/<exe>, run install.sh

A release folder contains the program, install.sh (install or update: stops a running instance, registers with SteamVR, starts it), uninstall.sh, README.txt and the licenses. The app logs to logs/frame-assistant.log in that folder (passed by the manifest), and needs a settings file first (~/.config/frameassistant/config.json, from share/frameassistant/config.example.json; see README.md, "Settings"). SteamVR stores the folder's absolute path, so after moving the folder, run install.sh again.

Without the deploy script: copy the .tar.gz, unpack it on the Frame, run ./install.sh (SteamVR must be running). Over SSH this works too: SteamVR starts the dashboard itself.

What the Frame requires (all handled by the overlay platform)

Finding Consequence
SteamVR is installed system-wide under /opt/steamvr; its log is ~/.local/share/Steam/logs/vrserver.txt Look there when a manifest or start fails
The manifest needs binary_path_linux_arm; entries with only binary_path_linux are silently skipped ("must specify binary_path") The manifest template picks the key from the target architecture
SteamVR refuses VRApplication_Utility (VRInitError_Init_NotAvailableToUtilityApps) Manifest commands connect as VRApplication_Background (needs a running SteamVR, never starts one)
An executable named vrdashboard is taken for SteamVR's own dashboard (its watchdog then "restarts" it) Executable frame-assistant; CMake rejects SteamVR process names
OpenGL runs through zink on Vulkan (no native GL driver for the Adreno) Vulkan is the default: 1.01 ms vs 1.89 ms per frame (--benchmark, 1600×1000)
OpenVR must shut down before the graphics device is destroyed Teardown order in DashboardApplication::runOverlay() (else a crash at exit with Vulkan)
Qt needs a display connection even for off-screen rendering; over SSH none is set SteamVR-launched instances inherit it; over SSH, set DISPLAY=:0
Process names are cut to 15 characters Scripts find running instances by command line, not by name
Floated/pinned dashboard tabs stay visible and operable in games Rendering follows the overlay's visibility, not the dashboard's

Libraries on the Frame

Checked 2026-10-05; details per requirement in REQUIREMENTS.md, Appendix C.

  • System Qt 6.8.0 under /usr/lib includes, besides the base modules: DBus, Network, Multimedia (FFmpeg plugin), WebSockets, WebEngine (Core, Quick), WebView, TextToSpeech, Positioning, Sensors, Svg, VirtualKeyboard. TLS plugins: libqopensslbackend.so, libqcertonlybackend.so.
  • It apparently comes with the KDE Plasma desktop mode (plugins for plasma, kwin, discover). SteamVR does not use Qt 6: nothing under /opt/steamvr links or ships libQt6*. So the system Qt is not a SteamVR dependency, which is one more reason to keep the bundled-Qt fallback.
  • Qt WebEngine on the Frame can't be loaded (checked 2026-10-05): qt6-webengine and qt6-webchannel are 6.7.0 while the rest of Qt is 6.8.0, and WebEngine was built against FFmpeg 6 (libavcodec.so.60, libavformat.so.60, libavutil.so.58); the Frame has FFmpeg 7.0 (.61/.59) and an old FFmpeg 4 (.58/.56). Only qt6-webview and signon-ui depend on it. A program linking WebEngine fails to start ("libavcodec.so.60: cannot open shared object file"). Other Qt modules are 6.8.0 (pacman -Q | grep qt6-). Not yet checked: whether Qt Multimedia's FFmpeg plugin has the same problem.
  • Qt add-on modules must come from the system Qt. Shipping one fails: they use Qt's private API, and QtCore aborts on any version mismatch ("Cannot mix incompatible Qt library").
  • Not present: any MQTT library (no libmosquitto, no Qt MQTT). FrameAssistant ships libmosquitto.
  • Present: OpenSSL 3.2.1 (libssl.so.3, libcrypto.so.3), glibc 2.39, libcjson.so.1 (1.7.17), libpulse.so.0, libpipewire-0.3.so.0, and the tools wpctl, pactl, nmcli.
  • Libraries we ship must not need newer symbol versions than the Frame has (e.g. OPENSSL_3.x, GLIBC_2.x): check with readelf -V. Debian's libmosquitto needs at most OPENSSL_3.0.0 and GLIBC_2.34.

Notes

  • The Frame's package repositories in /etc/pacman.conf are private (URLs marked "DO_NOT_SHARE"). Don't put them into scripts or this repository.
  • Valve's public Holo Core preview container (registry.gitlab.steamos.cloud/holo/ holo-core-aarch64-preview/base-devel) ships Qt 6.10, newer than the Frame's 6.8. It is not usable for system-Qt builds.