The Dawn of OpenXR

Rune Berg
6 min readJan 4, 2021

2020 is arguably forever etched in the memory of many for a variety of reasons that transpired in the world stage. One of it for me is the release of the OpenXR spec and my later involvement on “last mile” efforts around SteamVR’s implementation.

My day-to-day work with Valve as a full time contract developer is often enjoyable, never dull, but also quite challenging — OpenXR is no exception.

Image from Khronos Group under the Creative Commons Attribution 4.0 International License

And with the rare holiday break I give myself, I thought I’d start an open source project that’ll help solidify some of the stuff I’ve learned from the past year developing on this api, create a pet project for the upcoming year and potentially help other XR developers (incl. future me) in using OpenXR for their XR projects/tasks.

So was born the…

OpenXR Provider Library
https://github.com/1runeberg/OpenXRProvider

Imagine building a typical picket fence but you have to fell the tree yourself and cut all the wooden bits to the appropriate size and shape.

Using the raw OpenXR Loader library can be somewhat akin to this. With a lot of granular steps you need to do in just the right order to effectively access the various OpenXR compatible runtimes (SteamVR, Oculus, WMR, Monado, etc).

The goal of the OpenXR Provider library therefore is to provide (pun intended) “last mile” developers such as application and engine developers a simpler method to take advantage of OpenXR without having to wade through its intricacies.

“Create-and-play” is the new “plug-and-play”

One of the keys to making this happen in the OpenXR Provider library’s design is centred around classic object instantiation.

Instantiating key objects provided by the library will trigger all the necessary OpenXR calls and create the key connections and states with the active OpenXR runtime — ready to be consumed by the application.

This basic operation alone can take several dozen to more than a hundred lines of code when done via the raw OpenXR Loader library. Not counting having to keep track of raw OpenXR objects that need to be destroyed in their proper order after use. So you could see how this library can potentially shave hours of work and troubleshooting for application or engine developers.

In that note, to save myself writing a thousand words, here’s a diagram of the library’s object creation process and the stuff that gets made in OpenXR behind the scenes:

As of this writing. the XR Input Manager is not yet done, hence its greyed out currently in the diagram

Hindsight is 20/20 — so Extensibility is Queen

It’s a bit strange to start with the Extension system when discussing the core parts of this library, but creating an instance in OpenXR which is one of the first steps in establishing a connection with a runtime (e.g. SteamVR, Oculus, WMR), requires you to specify any extensions you wish activated beforehand.

As an OpenXR extension can pretty much do anything, the library uses custom objects derived from an abstract class (XRBaseExt). Allowing for the flexibility required.

These extension objects and via the Event Handler can also potentially be used to “augment” other OpenXR system implementations in a future release (e.g. a developer can create their own OpenXR extension implementation and add it to popular game engines with their own built-in OpenXR System support).

Image from Khronos Group under the Creative Commons Attribution 4.0 International License

For this early version of the library, I’ve added an implementation of the Khronos Visibility Mask extension which most of the major OpenXR runtimes such as SteamVR support.

A visibility mask is an occlusion mesh that tells the application areas in an eye texture where it should render and/or areas that it shouldn’t need to as they will not appear in the user’s headset, therefore saving on precious rendering resource cost.

Earlier in the year I’ve actually created a tool that helps visualize this mesh and may help for further understanding its use:

VR Hidden Area Mask (Visibility Mask) Previewer
https://github.com/1runeberg/VRHiddenAreaMaskPreviewer

One impetus for me to use the visibility mask as a first extension implementation in this library (technically second, but I’m getting ahead of myself) — is a known issue which I’ve been meaning to work on more closely is SteamVR providing extra vertices in its visibility mask line loop type. So I now have an immediate and practical use for this new library on my first day back at work in 2021.

Oh and one more thing (about extensions)…

Noticed anything unusual in the object creation diagram earlier? Hint: have a closer look at the XR Render Manager and the Graphics API object.

You’d naturally think being a “Render” manager, it should be creating the Graphics API object who’s use is to handle 3D graphics api (OpenGL, DirectX, Vulkan, etc) specific tasks.

Image from Khronos Group under the Creative Commons Attribution 4.0 International License

The reason the XR Provider instantiates this object and starts at so early in the process is that a Graphics API implementation is actually an extension as well in OpenXR. And so this object is a special extension object that gets automatically created depending on the compiled library version (as of this writing only OpenGL is supported with other 3D apis to follow).

And as you learned from the previous section, extensions need to be pre-advertised before instance creation, so the graphics api (extension) object must be created early on which then creates a session — which informs the runtime that the application intends to begin rendering to the user’s headset.

Render Manager

Which brings us to the Render Manager which actually manages all the rendering operations. Its responsible for starting an OpenXR session (the one created by the Graphics API extension object).

It also creates the swapchain which at the risk of oversimplifying, is a container that holds metadata and the textures in a graphic api specific format (GL_RGBA16, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, etc). that applications will use to render to.

The textures being graphics api dependent, are created by the Graphics API object but on the prompting of the XR Render Manager at the appropriate time in the session lifecycle .

All that is certain is change

An XR application is a highly dynamic beast and a lot of things can and does happen during its lifetime. OpenXR deals with this by broadcasting events which provides applications an opportunity to react.

The library exposes an Event Handler accessed via the main XR Provider object. Applications can register (and de-register) their own functions to these OpenXR events.

Registered functions are then called by the OpenXR Provider library when the appropriate event is triggered along with a data payload about the particular event (e.g. visibility mask configuration has changed, runtime wants to close the application, etc).

And that’s all the key components of the library so far.

If you’ve made it this far, thanks and hopefully you’ve picked up a thing or two for your own journey with OpenXR. 2021 is as good a year as any with various runtimes such as SteamVR, Oculus, WMR, and Monado polishing daily their respective implementations of this new standard.

Its very existence, a miracle in of itself… but that’s another story for another time and space ;)

Library source code at: https://github.com/1runeberg/OpenXRProvider

--

--