Developing with OpenXR and Monado

The OpenXR SDK.

On Archlinux, the OpenXR loader installs these files

/usr/lib/libopenxr_loader.so*
The library that applications use for linking to OpenXR. Usually with soname symlinks: libopenxr_loader.so, libopenxr_loader.so.1 and libopenxr_loader.so.1.0.11
/usr/lib/cmake/openxr/*.cmake
cmake files that enable cmake directives like PKG_SEARCH_MODULE(OPENXR REQUIRED openxr)
/usr/lib/pkgconfig/openxr.pc
pkg-config files that can be used by cmake with FindPkgConfig or non-cmake build systems.
Run pkg-config --libs --cflags openxr to see what it provides.

Other distributions may use different paths like /usr/lib/x86_64-linux-gnu/....

The OpenXR headers

/usr/include/openxr/openxr.h
The main OpenXR API header.
/usr/include/openxr/openxr_platform_defines.h
Various platform defines used by the main OpenXR API header. Usually you don’t need to use it directly.
/usr/include/openxr/openxr_platform.h
The part of the OpenXR API that is platform specific.
Before including this header, add defines for the parts you want to use, e.g.
#define XR_USE_PLATFORM_XLIB
#define XR_USE_GRAPHICS_API_OPENGL
/usr/include/openxr/openxr_reflection.h
Not necessary, but useful for iterating over OpenXR enums, or getting string representations of OpenXR enum values.

To start developing for OpenXR only those components are necessary. Similar to how Vulkan applications are developed by including Khronos’ Vulkan headers and linking to Khronos’ Vulkan loader, OpenXR applications include Khronos’ OpenXR headers and link to Khronos’ OpenXR loader. Just like compiling a Vulkan application does not require any Vulkan driver to be installed, compiling an OpenXR application does not require any OpenXR runtime to be installed.

Khronos has not released a reference implementation for OpenXR, so for actually running an OpenXR application some vendor’s OpenXR runtime (for example Monado) has to be installed.

Setting up the project

CMake

Here is a minimal cmake example to compile an example executable that can include OpenXR headers and links to the OpenXR loader.

cmake_minimum_required(VERSION 3.0.0)
project(Example)
add_executable(example main.c)
find_package(OpenXR REQUIRED)
if(OpenXR_FOUND)
target_include_directories(example PRIVATE OpenXR::Headers)
target_link_libraries(example PRIVATE OpenXR::openxr_loader)
else()
MESSAGE(FATAL_ERROR "Please verify your OpenXR SDK installation")
endif()

As an alternative you can use OpenXR’s pkg-config file with CMake’s FindPkgConfig module.

cmake_minimum_required(VERSION 3.0.0)
project(Example)
add_executable(example main.c)
INCLUDE(FindPkgConfig)
PKG_SEARCH_MODULE(OpenXR REQUIRED openxr)
if(OpenXR_FOUND)
target_link_libraries(example PRIVATE ${OpenXR_LIBRARIES})
target_include_directories(example PRIVATE ${OpenXR_HEADERS})
else()
MESSAGE(FATAL_ERROR "Please verify your OpenXR SDK installation")
endif()

Application.

With this project setup you can start including the <openxr/openx.h> header and start calling OpenXR functions.

As a starting point, here is a minimal C example for starting an OpenGL application on Linux with the xlib graphics binding.

// openxr_platform.h does not include all its dependencies, we have to include some headers before it
#include <string.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
// before including openxr_platform.h we have to define which platform specific parts we want enabled
#define XR_USE_PLATFORM_XLIB
#define XR_USE_GRAPHICS_API_OPENGL
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
int main()
{
char *extensions[] = { XR_KHR_OPENGL_ENABLE_EXTENSION_NAME };
int extension_count = sizeof(extensions) / sizeof(extensions[0]);
XrInstanceCreateInfo instanceCreateInfo = {
.type = XR_TYPE_INSTANCE_CREATE_INFO,
.next = NULL,
.createFlags = 0,
.enabledExtensionCount = extension_count,
.enabledExtensionNames = (const char * const *) extensions,
.enabledApiLayerCount = 0,
.applicationInfo = {
.applicationVersion = 1,
.engineVersion = 0,
.apiVersion = XR_CURRENT_API_VERSION,
},
};
strncpy(instanceCreateInfo.applicationInfo.applicationName, "Example Application", XR_MAX_APPLICATION_NAME_SIZE);
strncpy(instanceCreateInfo.applicationInfo.engineName, "Example Engine", XR_MAX_APPLICATION_NAME_SIZE);
XrInstance instance;
xrCreateInstance(&instanceCreateInfo, &instance);
return 0;
}