Repository navigation
Fix OpenXR controller bindings on non-SteamVR runtimes, and Revive call bugs - #21
Merged
Villagers654 merged 3 commits intoOct 24, 2026
Conversation
Three Vulkan entry points in the OpenXR backend and two in the OpenVR backend evaluated ovrError_InvalidParameter without returning it, so a null argument fell through to the rest of the call. The OpenVR backend's audio endpoint lookup now reads the endpoint GUID only from a string property, clears the property and frees the device id, as the OpenXR backend already does.
The OpenXR backend suggested one controller profile: Index on SteamVR, Touch elsewhere. A runtime that can't convert that profile leaves the controllers without a binding, so they never track. Monado doesn't convert Touch to WMR controllers (real ones or its simulated ones), and SteamVR may not convert Index to newer controllers such as the Steam Frame's. Touch is now always suggested, Index on SteamVR as before, and WMR's own profile everywhere; the WMR runtime keeps only its own. A rejected suggestion is traced and no longer costs the other profiles. WMR's trackpad click is bound to both A/X and B/Y and split by trackpad height. That split ran only on the WMR runtime, so with WMR bound elsewhere one left trackpad click read as X+Y, which the Menu chord turns into Menu. The backend now tracks which profile the runtime bound to each hand (INTERACTION_PROFILE_CHANGED) and splits the click whenever WMR is bound. The bound profiles are traced as interactionProfile.left/right. An explicit OpenXR launch can now use SteamVR's OpenXR runtime as well, so SteamVR gets all three suggestions and binds Touch controllers to the Touch profile directly.
…iring InitSession chained XrViewConfigurationViewFovEPIC to every view config even when XR_EPIC_view_configuration_fov isn't enabled. A struct from a disabled extension is invalid, and SteamVR fails xrEnumerateViewConfigurationViews with XR_ERROR_VALIDATION_FAILURE over it; the view fallback already derives the fov without it. A new swapchain's first image was acquired straight after xrCreateSwapchain. GE-Proton's WineOpenXR learns the image count only when the images are first enumerated and refuses that acquire with XR_ERROR_CALL_ORDER_INVALID, so the count is asked for first.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
Controllers that never track (Monado, WMR controllers, newer SteamVR controllers).
The OpenXR backend suggested a single controller profile: Index on SteamVR, Touch everywhere else. A runtime that can't
convert that one profile leaves the controllers unbound, so the hands never move. On Monado with WMR controllers, main's
bridge gets no profile on either hand (
left: (null),right: (null)in Monado's binding log).its own profile.
binds Touch controllers to the Touch profile directly.
The trackpad split follows the bound profile. WMR's trackpad click is bound to both A/X and B/Y and split by where
the thumb is on the trackpad. Main only binds WMR on the WMR runtime, where the split already runs. Now that the WMR
profile is suggested on every runtime, the split has to run wherever WMR is bound, or one left click would read as X+Y,
which the Menu chord turns into Menu. The backend follows which profile the runtime bound to each hand
(
XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) and splits the click whenever WMR is bound. The bound profiles showin the trace as
interactionProfile.left/right.Null arguments falling through. Three Vulkan entry points in the OpenXR backend and two in the OpenVR backend
evaluated
ovrError_InvalidParameterwithout returning it. With a null size pointer,ovr_GetInstanceExtensionsVkandovr_GetDeviceExtensionsVkcrash with an access violation in main's DLLs (both backends); they now return the error.Two runtime calls made spec-conformant. These come from EchoXR, where they showed up with other runtime versions.
Neither could be reproduced on the runtimes tested here (SteamVR 2.16.7, Monado, WiVRn 26.9, GE-Proton 11-3), so they
are checked for "no regression" only:
InitSessionchainedXrViewConfigurationViewFovEPICeven whenXR_EPIC_view_configuration_fovisn't enabled, whicha runtime may reject with
XR_ERROR_VALIDATION_FAILURE. It is now chained only when the extension is on; the fallbackalready derives the field of view without it.
xrCreateSwapchain. A wineopenxr that only learns the image countwhen the images are enumerated refuses that with
XR_ERROR_CALL_ORDER_INVALID, so the count is now asked for first.OpenVR audio endpoint cleanup. The OpenVR backend's endpoint lookup now reads the GUID only from a string property,
clears the property and frees the device ID, as the OpenXR backend already does.
Testing
On 0.11.1.2
The three commits apply to 0.11.1.2 unchanged. Upstream's runtime changes since the last base (swapchain retries,
SteamVR for explicit OpenXR launches, the OpenVR input lock) don't touch the same code, and the image-count query
still runs right before the first acquire, after the new retries.
tests/test_openxr_input.pypasses; so does the full suite on Linux (Python 3.10 + PySide6 6.7, 3.12 + 6.11 and3.12 + 6.12) and on macOS.
game is known to use OpenGL, Vulkan or a 32-bit build.
test games need it to get past sign-in.
left: (null),right: (null))./interaction_profiles/microsoft/motion_controlleron both (interactionProfile.left/right 3inthe trace). The trailer renders with both (5,013 and 5,025 frames).
ovrError_InvalidParameter.XR_ERROR_CALL_ORDER_INVALID.vrserver.txt):what the Quest's controllers are through Steam Link.
oculus_touch. SteamVR logs "Unable to find input profile forholographic_controller" for the WMR suggestion and loads the other three.
with both bridges (2,711 and 2,561 frames in its first 40 s).
/interaction_profiles/oculus/touch_controlleron both hands(
interactionProfile.left/right 1), in the trailer and in Lone Echo 3.17.4.sticks, A, B, X and Y. X+Y (the Menu chord) opens the pause menu; through Steam Link the left menu button opens
SteamVR's dashboard instead. In the trailer the hands and fingers follow the controllers.
menuand rightsystempaths, the two buttons it keeps for its dashboard. The rest of the Touch binding loads. Main's bridgedoesn't suggest Touch there, so it doesn't get this line.
/interaction_profiles/oculus/touch_controller.That's expected: main already suggests Touch outside SteamVR.
interactionProfile.left/right 1)and follows WiVRn when it drops and restores the controllers (
0and back to1, matching WiVRn's own log).With both bridges the trigger, grip, both sticks, A, B, X and Y work, and the pause menu opens with the left
menu button and with X+Y.
It no longer reproduces, and the cause wasn't found.
Main's build hangs there before rendering because of its shim (Platform shim: stop hanging games in Meta's uninitialized implementation #20), so the bridges weren't compared on Windows.
Earlier, on 7289ef6
All runtime tests used the fork CI's MSVC builds of main and of this branch (the platform shim fix from
fix/platform-shim-uninitializedswapped in, since the test games need it to get past sign-in).branch binds
/interaction_profiles/microsoft/motion_controlleron both.XR_ERROR_CALL_ORDER_INVALID, nothing from the OpenXR core validation layer.SteamVR, as with main's.
ovrError_InvalidParameter; both return the same audio device GUIDs.tests/test_openxr_input.pycovers the trackpad split with WMR bound on a non-WMR runtime.No UI change, so no screenshots.