KhronosGroup/OpenXR-Docs

How to handle a timeout of xrWaitSwapchainImage?

Closed this issue · 7 comments

Slin commented

The spec says:
If the timeout expires without the image becoming available for writing, XR_TIMEOUT_EXPIRED must be returned. If xrWaitSwapchainImage returns XR_TIMEOUT_EXPIRED, the next call to xrWaitSwapchainImage will wait on the same image index again until the function succeeds with XR_SUCCESS. Note that this is not an error code; XR_SUCCEEDED(XR_TIMEOUT_EXPIRED) is true.

From this I take it that a timeout is a success but it also says in the paragraph before:
Once a swapchain image has been successfully waited on, it must be released before waiting on the next acquired swapchain image.
So if the timeout is a success I'd expect that I should also release the image. However the runtime on Quest 2 complains that the image has not been waited on in such a case.

It's not clear from the spec how to react to a timeout. Should the frame be ended? Should the next frame be started? What about acquiring the swap chain image again after, or should it just wait again?

Thanks!

A swapchain can only be released once it has been fully waited (XR_SUCCESS). The reason XR_TIMEOUT_EXPIRED is a success code is because we did not want to return error codes for things that are expected to happen when the app and system are running correctly (and a timeout can be expected on some runtimes in some cases).

I would recommend either waiting for XR_INFINITE_DURATION, or waiting for less time (like 1 frame, or predictedDisplayPeriod) but putting the wait in a loop with some diagnostic tracing outside the wait if you want visibility for when it is getting throttled. But if a runtime is permanently returning XR_TIMEOUT_EXPIRED that is a runtime bug.

Slin commented

Thanks for the answer!

From your response I take it that I should do nothing but just keep waiting? No ending the frame, beginning a new one and acquiring the image again?
In this specific case it will just wait until the timeout is over and only then move on, so an infinite timeout seems scary. I am pretty sure that's a runtime issue though and I sent a bug report to Facebook, maybe someone will look at it. It keeps happening when opening an android system permission dialog. After that everything goes bad.
I worked around it for now by showing the dialog before initializing OpenXR.

I would recommend an infinite timeout in general (even the official Khronos sample app hello_xr will do this), and working with Oculus to fix the issue with the permission dialog. The swapchain state machine is relatively decoupled from the frame state machine (at least as far as the OpenXR specification is concerned), so ending a frame and starting a new one won't necessarily help, and it makes the app code more error prone because you will need to keep track of the swapchain state now (i.e. don't acquire on the next frame because the previous acquire is still not waited/released).

An issue (number 1603) has been filed to correspond to this issue in the internal Khronos GitLab (Khronos members only: KHR:openxr/openxr#1603 ), to facilitate working group processes.

This GitHub issue will continue to be the main site of discussion.

@Slin The working group discussed this and we will clarify the spec around xrReleaseSwapchainImage and timeout. Another thing that was pointed out that I had forgotten is we have this sentence in the spec which is why it is (barring runtime bugs) safe to use an infinite wait:

The runtime must eventually relinquish ownership of a swapchain image to the application and must not block indefinitely.

Slin commented

Nice! Thank you!

Clarification has shipped in 1.0.20. Thanks for the report!