Files
OpenVR-AdvancedSettings-frame/docs/steamframe/PROGRESS.md
T
Matthias JanetschekandClaude Opus 5.5 4826686a4d Render through public Qt API: OpenGL and Vulkan backends, --graphics-api
Replace the QRhi rendering in OverlayController (private Qt API) with the
render backends of the vrdashboard template (src/render/), which use public
Qt API only (QQuickRenderTarget::fromOpenGLTexture / fromVulkanImage). The
binary then runs on another Qt 6 patch release, e.g. the Steam Frame's system
Qt.

The Vulkan backend also does what SteamVR requires and the QRhi path lacked:
the required instance/device extensions and the HMD's GPU (via
openvr_init::renderInterop()), VK_FORMAT_R8G8B8A8_UNORM, and the transition to
TRANSFER_SRC_OPTIMAL after each frame.

- New option --graphics-api opengl|vulkan (default opengl, no fallback).
- Shutdown() calls VR_Shutdown before the render target and Qt's device go
  (crash on the Steam Frame with Vulkan otherwise); it runs only once.
- Mouse y is flipped on every platform: SteamVR reports it in GL convention.
- Render delay 5 -> 16 ms (about 60 fps).
- GuiPrivate is no longer needed.

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

5.3 KiB

Steam Frame port: progress

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).