KhronosGroup / OpenXR-SDK-Source

Sources for OpenXR loader, basic API layers, and example code.
https://khronos.org/openxr
Apache License 2.0
679 stars 249 forks source link

Hello_xr runs at 64-67 FPS on Quest 2 using Oculus Runtime, when set to 90 Hz. #227

Closed BattleAxeVR closed 3 years ago

rpavlik-bot commented 4 years ago

An issue (number 1476) has been filed to correspond to this issue in the internal Khronos GitLab.

If you have a Khronos account, you can access that issue at KHR:openxr/openxr#1476.

philpax commented 3 years ago

I can confirm this behaviour in both a real application and hello_xr. xrWaitFrame takes a considerable amount of time on the Oculus runtime, resulting in 60-70 FPS. Using the SteamVR runtime results in a near-solid 90 FPS.

Optick Oculus trace, where vr::PreTick is just xrWaitFrame: image

Optick SteamVR trace, 12ms frame (outlier, probably due to some frame timing adjustment required on my part)= image

bradgrantham-lunarg commented 3 years ago

Hi, @BattleAxeVR !

I've just verified that my WinMR headset here runs at a rock solid 90Hz in hello_xr. That seems to point at this issue not being with the SDK. In any case, the SDK doesn't do anything different for any particular HMD or OpenXR runtime.

The OpenXR SDK can be thought of as a thin layer of functions that call the vendor's runtime on the application's behalf (and taking care of a lot of bookkeeping so the application doesn't have to), as well as a sample program, "hello_xr".

That is to say, the OpenXR SDK is basically doing this (simplified e.g. ignoring API layers):

XrResult xrWaitFrame(...) {  // This function is in the loader
    return runtime->WaitFrame();  // The implementation of this call is provided by the vendor's runtime.
}

It's a lot like Direct3D on Windows calling the driver provided by a vendor. When you say "implementation", the "implementation" in this case is from Facebook. The OpenXR SDK doesn't "interact" or do anything with swapchains except pass them back to the app, or from the app back to the runtime.

(SteamVR is a special case, since as I understand it Valve's OpenXR implementation may be calling the non-OpenXR Oculus libraries.)

You can review the source for hello_xr and the SDK (primarily the loader, which calls the vendor's runtime on behalf of your app) to verify this. Both are in this repository. I think you'll find that the code in the SDK in xrWaitFrame between your app and the OpenXR runtime amounts when the application is running to little more than taking your function parameters and calling another function in a DLL that the OpenXR loader has loaded.

If you have identified a bug with the loader, or incompatible versions of the header, or a specification typo, this repo is a good place to open an issue.

But this isn't the right place to ask about a Quest performance problem. Since Facebook authored their OpenXR runtime, they certainly have run hello_xr themselves. So they may know about this issue and possibly how to fix it. I don't know why there hasn't been any visible progress on your issue in the Facebook Oculus developer forum, but you won't have much luck here in OpenXR-SDK-Source because OpenXR contributors reading these are focused on SDK issues.

BattleAxeVR commented 3 years ago

For anyone interested, Oculus shared the workaround with me after I raised it on their forums here:

https://forums.oculusvr.com/developer/discussion/comment/788028

You need to call timeBeginPeriod(1) before initializing anything else on Windows.

Unreal does so in WindowsPlatformMisc.cpp (587) and a few other places, like for audio.

Oculus told me they will be adding this call internally in v27 of their runtime but there's no harm in calling it multiple times so I'm going to leave it in my code.