Files
OpenVR-AdvancedSettings-frame/docs/steamframe/PROGRESS.md
T
matzmanandClaude Opus 5.5 bbb3d1ba0e Log debug output only in builds with debugSymbolsAndLogs
On master, easylogging's Debug level was disabled unless OVRAS was built
with debugSymbolsAndLogs (ENABLE_DEBUG_LOGGING). The qt6 branch switched
to qDebug() and lost that: debugLoggingEnabled was left unused, and all
debug output reached the log. On the Steam Frame it filled with
"updateAllPulseData done." about every 11 ms, as the audio tab reads the
microphone's mute state on every tick.

setUpLogging() now disables debug output through a logging filter rule.
QT_LOGGING_RULES="*.debug=true" takes precedence and turns it on again
for troubleshooting without a rebuild.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:32:00 +02:00

16 KiB
Raw Blame History

Steam Frame port: progress

Status (2026-10-07): iteration 1 implemented. Next: test checklist T1–T11 on the Frame (at the end of this file), then assessment. Getting started: README.md.

Iteration 1

Step 1: build fixes, bytecode-only QML (2026-10-07)

Changes:

  • CMakeLists.txt:
    • Core5Compat removed (unused, not on the Frame).
    • GuiPrivate requested explicitly. This is temporary, until step 3 replaces QRhi.
    • QT_QMLCACHEGEN_ARGUMENTS --only-bytecode.
    • OpenVR library directory per architecture (linux64 / linuxarm64 / win64), for linking and for the copy next to the binary.
    • RPATH $ORIGIN.
    • libXtst linked.
  • overlaycontroller.cpp: d3d11.h and case QRhi::D3D11 only under _WIN32.
  • Logging: 8 active easylogging LOG(INFO) calls became qInfo() (overlaycontroller.cpp 6, ChaperoneTabController.cpp 1, MoveCenterTabController.cpp 1). Commented-out LOG lines are left unchanged.
  • Only changed lines are formatted (git clang-format).

Results (x86_64, Arch, Qt 6.11.1, GCC):

  • The build succeeds, with 1463 compiler warnings, as in qt6.
  • objdump -T: 7 Qt_6_PRIVATE_API symbols, all QRhi… (step 3). The QQmlPrivate::AOTCompiledContext symbols are gone (bytecode-only QML).
  • libopenvr_api.so is resolved from the binary's directory (ldd).
  • Not started: without a running SteamVR the start hangs in OpenVR init (expected; tested on the Frame in step 5).

Step 2: platform option, R7, tick (2026-10-07)

Changes:

  • Platform option:
    • CMake option OVRAS_STEAM_FRAME (default OFF) sets the compile definition OVRAS_STEAM_FRAME=1.
    • New src/utils/platform_capabilities.h evaluates it as the only place. It holds k_chaperoneCommitSupported, k_defaultVsyncDisabled and k_defaultCustomTickRateMs.
  • Tick (R6):
    • In "vsync disabled" mode, m_pumpEventsTimer runs directly at customTickRateMs (applyTickInterval(), Qt::PreciseTimer); the 1 ms counting is gone.
    • Changing the setting restarts the timer.
    • Setting defaults in settings_controller.h come from the constants: Frame true/11 ms, otherwise unchanged false/20 ms.
  • R7: with !k_chaperoneCommitSupported:
    • updateChaperoneResetData() and applyChaperoneResetData() skip CommitWorkingCopy/RevertWorkingCopy. Each logs once per function.
    • The init autosave profile is skipped.

Results:

  • Both variants (default and -DOVRAS_STEAM_FRAME=ON) build on x86_64. The definition is only set in the Frame variant (compile_commands.json).
  • Not tested at runtime yet (Frame, step 5).

Notes:

  • Another commit at start-up remains, but only on opt-in. SetWidget() applies a chaperone profile and commits when "auto-apply chaperone" (autoApplyChaperoneToggle, default false) is on. That's a chaperone-profile feature, so it belongs to R5 (iteration 2).
  • clang-format reflows comment blocks next to new comments. Separate new comments from existing commented-out code with a blank line, otherwise the diff grows.

Step 3: rendering through public API, --graphics-api, mouse y, shutdown order (2026-10-07)

Changes:

  • src/render/ (new): RenderBackend, OpenGLRenderBackend, VulkanRenderBackend from the template (4a5b090).
    • Changes to the template code: VRDASH_* → OVRAS_* names, origin note in the file header, references to OverlayController.
    • Formatted completely in OVRAS style.
    • One comment in VulkanRenderBackend.h was wrapped by hand, because the automatic wrapping had broken its column layout.
  • OverlayController:
    • QRhi block replaced by configureWindow → renderControl.initialize → attachWindow → createRenderTarget.
    • renderOverlay() wraps the frame in beginFrame/finishFrame. It submits vrTextureBounds + vrTexture while the context is current.
    • SetOverlayFromQRhiTexture, the QRhi members and QVulkanInstance are removed.
    • Render delay 5 → 16 ms (about 60 fps).
  • Shutdown: Shutdown() runs only once. It calls VR_Shutdown(), then frees the backend's render target (releaseRenderTarget, detachWindow).
  • Mouse y: always flipped; the Linux un-flip and its TODO are removed.
  • openvr_init::renderInterop(): Vulkan extensions and HMD GPU from SteamVR.
  • main.cpp: parses --graphics-api, then createRenderBackend → initialize → QQuickWindow::setGraphicsApi → OverlayController.
  • setup.*: --graphics-api opengl|vulkan (default opengl). Unknown or not built in → error, exit code GENERAL_FAILURE.
  • CMake:
    • GuiPrivate is gone.
    • The Vulkan backend is built when QT_FEATURE_vulkan is set (OVRAS_HAS_VULKAN).

Results (x86_64, Qt 6.11.1):

  • The build succeeds. The Vulkan backend is built in.
  • objdump -T: only QVulkanDeviceFunctions::* / QVulkanFunctions::* remain as Qt_6_PRIVATE_API. Acceptance criterion R1 (symbols) is met.
  • Warnings 1463 → 1630. The new code itself has none; the additional ones come from openvr.h in the three new translation units.
  • Not tested yet:
    • running both backends, Vulkan validation, the snapshot test (step 5, with the containers)
    • mouse direction (Frame)

Risk:

  • MyTextField opens the SteamVR keyboard on activeFocus. The template had to send the offscreen window an explicit FocusIn, otherwise activeFocusItem stayed null. The qt6 branch doesn't send it. If text fields don't respond on the Frame, that is the cause (R4).

Step 4: manifest and installation (2026-10-07)

Changes:

  • manifest.vrmanifest: binary_path_linux and binary_path_linux_arm → AdvancedSettings_app.
  • manifest::handleManifests:
    • VR_Init(Utility); on VRInitError_Init_NotAvailableToUtilityApps, VR_Init(Background).
    • Other errors: message and exit code OPENVR_INIT_ERROR, instead of initializeOpenVR's retry loop.
  • main.cpp: --graphics-api is checked before connecting to OpenVR. A wrong value used to fail only after initializeOpenVR's retry loop.

Results (x86_64, without SteamVR):

  • --force-install-manifest exits right away with OPENVR_INIT_ERROR (−2).
  • --graphics-api foo exits right away with GENERAL_FAILURE (−1).
  • The build tree contains the binary, libopenvr_api.so, both manifests, default_action_manifests/ and res/.
  • Not tested yet: Background on the Frame (step 5).

Step 5: Frame build, package, tests (2026-10-07)

Changes:

  • build_scripts/steamframe/ (new, see DESIGN.md section 9): containers, toolchain, build, test, package and deploy scripts.
  • test/render/ (new): render test for both backends (OVRAS_BUILD_TESTS=ON).
  • CMakeLists.txt:
    • option OVRAS_BUILD_TESTS
    • RPATH only $ORIGIN (BUILD_WITH_INSTALL_RPATH). Before, the cross binary also had the host's absolute link directory in its RUNPATH.
  • .gitignore: dist/.

Results:

  • Render tests:
    • locally (Arch, Qt 6.11, Intel Iris Xe): OpenGL and Vulkan, 4/4 passed each
    • in the container (Debian trixie, Qt 6.8, same GPU via /dev/dri): 2/2 passed, no Vulkan validation messages
    • Proof that the layer was active: VK_LOADER_DEBUG=layer shows "Inserted device layer VK_LAYER_KHRONOS_validation".
  • Cross build (aarch64, Qt 6.8 Debian): succeeds once the container has libxt-dev (input_sender_X11.cpp includes X11/Intrinsic.h).
    • Qt_6_PRIVATE_API without QVulkan*: 0 → R1 symbols met.
    • Qt version tag: Qt_6.8 (fits the Frame's 6.8.0).
    • GLIBC ≤ 2.38 (the Frame has 2.39); GLIBCXX ≤ 3.4.32 (not checked against the Frame).
    • NEEDED: Qt6 Core/Gui/Qml/Quick/Widgets/Network/DBus/Multimedia/WebSockets, libX11, libXtst, libpulse, libopenvr_api, libstdc++/libc.
  • Package dist/AdvancedSettings-5.7.4-linux-arm64.tar.gz: 3.0 MB (9.1 MB unpacked); since the version fix below …-5.8.17-…. The version 5.7.4 comes from qt6's project() (master is at 5.8.17).

Open (needs the Frame):

  • Are the QML modules OVRAS imports present in the Frame's system Qt? QtQuick.Controls (Material), Layouts, Dialogs, Multimedia.
  • Do libXt/libXtst exist on SteamOS? Is libstdc++ new enough?

Version from compile_version_string.txt (2026-10-07)

  • Problem: qt6's CMakeLists.txt had the version hard-coded as 5.7.4. The qmake build read it from build_scripts/compile_version_string.txt (5.8.17-release). master is fully merged into qt6, so only the number was stale. Consequence: the version check (comparison with ver/versioncheck.json, 5.8.17) would have reported an update.
  • Fix: CMake reads the file.
    • APPLICATION_VERSION = full string, as in qmake.
    • project(VERSION) = numeric part.
  • Result: APPLICATION_VERSION="5.8.17-release", CMAKE_PROJECT_VERSION=5.8.17, package dist/AdvancedSettings-5.8.17-linux-arm64.tar.gz (3.0 MB).

Fix: manifest commands without a display (2026-10-07)

  • Problem (first deploy to the Frame): install.sh aborted with a core dump in ./AdvancedSettings_app --force-install-manifest. Log: "could not connect to display", then "no Qt platform plugin could be initialized" (fatal).
  • Cause: main.cpp creates the QApplication before it handles the manifest options. Qt's default platform plugin (xcb) aborts without a display, and over SSH there is none. install.sh set DISPLAY=:0 only for the start, not for registering. uninstall.sh (--force-remove-manifest) had the same problem.
  • Fix (package-release.sh, generated scripts only): both manifest calls run with QT_QPA_PLATFORM=offscreen. Registering draws nothing, so it needs no display at all. The normal start keeps DISPLAY=:0 (xcb), because rendering needs a real OpenGL/Vulkan context. No change to the program.
  • Result: package rebuilt (--no-build), generated scripts checked with sh -n.
  • Not tested yet: the fix itself on the Frame (T1, T11). No local x86 build was at hand for a test without a display.

Fix: OpenVR library for aarch64 (2026-10-07)

  • Problem (second deploy): with the display fix, --force-install-manifest got as far as VR_Init and failed there: "Installation path could not be located (110)", and on stderr "Unable to read VR Path Registry from /data/work/openvrpaths.vrpath". ~/.config/openvr/openvrpaths.vrpath on the Frame is correct (runtime /opt/steamvr).
  • Cause: the package shipped third-party/openvr/lib/linuxarm64/libopenvr_api.so. It is byte-identical to the OpenVR SDK 2.15.6's lib/linuxarm64 and looks for the path registry in the fixed path /data/work/openvrpaths.vrpath. The SDK's bin/linuxarm64 library (used by the template, verified on the Frame) and SteamVR's own one in /opt/steamvr/bin/linuxarm64 don't contain that path. OVRAS's third-party/openvr had no bin/linuxarm64.
  • Fix:
    • New file third-party/openvr/bin/linuxarm64/libopenvr_api.so from the SDK v2.15.6 (raw.githubusercontent.com/ValveSoftware/openvr/v2.15.6/bin/linuxarm64/…, SHA-256 cc3671d2…47e9).
    • CMakeLists.txt: OPENVR_LIB_DIR = bin/linuxarm64 for aarch64 only. x86_64 and Windows are unchanged.
    • Rejected: setting VR_PATHREG_OVERRIDE in the scripts. It wouldn't help when SteamVR autostarts OVRAS.
  • Result: cross build and package succeed. The package contains the new library (no /data/work), Qt_6_PRIVATE_API without QVulkan*: 0, RUNPATH $ORIGIN. Package 1.6 MB (was 3.0 MB, the old library was 5.4 MB).
  • Not tested yet: on the Frame (T1).

Finding: app key already registered by Steam (2026-10-07)

  • Third try of T1 (by hand on the Frame, with the two fixes above): VR_Init works, as Utility (vrserver.txt: "New Connect message … (VRApplication_Utility)"; SteamVR did not refuse Utility this time, unlike with the template). Then: "Manifest Previously Installed", "Could not find working directory of already installed application: VRApplicationError_PropertyNotSet".
  • Cause: Steam's generated steamapps.vrmanifest lists every owned VR app, including OVRAS (steam.overlay.1009850, launch via steam:// URL), although the Steam version is uninstalled. Not a leftover of the uninstallation; it can't be removed permanently.
  • Next: design DESIGN.md section 2a (approved 2026-10-07).
  • Implementation (setup.cpp, setup.h): as designed: key without working directory → nothing removed, AddApplicationManifest directly (error name on refusal); logApplicationEntry() after "Manifest reinstalled." logs source, launch type, working directory, binary, URL and auto-launch for the key.
  • Result: cross build and package succeed, Qt_6_PRIVATE_API without QVulkan*: 0.
  • Not tested yet: on the Frame. The log decides: AppKeyAlreadyExists or Steam's entry (steam:// URL) → own app key needed (option 2); our working directory and binary → enough.

Result on the Frame (2026-10-07, deploy with ec82b5f): SteamVR accepts our manifest (no error) but keeps using Steam's entry for the key: source: "steam" launch type: "url" working dir: PropertyNotSet binary: PropertyNotSet URL: "steam://launch/1009850/openvroverlay" auto-launch: true.

  • Consequence: the native build needs its own app key (option 2, DESIGN.md 2a, follow-up). Design pending.
  • Side effect: --force-install-manifest switched auto-launch on for Steam's key. At the next SteamVR start, SteamVR may launch steam://launch/1009850 (the uninstalled Steam version). To be switched off again.
  • OVRAS itself was started by install.sh and keeps running (not yet checked in the dashboard, T2).

Fix: debug output only with debugSymbolsAndLogs (2026-10-07)

  • Problem: the log filled with [D] updateAllPulseData done. about every 11 ms (8399 lines in 6 s). AudioTabController::eventLoopTick() reads the microphone's mute state on every tick, and every read calls updateAllPulseData() (AudioManagerPulse_internal.h:312).
  • Cause (regression in qt6): on master the message was easylogging's LOG(DEBUG), and the Debug level was disabled unless built with debugSymbolsAndLogs (ENABLE_DEBUG_LOGGING). qt6 switched to qDebug() and lost that; the constant debugLoggingEnabled in setup.cpp was left unused, so all 46 qDebug() calls were always active.
  • Fix (setup.cpp, setUpLogging()): without ENABLE_DEBUG_LOGGING, QLoggingCategory::setFilterRules("*.debug=false"). QT_LOGGING_RULES="*.debug=true" takes precedence and turns debug output on again without a rebuild.
  • Result: cross build and package succeed, Qt_6_PRIVATE_API without QVulkan*: 0.
  • Not tested yet: on the Frame (log without [D] lines; with QT_LOGGING_RULES with them).
  • Open for R6/T10: each tick makes three synchronous PulseAudio queries (server info, all sinks, all sources) for the mute state. Not changed now.

Test checklist on the Frame (step 5)

Deploy: build_scripts/steamframe/deploy-to-frame.sh <user>@<frame> (SteamVR running).

# Check Criterion Result
T1 install.sh: registration works (log: "Manifest reinstalled", via Background) R2 first try failed: abort without a display (fixed, see above); retest open
T2 Tab appears in the dashboard, UI correct (OpenGL) R2, R3 open
T3 ./run.sh vulkan: UI correct R3 open
T4 Laser right way up, click, scrolling on several pages (both APIs) R4 open
T5 Text field (e.g. new profile name): SteamVR keyboard opens, input arrives R4 open
T6 An OVRAS action arrives (e.g. push-to-talk, log/notification) R4 open
T7 Play area before/after start unchanged; log: "CommitWorkingCopy skipped" R7 open
T8 Quit app (OVRAS "Exit" and Quit in the SteamVR dashboard): no crash (both APIs) R2 open
T9 Auto-start after a SteamVR restart / reboot R2 open
T10 pidstat -p $(pgrep -f AdvancedSettings_app) 10 6: dashboard closed / OVRAS visible / other tab visible R6 open
T11 uninstall.sh unregisters it R2 open

Wrap-up (2026-10-07)

  • Remotes: origin = git@git.matzman.net:SteamFrame/OpenVR-AdvancedSettings-frame.git (branches steamframe, qt6, master); upstream = GitHub OVRAS.
  • Handover documentation: docs/steamframe/README.md (entry point), CLAUDE.md (working rules, conventions), docs/steamframe/OVRAS-FEATURES.md (feature analysis).
  • Still open in iteration 1: phase 4 (tests on the Frame, T1–T11) and phase 5 (assessment).