XRTraits C++ OpenXR Utilities
|
OpenXR, based largely in the practice developed in Vulkan, has a system where most structure types contain two "meta" members to provide polymorphism and extensibity.
XrStructureType type;
, which is defined to contain a value representing the dynamic type of a structure (its run-time type - contrast with static type, which is known at compile time)void* next;
or const void* next;
(depending on the usage of a struct), which is intended for use mainly by extensions and future revisions of the spec.The next
member is either nullptr
or points to some other structure type that begins with type
and next
members. Thus, these next
pointers form a singly-linked list of structures that can be queried for their dynamic type.
Types like this are sometimes referred to in this library and its documentation as "XR tagged types" or "XR tagged structs" since they contain a member tagging them with their dynamic type, as in a discriminated/tagged union type. Most but not all XR tagged types are associated with a distinct value of the XrStructureType
enum. This association is made in the XML registry for OpenXR - look at the "values" attribute of the member tag wrapping type
for any such struct to see its corresponding enum value ("type tag").
For example, XrInstanceCreateInfo
is associated with XR_TYPE_INSTANCE_CREATE_INFO
as this is found in its definition in the registry:
This library originated with some C++11/14 "type traits" that are generated from the XML registry specification of OpenXR to support type-safe usage of these next chains - see xrtraits::traits.
It is important to note that this library can wrap all "type-unsafe" operations with OpenXR structs. With these utilities, it is possible to completely avoid using reinterpret_cast()
directly: use the higher-level constructs instead. The type-safety checks of clang-tidy have been left enabled since these generic high-level constructs locally suppress those warnings in their implementation.
Because of the dynamic typing possibility of OpenXR structs, it is important to distinguish "pointers to structs we got from somebody else" from "references to structs with verified dynamic type". This library includes the xrtraits::DynamicVerified<T> type template which wraps a pointer to an OpenXR tagged struct type, acting just like a pointer but asserting that the dynamic type has been checked to match with the static OpenXR struct type T
. For the sake of simplicity, we will use XrInstanceCreateInfo
as the example type here, but all XR tagged types with known tag can be substituted in place of XrInstanceCreateInfo
. The transition from a passed-in XrInstanceCreateInfo *
(which might be null, or might have the wrong dynamic type), to code that can safely assume that they have a pointer/reference to an OpenXR struct with a known type, should only take place once for each parameter, and ideally should be distinguished in a compiler-checked way. The Dynamic Typing verification tools provide both verification and type-checked distinction. Calling xrtraits::verifyDynamicType() performs null pointer checking, verification of dynamic type, and wrapping the pointer in a DynamicVerified
type to indicate to code elsewhere that they can rely on the static type. In most cases, code outside of externally-exposed APIs should only deal with types already wrapped in DynamicVerified
or a related safe type.
xrtraits::DynamicVerifiedOrNull is a related type that is weaker than DynamicVerified. It only asserts that if the contained pointer is not null, then the dynamic type matches. However, since it can be used to store/pass a null pointer, it can be used with optional parameters.
If you need to create an OpenXR tagged type on the stack, you may use xrtraits::Initialized<T> instead of creating it directly. This automatically zeros the memory and initializes the type
member appropriately. If you pass another such type, it will set the next
pointer for you as well, to create chained structures. (Any additional arguments passed to the constructor are forwarded to the struct initializer itself after type
and next
.) It also (weakly) conceals the type
and next
members from your code, to make it harder to accidentally modify these values. If you're in search of a collection of OpenXR structs, look into xrtraits::make_zeroed_vector(). However, if you need a collection of empty structs, you might be trying to use the two-call idiom, in which case see functionality in TwoCall.h to simplify it further.
For this page only:
Copyright 2018-2019 Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0