chromium/device/vr/openxr/README.md

# OpenXR

*The OpenXR specification writes its name as 'OpenXR'; however, the Chrome
style guide requires us to write this as 'OpenXr' in code, when talking about
the system as a whole, we will use 'OpenXR' and will use 'OpenXr' only for
specific classes for accuracy.*

This directory contains Chrome's OpenXR integration. That is to say, this
code translates WebXR requests into OpenXR API Calls, and translates the data
from OpenXR into the more generic device interfaces (which are typically mojom),
that ultimately get translated into WebXR types.

## General Architecture

The main entry point to OpenXR is via an [`OpenXrDevice`](openxr_device.h).
Depending on the platform, this may be directly created by a more general
purpose device provider (e.g. Windows and the [Isolated Xr Device service][xr_device_service])
or by a specific `OpenXrDeviceProvider` (e.g. [Android's](../../../components/webxr/android/openxr_device_provider.h)).
It is a good idea to try to create both an `XrInstance` and an `XrDevice` via
the OpenXR API before creating an `OpenXrDevice`, as that will indicate that a
session can *actually* be created. This `OpenXrDevice`, when requested for a
session will create and maintain an [`OpenXrRenderLoop`](openxr_render_loop.h).
This `OpenXrRenderLoop` will create an [`OpenXrApiWrapper`](openxr_api_wrapper.h),
which is largely responsible for handling the `XrSession` object. The
`OpenXrRenderLoop` and `OpenXrApiWrapper` between themselves will create a
number of helper objects to abstract various aspects of the API (e.g. [OpenXrInputHelper](openxr_inut_helper.h)
and [OpenXrExtensionHelper](openxr_extension_helper.h)). Classes that depend
solely on the core spec can be created directly by the render loop or API
wrapper; but classes that rely on extension methods should be created by the
extension helper.

## Platform Support

Currently, we only support OpenXR on Android and Windows. The vast majority of
the code that we use is cross-platform, but some things (i.e. rendering) are
inherently platform-specific. The `OpenXrPlatformHelper` is used to abstract out
anything that is especially platform-specific, including deciding what kind of
`OpenXrGraphicsBinding` should be used (e.g. to use DirectX on Windows and
OpenGLES on Android). At a minimum to extend platform support you will likely
need to create an implementation of these two interfaces. The specific platform
helper will likely be chosen by either platform-specific ifdefs at construction
or via the device provider mechanism.

## OpenXR Extensions

OpenXR methods provided by an extension and tied to a session should be created
via and stored on the `OpenXrExtensionHelper` and corresponding
`OpenXrExtensionMethods` struct. This helps to avoid multiple instances of a
class that wants to use the method needing to load the method. These methods
should either be checked for their own validity or that the extension which
guards them is enabled before their use. The base class [`OpenXrPlatformHelper`](openxr_platform_helper.h)
is ultimately responsible for building the list of extensions that we wish to
enable on a session based on whether the functionality is required or optional.

Code that leverages extensions wholly or in part to supply the necessary data to
WebXR should typically be wrapped in their own classes, with the ordering in [`GetExtensionHandlerFactories`](openxr_extension_handler_factories.cc)
serving as the factory/arbiter of which class is created based upon the
prioritization of classes due to enabled extensions. This enables us to support
WebXR features with a variety of extensions when multiple ones exist that
surface similar functionality in ways that are (usually) device specific.
Support for these classes and a declaration of their requirements (in the form
of needed extensions), is provided by implementing an [`OpenXrExtensionHandlerFactory`](openxr_extension_handler_factory.h)
and adding it to the [`GetExtensionHandlerFactories`](openxr_extension_handler_factories.cc)
list. Entries in the list should generally be grouped by the type of data that
they can handle and then ordered by priority in that group (the creation code
will create the first handler that provides the data that it wants), with
platform-specific extensions usually coming first.

Extension handlers for XR_EXT_ and XR_KHR_ extensions should be placed in
//device/vr/openxr, whereas code to handle other extensions should be placed in
a subfolder matching the extension vendor (e.g. fb/ for XR_FB_ or msft/ for
XR_MSFT_).

## Input

All input sources for WebXR must support at a bare minimum the ability to be
tracked and to send up a "primary input button" (essentially a click). Adding
a new input source will always require an entry to [openxr_interaction_profile_type.mojom](../public/mojom/openxr_interaction_profile_type.mojom),
and an entry to `GetOpenXrInputProfilesMap` in [openxr_interaction_profiles.cc](openxr_interaction_profiles.cc)
to define the types of profiles that are supported. From there there are two
potential paths to finish adding support via OpenXR.

### Interaction Profiles

If the device has an associated set of interaction profiles that can be bound to
actions, this is the easiest (and preferred) way to add support. A button map
simply needs to be built in `GetOpenXrControllerInteractionProfiles` in [openxr_interaction_profiles.cc](openxr_interaction_profiles.cc).
Any required extension for the profile will automatically be enabled on the
session if the runtime supports it by the setup code. New button types can be
added and extended as needed. The base path of the interaction profile must be
defined as a constant in [openxr_interaction_profile_paths.h](openxr_interaction_profile_paths.h),
for compatibility with tests. If the interaction profile should have hand input
enabled for it, the required extension should also be added to the list in the
[OpenXrHandTrackerHandlerFactory](openxr_hand_tracker.h).

### Hand Gesture Extensions

The secondary means of adding interaction profile support depends upon extension
methods to the XR_EXT_hand_tracking structs. After the initial enum and profile
map has been added, simply extend [OpenXrHandTracker](openxr_hand_tracker.h),
which has some more detailed instructions. [OpenXrHandTrackerAndroid](android/openxr_hand_tracker_android.h)
is an example of a class that extends `OpenXrHandTracker` to provide such
support. Note that you are still responsible for ensuring that your extension is
enabled when available and providing a means to create your new class as
described in [OpenXR Extensions](#openxr-extensions).

[xr_device_service]: https://source.chromium.org/chromium/chromium/src/+/main:content/services/isolated_xr_device/README.md