Copyright 2014-2024, The Khronos Group Inc.
This work is licensed under a Creative Commons Attribution 4.0 International License.
1. Introduction
This document contains required procedures and conventions when writing specifications for new OpenXR APIs, extensions and layers, or related Khronos documentation such as white papers and tutorials; or contributing to existing OpenXR specifications. These are collectively referred to as OpenXR Documentation or just documentation below. The primary focus is the API Specification and API extensions, although all of the markup and most of the writing style is equally applicable to other documentation.
It should be noted that the OpenXR Documentation has been branched from the Vulkan documentation. A deliberate decision was made to keep the API standards similar, although this may diverge over time as changes are made to either standard. The OpenXR version of this style guide is also influenced by the proposal that was adopted as a starting point for the OpenXR specification.
The primary purpose is to achieve consistency across the API, as well as across all of our source and output documents. Consistency makes it easier for developers, editors, reviewers, and users of our documentation to understand and modify it.
Unless explicitly stated otherwise, the procedures and conventions must be followed when making changes or additions to the OpenXR specification. If you have a strong desire to modify the procedures and conventions, such changes must be made through the normal OpenXR Working group process.
Note that some conventions in naming and API design that would be relevant to a user of the standard are discussed in the "Fundamentals" and "Appendix" chapters of the specification itself. If a contradiction is found, the specification itself takes precedence, and normal working group procedures should be followed to correct this style guide.
1.1. Terminology
The key words must, required, should, recommend, may, and optional in this document are to be interpreted as described in RFC 2119.
1.2. Document Structure
The style guide is broken into five sections:
-
API Naming Conventions - the required rules for choosing names of OpenXR identifiers of all types.
-
Extensions and Layers - the required procedures for creating formal OpenXR extensions and layers.
-
Markup Style - the required and recommended markup style for writing asciidoc and XML source that follows consistent formatting and layout guidelines, tags special terms and phrases for proper processing by the spec generation tools, etc.
-
Writing Style - the required and recommended writing style for overall and fine-grained structure and conventions, normative language use, API naming conventions, common words and phrases to use and to avoid, linking and cross-referencing, etc.
-
Registry XML Schema - a brief description of the XML registry format as well as the declarative schemas and tools available to assist in verification of changes.
1.3. Asciidoc Markup
OpenXR Documentation is primarily written in Asciidoc, a form of text markup language. Specifically we’re using the version of Asciidoc that is actively maintained by asciidoctor, which is documented on its website at http://www.asciidoctor.org/.
References to the Asciidoctor User Manual are to sections in the document at http://asciidoctor.org/docs/user-manual/.
Asciidoctor is implemented in Ruby (https://www.ruby-lang.org/), which is
available for Linux, MacOS, and Microsoft Windows.
Multiple preview tools also exist for the language, primarily using
AsciidoctorJ (https://github.com/asciidoctor/asciidoctorj) or asciidoctor.js
(https://github.com/asciidoctor/asciidoctor.js).
In particular, GitHub and GitLab both have asciidoc previews for .adoc
or
.asciidoc
files in repositories, and live preview extensions exist for
Chrome and Firefox.
The Asciidoctor toolchain and build process are not addressed by this document, which concentrates solely on source documents.
1.4. Normative References
Normative references are references to external documents or resources to which documentation authors must comply.
International Organization for Standardization, Data elements and interchange formats — Information interchange — Representation of dates and times, http://www.iso.org/iso/catalogue_detail?csnumber=40874, 2004-12-01. Also see https://www.w3.org/QA/Tips/iso-date for colloquial examples.
2. API Naming Conventions
Identifiers in the OpenXR API (e.g. types, parameters, constants, etc.) all follow a set of naming rules, providing a consistent scheme for developers.
The OpenXR C API uses prefixes as an implicit namespace control mechanism. Bindings to other languages can choose not to use these prefixes if the language provides an explicit namespace mechanism.
2.1. General Naming Rules
Names of identifiers should generally be written with full words, avoiding
abbreviations, as a concise description of what that identifier is.
For example, the type of a structure containing information about how to
create an instance is XrInstanceCreateInfo
.
Abbreviations and prefixes are sometimes used in the API when they are in common use.
All abbreviations and prefixes used in the API must be approved by the OpenXR working group, and be added to the Common Abbreviations and Standard Prefixes sections, respectively.
Whenever an abbreviation exists for a particular word, it should be used in place of the full word unless there is good reason not to.
2.2. Preprocessor Defines
Preprocessor definitions include an underscore _
as a delimiter between
words, with every character in upper case.
Each definition is prefixed with XR_
, followed by the name.
This rule applies to most declarations with the C Preprocessor’s #define
token, including macros and constants.
There are however a few exceptions:
-
The header guard for each header includes an additional underscore
_
at the end of the identifier.-
Example:
OPENXR_H_
-
-
Definitions that denote the presence of an extension follow the extension name string convention.
-
Example:
XR_KHR_opengl_enable
-
-
Three
XRAPI_*
definitions are defined by the platform header to alias certain platform-specific identifiers related to calling conventions.-
Examples:
XRAPI_ATTR
,XRAPI_CALL
andXRAPI_PTR
-
-
The C preprocessor may be used to create aliases between other OpenXR identifiers, which could happen if a determination is made that something has been misnamed. In these cases, the fixed name is added to the API, and the old name is made into an alias of that. In these cases, the name will be whatever the original misnamed identifier was.
// Provided by XR_VERSION_1_0
#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL)
// Provided by XR_VERSION_1_0
// OpenXR current version number.
#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 34)
2.3. Type Names
Type names are declared with no separator between words. Each word starts with a capital letter, and other characters in each word are lower case.
Each type name is prefixed with Xr
.
This rule applies to all type definitions except function pointer types, including struct and union types, handles, base typedefs, and enumerant types.
XR_DEFINE_HANDLE(XrInstance)
typedef uint64_t XrFlags64;
typedef enum XrStructureType {
...
} XrStructureType;
typedef struct XrInstanceCreateInfo {
XrStructureType type;
const void* next;
XrInstanceCreateFlags createFlags;
XrApplicationInfo applicationInfo;
uint32_t enabledApiLayerCount;
const char* const* enabledApiLayerNames;
uint32_t enabledExtensionCount;
const char* const* enabledExtensionNames;
} XrInstanceCreateInfo;
2.3.1. Extension Structure Names
Structures which extend other structures through the next
chain should
reflect the name of the base structure they extend, or the role that they
play.
Examples of the "role" guideline include:
-
GraphicsBinding
structures in theXrSessionCreateInfo
next
chain -
XrSpaceVelocity
in theXrSpaceLocation
next
chain
New non-KHR
structures which add extended object creation parameters to a
base structure should use this naming scheme:
Base Structure Name | Extension Structure Name |
---|---|
|
|
Object
is the name of the object being created.
Name
is a short name for the extension or the new information added by
that extension.
Author
is the author ID of the extension.
2.4. Enumerant Names
Enumerants include an underscore _
as a delimiter between words, with
every character in upper case.
Each enumerant name is prefixed with XR_
.
Enumerants are prefixed with the exact name of the type it belongs to,
converted to the correct case (e.g. XrEyeVisibility
→
XR_EYE_VISIBILITY_LEFT
), and with the extension author indication moved to
the end.
This rule applies to all enumerants, with some exceptions.
-
The
XrStructureType
enumerants begin withXR_TYPE
instead ofXR_STRUCTURE_TYPE
. -
Flag types do not use
FLAGS
in the name (e.g.XrSpaceLocationFlags
usesXR_SPACE_LOCATION_POSITION_VALID_BIT
instead ofXR_SPACE_LOCATION_FLAGS_POSITION_VALID_BIT
). -
The
XrResult
enumerants are split into two sub types: error and success codes.-
Success codes are prefixed with
XR_
. -
Error codes are prefixed with
XR_ERROR_
.
-
-
Some graphics API names are exceptions to this rule, see Naming Exceptions
typedef enum XrStructureType {
XR_TYPE_API_LAYER_PROPERTIES = 0,
XR_TYPE_EXTENSION_PROPERTIES = 1,
...
} XrStructureType;
typedef XrFlags64 XrSwapchainCreateFlags;
// Flag bits for XrSwapchainCreateFlags
static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT = 0x00000001;
static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT = 0x00000002;
typedef enum XrResult {
XR_SUCCESS = 0,
...
XR_ERROR_SESSION_RUNNING = -3,
...
} XrResult;
// Provided by XR_KHR_android_thread_settings
typedef enum XrAndroidThreadTypeKHR {
XR_ANDROID_THREAD_TYPE_APPLICATION_MAIN_KHR = 1,
XR_ANDROID_THREAD_TYPE_APPLICATION_WORKER_KHR = 2,
XR_ANDROID_THREAD_TYPE_RENDERER_MAIN_KHR = 3,
XR_ANDROID_THREAD_TYPE_RENDERER_WORKER_KHR = 4,
XR_ANDROID_THREAD_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
} XrAndroidThreadTypeKHR;
2.5. Function Names
Function names are declared with no separator between words. Each word starts with a capital letter, and every other character in each word is lower case.
Function names are prefixed with xr
.
This rule applies to all function declarations.
XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance( ... );
XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem( ... );
2.5.1. Function Pointer Type Names
Function pointer names are declared exactly as the equivalent statically
declared function would be declared, but prefixed with PFN_
, standing for
"Pointer to FunctioN".
typedef XrResult (XRAPI_PTR *PFN_xrCreateInstance)( ... );
2.6. Function Parameter and Struct/Union Member Names
Function parameter names are declared with no separator between words. Each new word, except for the first, starts with a capital letter. All other characters in the parameter name are in lower case.
Members/parameters of a type that is not a base type should generally be named in a similar way to the type itself, with additional context added for clarity when necessary.
Any member that describes the size of a memory allocation should be suffixed
with Size
, or CapacityInput
in the case of the input parameter to the
two-call idiom.
Any member that describes the number of something, such as an array length
or number of internal allocations, should be suffixed with Count
, or
CountOutput
in the case of the count output parameter to the two-call
idiom.
The size
rule overrides this rule, though it is possible to have multiple
sizes (e.g. sizeCount
).
If the member is an array length, then the name of length should correspond
to the name of the array member, usually xyzCount
for an array named
xyzs
.
If a member of a chained extension structure is an array whose length must
match the length of an array of the base structure, then the chained
extension structure should include an array length member with the same name
as the length in the base structure.
2.6.1. Two-call Idiom Parameter Names
The two-call idiom for buffer size parameters uses names as follows.
-
For arrays of typed structures that are not strings or byte buffers, naming is based on a noun describing a single item. In this example, we will use
item
as that noun.-
The first parameter should be the singular noun followed by
CapacityInput
. e.g.itemCapacityInput
-
The second parameter should be the singular noun followed by
CountOutput
. e.g.itemCountOutput
-
The third parameter (the array output) should be the item noun pluralized. e.g.
items
.
-
-
For byte buffers or strings (
char
arrays), the following parameter names are used:-
bufferCapacityInput
-
bufferCountOutput
-
buffer
-
This naming is enforced by the xml_consistency
script.
If your item name is unusual to pluralize (e.g. "index" → "indices") the
script may need modification.
// Provided by XR_VERSION_1_0
XrResult xrGetInputSourceLocalizedName(
XrSession session,
const XrInputSourceLocalizedNameGetInfo* getInfo,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
typedef struct XrFrameEndInfo {
XrStructureType type;
const void* next;
XrTime displayTime;
XrEnvironmentBlendMode environmentBlendMode;
uint32_t layerCount;
const XrCompositionLayerBaseHeader* const* layers;
} XrFrameEndInfo;
// Provided by XR_EXT_debug_utils
typedef struct XrDebugUtilsMessengerCreateInfoEXT {
XrStructureType type;
const void* next;
XrDebugUtilsMessageSeverityFlagsEXT messageSeverities;
XrDebugUtilsMessageTypeFlagsEXT messageTypes;
PFN_xrDebugUtilsMessengerCallbackEXT userCallback;
void* userData;
} XrDebugUtilsMessengerCreateInfoEXT;
// Provided by XR_VERSION_1_0
XrResult xrPollEvent(
XrInstance instance,
XrEventDataBuffer* eventData);
CapacityInput
and CountOutput
// Provided by XR_VERSION_1_0
XrResult xrEnumerateApiLayerProperties(
uint32_t propertyCapacityInput,
uint32_t* propertyCountOutput,
XrApiLayerProperties* properties);
// Provided by XR_VERSION_1_0
typedef struct XrCompositionLayerProjection {
XrStructureType type;
const void* next;
XrCompositionLayerFlags layerFlags;
XrSpace space;
uint32_t viewCount;
const XrCompositionLayerProjectionView* views;
} XrCompositionLayerProjection;
2.6.2. Naming exceptions
There are a few graphics API-related names that have specific capitalization that are an exception to these rules:
-
Direct3D, usually shortened to D3D, followed by a version number with no delimiter. Left as-is in all names, e.g.
D3D11
-
OpenGL
-
OpenGL ES -
OpenGLES
in function and type names, andOPENGL_ES
in enumerants.
2.7. Extension Identifier Naming Conventions
Identifiers defined by an extension are modified by appending the extension’s author ID to the end of the identifier, as described below. Author IDs are obtained as described in the Extension and Layer Naming Conventions section.
If an extension becomes part of core, a new version of the extension’s identifiers should be created, that do not contain the author ID at the end of the identifier. The original identifiers should be kept in order to maintain source-level compatibility with existing software.
2.7.1. Extension Type Names
Types defined by extensions have the author ID appended to the end of the type name.
KHR
Appended// Provided by XR_KHR_vulkan_enable
typedef struct XrGraphicsBindingVulkanKHR {
XrStructureType type;
const void* next;
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamilyIndex;
uint32_t queueIndex;
} XrGraphicsBindingVulkanKHR;
2.7.2. Extension Enumerant Names
Enumerants defined by extensions will have the author ID appended to the end of the enumerant name, separated by an underscore. This includes the begin, end, range and max values added to enumeranted type definitions by the generator scripts.
_EXT
Appended// Flag bits for XrDebugUtilsMessageTypeFlagsEXT
static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001;
static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002;
static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004;
static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT = 0x00000008;
2.7.3. Extension Function Names
Function and function pointer type names defined by extensions have the author ID appended to the end of the name.
KHR
Appended// Provided by XR_KHR_vulkan_enable
XrResult xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
KHR
Appendedtypedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
2.7.4. Extension Interaction Profile Names
Interaction Profile names defined by extensions have the author ID appended to the end of the name.
<extensions>
<extension name="XR_KHR_loader_init" number="89" type="instance" supported="openxr">
<require>
<enum value="1" name="XR_KHR_loader_init_SPEC_VERSION"/>
<enum value=""XR_KHR_loader_init"" name="XR_KHR_LOADER_INIT_EXTENSION_NAME"/>
<interaction_profile name="/interaction_profiles/khr/flux_compensator_khr"/>
</require>
</extension>
</extensions>
2.8. Common Abbreviations
Abbreviations and acronyms are sometimes used in the OpenXR API Specification and the OpenXR API where they are considered clear and commonplace. All such abbreviations used in the core API are defined here. Extensions should also use these abbreviations where appropriate.
- Src
-
Source
- Dst
-
Destination
- Min
-
Minimum
- Max
-
Maximum
- Rect
-
Rectangle
- Info
-
Information
- Bool
-
Boolean
Exceptions may be made for historical reasons. If that decision is made these exceptions may be noted here. |
- Addr
-
Address
- ID
-
Identifier
- UUID
-
Universally Unique Identifier
- Op
-
Operation
- R
-
Red color component
- G
-
Green color component
- B
-
Blue color component
- A
-
Alpha color component
- D3D
-
Direct3D
- D3D10
-
Direct3D 10.x
- D3D11
-
Direct3D 11.x
- D3D12
-
Direct3D 12
- Perf
-
Performance
2.9. Standard Prefixes
Prefixes are used in the API to denote specific semantic meaning of OpenXR names, or as a label to avoid name clashes, and are explained here:
- XR/Xr/xr
-
OpenXR namespace
All types, commands, enumerants and C macro definitions in the OpenXR specification are prefixed with these two characters, according to the rules defined above. - PFN
-
Function Pointer
Denotes that a type is a function pointer.
3. API Layers & Extensions
This chapter describes required and recommended processes for writing formal extensions and API layers for the OpenXR API. It is concerned with mechanical processes and registration, while fine-grained naming conventions are included in the API Naming Conventions chapter. The organizational processes behind extension creation are in a separate document, the OpenXR Working Group Extension Processes.
3.1. Introduction
The Khronos extension registries and extension naming conventions serve several purposes:
-
Avoiding naming collisions between extensions developed by mutually unaware parties, both in the extension names themselves, as well as their token, command, and type names.
-
Allocating enumerant values for tokens added by extensions.
-
Creating a defined order between extensions. Extensions with higher numbers may have dependencies upon extensions with lower numbers, and must define any relevant interactions with lower-numbered extensions.
-
Provides a central repository for documentation and header changes associated with extensions
Vulkan — on which OpenXR leans heavily for its design — introduced new paradigms that required rethinking the existing design practices:
-
API layers, and with them a focus on a more open ecosystem where non-Khronos members are expected to extend a Khronos API using the API layer mechanism.
-
Namespaced constants (enumerations) that do not necessarily draw from a single global set of token values.
OpenXR continues to use the standards that were adopted by Vulkan, with some adaptations.
3.2. General Rules/Guidelines
Some general rules to simplify the specific rules below:
-
Extensions and API layers must each have a globally unique name.
-
All commands and tokens must have a globally unique name.
-
Extensions can expose new commands, types, and/or tokens, but API layers must not.
-
However, API layers can expose their own extensions, which in turn are allowed to expose new commands and tokens.
-
-
All extensions must be registered with Khronos.
-
Callbacks supplied by the application are discouraged in extensions. Prefer polling or event patterns.
3.3. Extension and API Layer Naming Conventions
Extensions and API layers have formal names. These names are used in a variety of places:
-
When specifying extensions and API layers to enable in the API.
-
As a preprocessor symbol in the
openxr.h
andopenxr_platform.h
header files indicating that an extension interface is defined at compile time. -
To control building the OpenXR Specification from asciidoc source containing many extension, by explicitly enabling inclusion of one or more extensions.
Note
OpenXR uses a “single-branch” model in which extensions can optionally be included or not from a single set of source documents. In contrast with Vulkan, OpenXR also limits most extensions to modifying text only in their own dedicated section: hand-written spec language in the core of the spec does not conditionally depend on the enabled extensions. The auto-generated files (for implicit valid usage, prototypes, etc.) do reflect the enabled extensions. However, these mentions are automatic and do not require any manual maintenance outside of normal maintenance of the XML registry. It is possible that some vendors will choose to maintain their own extension branches — vendors are not required to use the Khronos OpenXR Gitlab. |
There is a rigid syntax for these names:
-
Extensions are named with the syntax:
XR_<AUTHOR>_<name>
. -
API layers are named with the syntax:
XR_APILAYER_{AUTHOR|FQDN}_<name>
.
Both extensions and API layer names include a XR_
prefix, as described in
the Preprocessor Defines section above.
In addition, API layers add the APILAYER_
prefix.
Extension and API layer names must both be valid C language identifiers.
3.3.1. Extension and API Layer Name Strings
The <name>
portion of extension and API layer names is a concise name
describing the purpose or functionality of the extension or API layer.
The underscore (_
) character is used as a delimiter between words.
Every character of the name must be in lower case.
3.3.2. Author IDs
Extension and API layer names also contain an author ID, indicated by
AUTHOR
above, identifying the author of the extension/API layer.
This ID is a short, capitalized string identifying an author, such as a
Khronos member developing OpenXR implementations for their devices, or a
non-Khronos developer creating OpenXR API layers.
Author IDs must be registered with Khronos.
As with Vulkan, some authors have platform communities they wish to distinguish between, and can register additional author IDs for that purpose. In the case of Vulkan, for example, Google has separate Android and Chrome communities.
Details on how to register an author ID are provided below. API layer authors not wishing to register an author ID with Khronos can instead use a fully-qualified domain name (FQDN) as the ID. The FQDN should be a domain name owned by the author. FQDNs cannot be used for extensions, only for API layers.
-
The following are examples of extension and API layer names, demonstrating the above syntax:
-
Extension names all use the base prefix
XR_
. -
Khronos-ratified extensions add the reserved author ID
KHR
, and will use the prefixXR_KHR_
. -
The following author IDs are reserved and must not be used:
-
XR
- To avoid confusion with the top-levelXR_
prefix. -
OPENXR
- To avoid confusion with the name of the OpenXR API. -
LAYER
- Reserve similar toAPILAYER
. -
APILAYER
- To avoid confusion with the higher-level “APILAYER” prefix. -
KHRONOS
- To avoid confusion with the Khronos organization.
-
-
Multi-author extensions that have not been ratified by Khronos (those developed via cooperation between, and intended to be supported by two or more registered authors) add the special author ID
EXT
to the base prefix, and will use the prefixXR_EXT_
. -
Traditional author-specific extensions developed by one author (or one author in cooperation with non-authors) add the author ID to the base prefix. For example, NVIDIA will use the prefix
XR_NV_
, and Valve will use the prefixXR_VALVE_
. Some authors can have additional registered author IDs for special purposes. For example, an Android extension developed by Google - but part of an Android open-source community project, and so not a proprietary Google extension - will use the author IDANDROID
. -
API Layer names follow the same conventions as extensions, but use the base prefix
XR_APILAYER_
. -
Because API layers need not be registered with Khronos, an alternative mechanism is needed to allow creating unique API layer names without registering an author ID. API layer authors that prefer not to register an author ID can instead use a fully-qualified domain name (FQDN) in reverse-order as an author ID, replacing
.
(period) with_
(underscore) characters. The restriction that API layer names must be valid C identifiers means that some FQDNs cannot be used as part of API layer names.
-
// Khronos extension name
XR_KHR_opengl_enable
// Multivendor extension name
XR_EXT_debug_utils
// Vendor API layer name using author ID LUNARG
XR_APILAYER_LUNARG_api_dump
// API layer name using the FQDN www.3dxcl.invalid instead of an author ID
XR_APILAYER_invalid_3dxcl_www_ourlayer
Note
To avoid linking to a nonexistent domain, the reserved TLD |
3.4. Extension Function, Type, and Token Naming Conventions
Extensions may add new functions, types, and tokens, or collectively “entities”, to the OpenXR API. These entities are given globally unique names by appending the author ID defined above for the extension name as described in the Extension Identifier Naming Conventions section above.
3.5. The OpenXR Registry
The canonical definition of the OpenXR APIs is kept in an XML file known as
the OpenXR registry.
The registry is kept in specification/registry/xr.xml
of the
KhronosGroup/OpenXR-Docs project.
The registry contains reserved author IDs, core and extension interface
definitions, definitions of individual commands and structures, and other
information which must be agreed on by all implementations.
The registry is used to maintain a single, consistent global namespace for
the registered entities, to generate the Khronos-supplied openxr.h
and
related headers, and to create a variety of related documentation used in
generating the API specification and reference pages.
In addition, the broader OpenXR community also consumes this XML registry to
create tools, bindings, and other OpenXR-related software.
3.6. Registering an Author ID with Khronos
Previous to Vulkan, Khronos APIs could only officially be modified by Khronos members. In an effort to build a more flexible platform, OpenXR allows non-Khronos developers to extend and modify the API via API layers and extensions in the same manner as Khronos members. However, extensions must still be registered with Khronos. A mechanism for non-members to register API layers and extensions is provided.
Extension authors will be able to create an account on GitHub and register an author ID with Khronos through the KhronosGroup/OpenXR-Docs project. The author ID must be used for any extensions that author registers. The same mechanism will be used to request registration of extensions or API layers with Khronos, as described below.
To reserve an author ID, propose a merge request against
xr.xml
.
The merge must add a <tag>
XML tag and fill in the name
, author
and
contact attributes with the requested author ID, the author’s formal name
(e.g. company or project name), and contact email address, respectively.
The author ID will only be reserved once this merge request is accepted.
Please do not try to reserve author IDs which clearly belong to another existing company or software project which may wish to develop OpenXR extensions or API layers in the future, as a matter of courtesy and respect. Khronos may decline to register author IDs that are not requested in good faith.
3.7. Registering a Vendor ID with Khronos
OpenXR implementers must report a valid vendor ID for their implementation
when queried by xrGetSystemProperties
, as described in the
OpenXR API Specification.
If there is no valid USB vendor ID defined for the physical device,
implementations must obtain a Khronos vendor ID.
Khronos vendor IDs are reserved in a similar fashion to author IDs. While vendor IDs are not directly related to API extensions, the reservation process is very similar and so is described in this section.
To reserve an Khronos vendor ID, you must first have a Khronos author ID.
Propose a merge request against xr.xml
.
The merge must add a <vendorid>
tag and fill in the name
and id
attributes.
The name
attribute must be set to the author ID.
The id
attribute must be the first sequentially available ID in the list
of <vendorid>
tags.
The vendor ID will be reserved only once this merge request has been
accepted.
Please do not try to reserve vendor IDs unless you are making a good faith effort to develop an OpenXR implementation and require one for that purpose.
3.8. Registering Extensions
Extensions must be registered with Khronos. Registration means:
-
Receiving an extension number.
-
Adding the extension name to the list in
xr.xml
and appearing on the Khronos registry website, which will link to associated documentation hosted on Khronos. -
For extensions which add to the OpenXR API, including definitions of those additions to
xr.xml
.
Registration for Khronos members is handled by filing a merge request in the
internal gitlab repository against the branch containing the core
specification against which the extension will be written.
The merge must modify xr.xml
to define extension names, API interfaces,
and related information.
Registration is not complete until the registry maintainer (the
specification editor) has validated and accepted the merge.
Non-Khronos members who want to create extensions must register with Khronos
by creating a GitHub account, and registering their author ID and/or FQDNs
to that account.
They can then submit new extension registration requests by proposing merges
to xr.xml
.
On acceptance of the merge, the extension will be registered, though its
specification need not be checked into the Khronos GitHub repository at that
point.
The registration process can be split into several steps to accommodate extension number assignment prior to extension publication:
-
Acquire an extension number. This is done by proposing a merge request against
xr.xml
similarly to how author IDs are reserved. The merge should add a new<extension>
tag at the end of the file with attributes specifying the proposed extensionname
, the next unused sequential extensionnumber
, and specifyingsupported="disabled"
. The extension number will be reserved only once this merge request is accepted. See the example below. -
Develop and test the extension using the registered extension number.
-
Publish the extension to Khronos using the previously registered extension number, by submitting merge requests defining the changes specific to the extension. Changes to both the specification source, and to
xr.xml
will be needed.-
Extension changes to the specification source must be limited to the added specification section as described in the Documenting Extensions section. (Their entities may be included in generated files incorporated into the final specification output document.) If, in a rare exception, such changes to the core source do need to occur, they must be protected by asciidoc conditionals.
-
Changes to
xr.xml
must define the extension interfaces in the<extension>
block, and must also change thesupported
attribute value of the<extension>
tosupported="openxr"
. -
When publishing an extension, mark it as enabled by proposing a merge request changing the
supported
attribute value of the<extension>
tosupported="openxr"
. Once the merge is accepted and the corresponding updated header with the new extension interface is committed to the intended release branch, publication is complete. -
Publishing on the Khronos public GitHub repository is preferred whenever possible. Khronos members may instead create branches on Khronos' internal gitlab server, but those changes will eventually be mirrored to GitHub upon publication.
-
Once the merge request defining an extension has been accepted into the intended release branch, publication is complete - although it may not be visible on GitHub until the next regular core Specification update is pushed out.
-
The following is an example of what the contents of the change inside an MR requesting an extension number reservation should look like:
<extension name="XR_KHR_android_create_instance" number="9" type="instance"
supported="openxr">
<require>
<enum value="1" name="XR_KHR_android_create_instance_SPEC_VERSION"/>
<enum value=""XR_KHR_android_create_instance""
name="XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME"/>
<enum offset="0" extends="XrStructureType"
name="XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR"/>
<type name="XrInstanceCreateInfoAndroidKHR"/>
</require>
</extension>
+ <extension name="XR_KHR_extension_10" number="10"
+ contact="Rylie Pavlik @rpavlik" supported="disabled">
+ <require>
+ <enum value="1" name="XR_KHR_extension_10_SPEC_VERSION"/>
+ <enum value=""XR_KHR_extension_10""
+ name="XR_KHR_EXTENSION_10_EXTENSION_NAME"/>
+ </require>
+ </extension>
</extensions>
NOTE: Spacing has been changed to make it more readable in this
document.
When making your change, please follow the layout spacing in the actual
xr.xml
document.
In the above example, the lines marked with '+' are the lines added by the
change.
Notice how the pending extension is now the last extension in the file and
supported
is set to "disabled".
The latter detail ensures the extension isn’t used by any of the tools which
use the xr.xml
as a source.
3.9. Documenting Extensions
Extensions are documented as added chapters to the OpenXR specification. Changes specific to an extension are protected by asciidoc conditionals. The changes are only visible in generated documentation when the Specification is built with an asciidoc attribute of that name defined. However, specifications generated from this branch will only include the extension when the Makefile is invoked appropriately.
Generally, extensions do not add conditional text to the core of the specification, although the generated files included in the core of the specification automatically reflect the extensions enabled at build time.
Note
This is referred to as the “single-branch” model, in contrast to an earlier model used by Vulkan where each extension lived in a separate branch from the Vulkan 1.0 core Specification source. |
For example, the XR_KHR_opengl_enable
extension is documented in the
main
branch of the GitHub
KhronosGroup/OpenXR-Docs project and internal
GitLab.
However, specifications generated from this branch will only include the
extension when the Makefile is invoked appropriately.
Except for extraordinary cases, language defining extensions should be localized into:
-
modification of parts of
xr.xml
defining the extension interfaces. -
one or a small number of asciidoc include files. One must be named
specification/sources/chapters/extensions/author/extension_name.adoc
whereauthor
is the author/vendor tag in all lowercase, andextension_name
is the extension name without the leadingXR_
and in all lowercase. This file will be conditionally and automatically included in the table of contents and generated specification documents and reference pages if enabled during a specification build. See below for more details.
3.9.1. Extension Documentation Names/Locations
All extension specification documentation can be found under the
specification/sources/chapters/extensions
folder and should end with the
asciidoc extension (.adoc
) The extension documentation should be named
based on the lower-case extension name, and without the XR_
prefix.
For example, the specification documentation for the XR_KHR_opengl_enable
extension is called khr_opengl_enable.adoc
.
Extensions are grouped in individual sub-folders based on the lower-case
author ID.
For example, Khronos ('KHR') extensions are grouped under the sub-folder
khr
.
Therefore, the asciidoc files for the XR_KHR_opengl_enable
extension can
be found in the specification/sources/chapters/extensions/khr/
folder.
Likewise, if Valve Software were to create an extension called
XR_VALVE_new_extension
, the documentation for that extension should be
placed in the 'valve' sub-folder under
specification/sources/chapters/extensions/
.
3.9.2. Extension Documentation Conditions
If the extension asciidoc file for an extension is named correctly, and placed in the correct folder, then the specification scripts will automatically find that file when generating the requested version(s) of the specification. However, the extension file is not included in the specification unless the following criteria have been met:
-
The extension sections have been properly added to the registry (xr.xml) file.
-
The extension has been enabled in the registry file by setting the
supported
field to a value of "openxr" -
The specification is built with the extension enabled
-
NOTE: You may use the
specification/makeAllExts
shell script to build the specification with all extensions enabled.
-
Once these criteria have been met, the extension file will be included in the specification build.
3.9.3. Specification and Extension Documentation Requirements
To create an extension, use an existing extension (such as
XR_KHR_opengl_enable
) as an example, making sure to keep the following in
mind:
-
In the preamble to the appendix, start with an asciidoc include of the automatically generated metadata information.
-
This information includes the extension name string, type, number, and revision from xr.xml.
-
-
Following the
include
, add as many of the following sections as are meaningful:-
Last Modified Date
-
IP Status - Such as No known IP claims.
-
Interactions and External Dependencies
-
May include requirements or interactions with optional OpenXR features and interactions (other than strictly requiring) with other OpenXR extensions.
-
Dependencies on OpenXR versions and extensions are automatically populated from the data in the registry XML.
-
-
Contributors - Names and corporate affiliations of people who have made significant direct contributions to this extension.
-
Overview - a brief introduction
-
New Object Types - leave empty if none.
-
New Flag Types - leave empty if none.
-
New Enum Constants - leave empty if none. This is where you may add something like the following for additions to core enumerations - most often
XrStructureType
.Example Markup*New Enum Constants* elink:XrStructureType enumeration is extended with: * ename:XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR
-
New Enums - leave empty if none.
-
New Structures - leave empty if none.
-
New Functions - leave empty if none.
-
Issues
-
Version History - this must be formatted exactly as found in existing specifications, and updated when a "substantial" change is made. It is parsed by
xml_consistency
and cross-checked against the version enum in the XML registry.Example Markup*Version History* * Revision 1, 2019-07-12 (Rylie Pavlik, Collabora, Ltd.) ** A brief revision description goes here. Mark up entity names with back-ticks instead of the normal macros in the version history to prevent errors in case future revisions rename things. * Revision 2, 2019-07-12 (Rylie Pavlik, Collabora, Ltd.) ** ... etc. ...
-
-
Extensions usually make significant additions and changes to the OpenXR specification. However, these sections are kept in the extension appendix and not directly integrated into the spec. This is to keep the core specification text clean of any extensions.
-
In every other place where the extension alters the behavior of the core Specification, clearly indicate the section in the extension appendix what is modified and in what way. Since the changes are not made to the specification language directly, care must be taken to make it abundantly clear what new behavior occurs when the extension is enabled versus when it is not.
-
If two extensions interact, the asciidoc conditionals must be carefully structured so as to properly document the interactions if the specification is built with both extensions. Asciidoc conditionals allow "and" and "or" constructs (see: http://asciidoctor.org/docs/user-manual/#conditional-preprocessor-directives and http://asciidoctor.org/docs/user-manual/#checking-multiple-attributes-ifdef-and-ifndef-only).
Example Markupifdef::XR_KHR_foo[] ... discussion of XR_KHR_foo ... ifdef::XR_KHR_fum[] ... discussion of interactions between XR_KHR_foo and XR_KHR_fum ... endif::XR_KHR_fum[] endif::XR_KHR_foo[] ifdef::XR_KHR_fum[] ... discussion of XR_KHR_fum ... endif::XR_KHR_fum[]
-
In cases where a new extension (A) modifies both core and an existing extension (B), if the new extension (A) becomes part of the core at a future release (i.e. is no longer an extension), the portion of the new extension that modified the existing extension (B) effectively becomes part of that existing extension. Thus, at the new core release, enabling the pre-existing extension (B) also enables the functionality that was previously enabled by enabling the previously-new extension (A).
-
For vendor extensions, changes made to existing core Specification source files and to
xr.xml
all fall under the Contributor License Agreement. Vendors may mark their own copyright on files added, and must ensure that a copyright statement and SPDX license identifier tag indicating CC-BY-4.0 terms are present. -
In most cases, there will be one new file added to the specification:
extensions/vendor/extension_name.adoc
. If you need more than one new file in theextensions/
directory, create a subdirectory named with the extension name and place the new files there.
3.9.4. Extension Lifecycle
Extensions have a very well-defined lifecycle.
Extensions start out as being "in development". While in development, extensions can change greatly and are considered more of a prototype and not intended for final use. Once extension authors believe they are finished, the extension is approved by the Khronos working group and becomes one of an "active" extension. As OpenXR grows, new versions of the API will be released.
At this point, extensions can stay "active" for a while, but eventually each extension will eventually go down one of 3 paths:
-
An extension can be "promoted" into the core API
-
An extension can be replaced (or "deprecated") by a newer extension
-
An extension can be "retired" and have all support removed
Extension Promotion
When the OpenXR Working Group decides to release a new major or minor
version of the OpenXR API, they typically will meet and decide to pull in a
set of "active" extensions into the core API.
This process of pulling in extensions into the core API is called
promotion
.
Extensions that are part of this process become "promoted" extensions.
An example of this behavior pattern in Vulkan is the release of Vulkan 1.1. Vulkan 1.1 was created by pulling in many of the "active" Vulkan extensions that were originally added to extend Vulkan 1.0.
Once an extension has been promoted, the original extension commands and types still exist and may still be used, especially when used with an older version of the API. However, if applications use the newer version of the API into which the extension was promoted, the application should switch to using the new core commands and types.
Extension promotion is indicated in the OpenXR registry by adding the
"promotedto" tag to the extension definition header.
The value of the "promotedto" field should indicate what it was promoted
into.
For example, if the extension was promoted into OpenXR as part of OpenXR
1.1, the value should read promotedto="XR_VERSION_1_1"
.
For example:
<extension name="XR_KHR_loader_init" number="89" type="instance" supported="openxr" promotedto="XR_VERSION_1_1">
<require>
<!-- ... -->
</require>
</extension>
Extension Deprecation
Extensions are often developed because an author believes that the provided functionality is the best way to perform some action or expose a new feature. However, due to the flexible nature of the API, someone may develop a better way to expose the feature. When this happens, the group may want to flag the original functionality in some way that indicates it is no longer the best way to access the feature. The way OpenXR does this is by labeling the extension as "deprecated". "Deprecated" extensions are still exposed by at least some of the available runtimes, but may disappear at some point in the future. Because of this, runtimes may emit a warning indicating the application should be modified to use the newer behavior.
Extension deprecation is indicated in the OpenXR registry by adding the
"deprecatedby" tag to the extension definition header.
The value of the "deprecatedby" field should indicate which
extension/feature should now be used.
For example, if the XR_KHR_metal_enable
extension was replaced by the
XR_KHR_metal_enable2
extension, the value should read
deprecatedby="XR_KHR_metal_enable2"
.
For example:
<extension name="XR_KHR_metal_enable" number="30" type="instance" protect="XR_USE_GRAPHICS_API_METAL" supported="openxr" deprecatedby="XR_KHR_metal_enable2">
<require>
....
</require>
</extension>
To make it clear which extensions are "active" and which are "deprecated", all "deprecated" extensions are listed in a separate extension list in the specification output documents.
Extension Retirement
Sometimes, extension functionality because useless. This could be because hardware or software has changed in some way since the extension was originally created that now makes the intended behavior undesirable. In this case, extension support will disappear from all runtimes and most applications. If this occurs, then when the OpenXR Working Group develops a new major version of the OpenXR API, they may choose to "retire" an extension and remove it from that version of the specification. From that point forward, the extension is considered "retired" and must not be used.
3.10. Assigning Extension Token Values
Extensions can define their own enumeration types and assign any values to their enumerants that they like. Each enumeration has a private namespace, so collisions are not a problem. However, when extending existing enumeration objects with new values, care must be taken to preserve global uniqueness of values. Enumerations which define new bits in a bitmask are treated specially as described in Reserving Bitmask Values below.
Each extension is assigned a range of values that can be used to create
globally-unique enum values.
Most values will be negative numbers, but positive numbers are also
reserved.
The ability to create both positive and negative extension values is
necessary to enable extending enumerations such as XrResult
that
assign special meaning to negative and positive values.
Therefore, 1000 positive and 1000 negative values are reserved for each
extension.
Extensions must not define enum values outside their reserved range without
explicit permission from the owner of those values (e.g. from the author of
another extension whose range is infringed on, or from the Khronos Registrar
if the values do not belong to any extension’s range).
Note
Typically, extensions use a unique offset for each enumeration constant they add, yielding 1000 distinct token values per extension. Since each enumeration object has its own namespace, if an extension needs to add many enumeration constant values, it can reuse offsets on a per-type basis. |
The information needed to add new values to the XML are as follows:
-
The extension name (e.g.
XR_KHR_opengl_enable
) that is adding the new enumeration constant. -
The existing enumeration type being extended (e.g.
XrStructureType
). -
The name of the new enumeration token being added (e.g.
XR_TYPE_INSTANCE_CREATE_INFO
). -
The offset, which is an integer between 0 and 999 relative to the base being used for the extension.
-
The direction may be specified to indicate a negative value (
dir="-"
) when needed for negativeXrResult
values indicating errors, likeXR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR
. The default direction is positive, if not specified.
Implicit is the registered number of an extension, which is used to create a range of unused values offset against a global extension base value. Individual enumerant values are calculated as offsets in that range. Values are calculated as follows:
-
base_value = 1000000000
-
range_size = 1000
-
enum_offset(extension_number, offset) = base_value + (extension_number - 1) × range_size + offset
-
Positive values: enum_offset(extension_number, offset})
-
Negative values: -enum_offset(extension_number, offset})
The exact syntax for specifying extension enumerant values is defined in the
readme.pdf
specifying the format of xr.xml
, and extension authors can
also refer to existing extensions for examples.
If an extension becomes part of core, the enumerant values should remain the same as they were in the original extension, in order to maintain binary compatibility with existing software.
3.10.1. Reserving Bitmask Values
Enumerants which define bitmask values are a special case, since there are only a small number of unused bits available for extensions. For core OpenXR API and KHR extension bitmask types, reservations must be approved by a vote of the OpenXR Working Group. For EXT and vendor extension bitmask types, reservations must be approved by the listed contact of the extension. Bits are not reserved, and must not be used in a published implementation or specification until the reservation is merged into xr.xml by the registry maintainer. In general, this is not done in any future extensions: create a chained structure with an entirely new bitmask field instead. See also the Extension Process discussion of this.
3.11. Required Extension Tokens
In addition to any tokens specific to the functionality of an extension, all extensions must define two additional tokens.
-
XR_extname_SPEC_VERSION
is an integer constant which is the revision of the extension namedXR_extname
(whereextname
is the capitalization of the actual extension name) inopenxr.h
oropenxr_platform.h
(the latter is used if aprotect
attribute is specified for the extension). This value begins at 1 with the initial version of an extension specification, and is incremented when changes are made. Note that the revision of an extension defined inopenxr.h
and the revision supported by the OpenXR implementation (thespecVersion
field of the XrExtensionProperties structure corresponding to the extension and returned by one of the extension queries) may differ. The revision value indicates a patch version of the extension specification, and differences in this version number maintain full compatibility, as defined in the API Version Numbers and Semantics section of the OpenXR API Specification.
Note
Any changes requiring the addition or removal of a type or command should be done by creating a new extension. The resulting extension should take care to include the appropriate dependency information on the original extension. |
-
XR_EXTNAME_EXTENSION_NAME
is a string constant which is the name of the extension (whereEXTNAME
is all upper-case)
For example, for the extension XR_KHR_opengl_enable
, at the time of
writing the following definitions were in effect:
#define XR_KHR_opengl_enable_SPEC_VERSION 8
#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
3.12. Extension Handles, Objects, Enums, and Typedefs
Expanding on previous discussion, extensions can add values to existing
enums; and can add their own commands, enums, typedefs, etc.
This is done by adding to xr.xml.
All such additions will be included in the openxr.h
and related headers
supplied by Khronos.
If the extension adds a new handle to OpenXR, a corresponding value must be
added to XrObjectType
in order to allow components to identify and
track objects of the new type.
The new enumeration value must conform to the naming defined in the
Extension Enumerant Names section.
In this case, the type’s Xr
prefix is replaced with the enum prefix
XR_OBJECT_TYPE_
, and the rest of the handle name is converted as
described in that section.
XrInstance -> XR_OBJECT_TYPE_INSTANCE
XrDebugUtilsMessengerEXT -> XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT
Note
Application developers are encouraged to be careful when using |
3.13. Extension Function Prototypes
Function pointer declarations and function prototypes for all core OpenXR
API commands are included the openxr.h
header file.
These come from the official XML specification of the OpenXR API hosted by
Khronos.
Function pointer declarations are also included in the openxr.h
and
openxr_platform.h
file for all commands defined by registered extensions.
No extension functions are part of the OpenXR ABI, and so by default, as
of OpenXR 1.0.15, extension function prototypes are not exposed in
openxr.h
or openxr_platform.h
unless a configuration define is enabled.
An extension can be considered platform specific, in which case its
interfaces appear in openxr_platform.h
and are protected by #ifdefs
.
3.14. Accessing Extension Functions from Programs
xrGetInstanceProcAddr can be used in order to obtain function pointer
addresses for core and extension commands (per the description in the
“Command Function Pointers” section of the
OpenXR API Specification).
Different OpenXR API loaders can choose to statically export functions for
some or all of the core OpenXR API commands, and can statically export
functions for some or all extension commands.
If a loader statically exports a function, an application can link against
that function without needing to call one of the xrGetInstanceProcAddr
commands.
Note
The official OpenXR API loader for Android, Linux, and Windows exports functions for all core OpenXR API functions, and no extension functions. |
3.15. Extension Interactions
Extensions can modify existing commands in one or more of the following ways:
3.15.1. Extending Command Structures
Extensions modifying the behavior of existing commands should provide
additional parameters by using the next
field of an existing
structure, pointing to a new structure defined by the extension, as
described in the “Valid Usage” section of the
OpenXR API Specification.
Extension structures defined by multiple extensions affecting the same
structure can be chained together in this fashion.
Any structure which can be chained in this fashion must begin with the
following two members:
XrStructureType type;
const void* next;
If the structure is an output parameter, the next
pointer should be
non-const
.
It is in principle possible for extensions to provide additional parameters
through alternate means, such as passing a handle parameter to a structure
with a type
defined by the extension, but this approach is discouraged
and should not be used.
When chaining multiple extensions to a structure, the implementation will process the chain starting with the base parameter and proceeding through each successive chained structure in turn. Extensions should be defined to accept any order of chaining, and must define their interactions with other extensions such that the results are deterministic. If an extension needs a specific ordering of its extension structure with respect to other extensions in a chain to provide deterministic results, it must define the required ordering and expected behavior as part of its specification.
Validation of such extended structure chains is automatically generated from the registry, as described in the description of attr:structextends in the registry schema document for Vulkan.
Take the following XML structure example:
<type category="struct" name="XrNewStructKHR" structextends="XrSessionCreateInfo">
...
</type>
In this case, the above block is indicating that the structure
XrNewStructKHR
is valid for use in the next
chain of the
XrSessionCreateInfo structure.
3.15.2. Extending Command Returns
Sometimes, extensions may add additional return values to an existing
OpenXR command.
This is done by adding a special tag in the new extension’s section of the
OpenXR registry file (xr.xml
) in the following fashion:
<extend type="command" name="[command_name]" successcodes="[success_return_list]" errorcodes="[error_return_list]"/>
Where:
-
[command_name]
is the name of the command you are extending-
e.g. xrCreateInstance, xrDestroyInstance, etc.
-
-
successcodes="[success_return_list]"
is optional and will extend the command’s existingsuccesscodes
values with the provided comma-delimited[success_return_list]
values, but only when this extension is enabled as part of the specification build process.-
e.g.
successcodes="XR_SWAPCHAIN_IN_USE
-
-
errorcodes="[error_return_list]"
is optional and will extend the command’s existingerrorcodes
values with the provided comma-delimited[error_return_list]
values, but only when this extension is enabled as part of the specification build process.-
e.g.
errorcodes="XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR
-
4. Markup Style
This chapter demonstrates Asciidoc and Specification structure, including text layout and markup style.
Chapters and sections follow a rigid template consisting of an optional anchor (if other parts of the document cross-reference the section) followed by a one line title (see section 19 of the Asciidoctor User Manual) and a blank line. The anchor is typically the base name of the file containing the chapter, with a lowercase version of the section name following, with spaces replaced by dashes.
Always use the one-line title form, with one to four = signs preceding the chapter/section title. The two-line title form cannot be easily searched for and often looks like other types of asciidoc delimiters. Using a mix of one-line and two-line titles causes compatibility issues, and using the two-line title form implicitly sets syntax compatibility mode.
Always precede the anchor by two blank lines (except at the beginning of a file), and follow the title by a blank line, to set off sections visibly.
[[markup]]
= Markup Style
[[markup-sample-section]]
== Sample Section
4.1. Sample Section
This is a sample section structurally similar to the Vulkan API Specification, nested one level inside a chapter. Sections can be nested up to level 5, although not all levels are included in the Table of Contents.
4.2. Asciidoc Markup And Text Layout
Asciidoc source should be text filled to 76 columns with hard line breaks. Each sentence in a paragraph ends with a newline to minimize git diff conflicts. Except when necessary for lists or other markup, text should begin at the first column of each line (leading spaces are often semantically meaningful in asciidoc markup).
UTF-8 characters outside the ASCII subset should be used sparingly, only when needed for non-English names. Instead use asciidoc markup for special characters, if required. For example, two hyphens produces an en-dash:
Example Markup
|
As an exception, multiplication should be marked with the unicode
multiplication symbol “×” (and not an asterisk) when used in plain text.
You may also use the ×
asciidoc attribute for this symbol.
In math sections, the same symbol should be referred to as \times
.
In code sections, a conventional asterisk (*
) should be used instead.
See section 40 of the Asciidoctor User Manual for supported special characters, as well as use of entity references.
Quotation marks should use the 66/99 convention. That is, double asymmetric quotation marks, indicated by a quotation mark then a backtick as opening marks, and a backtick then quotation mark as closing marks ("`like this`"), which renders “like this”.
Never use hard tabs or trailing blanks.
-
In some cases, limitations of asciidoc markup may result in lines that are longer than 76 characters and cannot easily be shortened without compromising the output documents.
4.2.1. Blocks
There are a variety of asciidoc block constructs. With the exception of tables and of open blocks used to group markup together, blocks should be delimited by exactly four repeated characters indicating the block type, for consistency. The block types and delimiters are shown in the following table.
Table Type | Delimiter | Comments |
---|---|---|
Open |
|
|
Example |
|
For Notes |
Passthrough |
++++ |
For some kinds of math markup |
Comment |
//// |
|
Listing |
---- |
For source code listings |
Sidebar |
**** |
|
Table |
|
For tables |
Quote |
____ |
Currently unused in the OpenXR Specification |
Literal |
…. |
Currently unused in the OpenXR Specification |
4.2.2. Footnotes
Use manually marked-up footnotes (the asciidoc footnote construct is OK for PDF outputs, but does not work well with long HTML documents since it places all footnotes at the end of the document).
Refer to footnotes with asciidoc superscript notation1, and mark up the footnotes below, but near the references as labeled lists. Manually assigned footnote numbers will inevitably be reused, which is OK as long as the colliding numbers are not in the same section.
- 1
-
Like this example footnote.
Example Markup
→ See reference2
|
4.2.3. Lists
Bullet Lists and Continuation Blocks
-
Bullet lists are the preferred form of list, aside from glossary definitions.
-
Lists should have no indentation for the list item delimiter (e.g. one or more asterisks, for bullet lists) and one space between the delimiter and the text.
Note that continuation blocks for list items longer than one paragraph cannot be indented, only the first paragraph.
In general, successive list items should not be separated by white space. However, list continuation blocks should be followed by a
+
on a line by itself, or by a blank line, due to limitations of the asciidoc parser. -
For bullet lists that extend over multiple lines, indent the successive lines to align with the text of the first line in that bullet. This lets us visually distinguish lists from other kinds of markup.
-
Nested lists should align the leftmost list item delimiter (bullet, etc.) with the parent delimiter.
-
* This is the first item in a bullet list.
** This is a nested item for the first item.
* The second item is described with two paragraphs.
The second paragraph is in a continuation block:
+
--
This is a continuation block containing the second paragraph on a new line.
--
+
** This is a nested list item for the second item.
Since it follows a continuation block, it must be separated by a blank
line or `+` from that block.
Labeled Lists
Labeled lists may be used in some cases such as footnotes; glossary entries; and long lists of information about similar names, such as the “Features, Limits, and Formats” chapter of the OpenXR Specification (there is no example currently in the OpenXR specification directly). Whenever labeled lists are used the label and its terminating double colon must be alone on a line, followed by the contents of that list entry.
For consistency do not use labels ending in three or four colons, or two semicolons, even though these forms are allowed in asciidoc markup.
Glossary Entry::
This is a glossary entry.
Last Modified Date::
2016-02-16
Numbered Lists
Numbered lists may be used if strictly necessary to place an ordering on list items. Always use implicit numbering, with the bullet point being a single period.
-
Explicit numbering with a number preceding the period is prone to accumulating errors as edits are made.
-
In addition, the markup is harder to recognize for scripts and tools (other than asciidoc itself) operating on the document source.
. First list item.
. Second list item.
. Etc.
4.2.4. Anchors and Cross-references
In general, chapters and sections should always have anchors, following the naming convention discussed above. Anchors to other sections of the document may be inserted as needed. In addition, the autogenerated include files defining commands, structures, enumerations and flags all define anchors whose name is the name of the command or type being defined, so it is easy to link to a (for example) a command name such as xrCreateInstance. However, using the markup macros described below is preferred when linking to anchors corresponding to API names, such as xrCreateInstance.
If you want a cross-reference to an anchor to appear as something other than the raw anchor name, always make sure to include that text as part of the cross-reference. There are several different toolchains followed for various forms of asciidoc output, and not all of them treat anchors without alt-text the same way.
In general, chapters and sections should always have anchors, following the
naming convention <<markup,discussed above>>.
...
so it is easy to link to a (for example) a command name such as
<<xrCreateCommandPool,xrCreateCommandPool>>. However, using the
<<markup-macros,markup macros>> described below is preferred when linking to
anchors corresponding to API names, such as flink:xrCreateCommandPool.
Extensions
Extensions, like commands and structures, have an auto-generated anchor.
The standardized way of referring to an extension by name is to prepend
apiext:
: for example, XR_KHR_vulkan_enable
.
When a link would be inappropriate (e.g. in the “Name” portion of the
extension’s spec itself), surrounding it with backticks is acceptable:
XR_KHR_vulkan_enable
.
Extensions, like commands and structures, have an auto-generated anchor.
The standardized way of referring to an extension by name is to prepend
`apiext{cl}`: for example, apiext:XR_KHR_vulkan_enable.
When a link would be inappropriate (e.g. in the "`Name`" portion of the
extension's spec itself), surrounding it with backticks is acceptable:
`XR_KHR_vulkan_enable`.
4.2.5. Tables
Asciidoc tables should use the block prefix |====
.
Where feasible, align the |
separating cells across rows.
This will sometimes result in very wide tables in the source document, but
makes it easier to see which cells belong to which column.
Alternatively, long cells can be broken onto a separate line with the |
separator appearing first, except for the first row of the table, which must
all appear on a single line.
Tables should usually be preceded with a short title.
.Normative Terminology Macros
[width="100%",options="header"]
|====
| Macro Name | Output
| can{cl} | can:
| cannot{cl} | cannot:
|====
4.2.6. Figures
All figures (images) must be marked up as follows, to ensure there is an anchor and that the figure is given a caption which shows the figure number and is added to the list of figures:
[[fig-anchorname]]
image::images/imagename.svg[align="center",title="Figure caption",{fullimagewidth}]
There must be both .svg and .pdf versions of each figure checked into the
images/ directory, to support generating both HTML and PDF outputs.
It is best to create images in Inkscape as SVG files and then use the
conversion rule in doc/specs/vulkan/images/Makefile
to generate PDF.
Asciidoc restricts captions in figures to be a single line in the source document. If a longer caption is required, follow the figure directive with a sidebar block including the full caption preceded by a link to the figure:
.Caption
****
In the <<fig-anchorname,Figure caption>> diagram, the diagram represents
... long caption text here.
****
4.3. Markup Macros and Normative Terminology
This section discusses Asciidoc macros used in the document. In addition to the macros defined by asciidoc itself, additional macros are defined by the OpenXR API Specification and Reference Page configuration files.
4.3.1. API Markup Macros
These macros must be used to tag command, structure, enumeration, enumerant,
and other OpenXR-specific names so they can be rendered in a distinctive
fashion, link to definitions of those names, and be easily searched for in
the source documents.
The validation scripts (make allchecks
output) also rely on these macros
being used consistently and correctly.
The API markup macros, with examples of their use, are in the following
table:
Macro Name | Usage and Meaning |
---|---|
flink: |
Generates a cross-reference or link to the definition of the command name in the macro argument. Example: flink:xrCreateInstance → xrCreateInstance. |
fname: |
Formats the macro argument like flink:. Does not
generate a cross-reference. Example:
fname:xrCreateInstance → Only use this macro when necessary. |
ftext: |
Formats the macro argument like fname:. May contain
asterisks for wildcards. Not validated. Example:
ftext:xrCreate* → Only use this macro when necessary. |
slink: |
Generates a cross-reference or link to the definition of the structure or handle in the macro argument. Example: slink:XrInstanceCreateInfo → XrInstanceCreateInfo |
sname: |
Formats the macro argument like slink:. Does not
generate a cross-reference. May also be an abstract
structure or handle name. Example:
sname:XrInstanceCreateInfo →
Only use this macro when necessary. |
stext: |
Formats the macro argument like sname:. May contain
asterisks for wildcards. Not validated. Example:
stext:Xr*CreateInfo → Only use this macro when necessary. |
elink: |
Formats the macro argument as an OpenXR enumerated
type name and links to the definition of that enumeration
type. Example: ename:XrResult → |
ename: |
Formats the macro argument as an OpenXR enumerant name.
Example: ename:XR_SUCCESS → |
etext: |
Formats the macro argument like ename:. Not validated.
Examples: etext:_RANGE_SIZE → Only use this macro when necessary. |
pname: |
Formats the macro argument as a OpenXR parameter or
structure member name. Example: pname:device →
|
ptext: |
Formats the macro argument like pname:. May contain
asterisks for wildcards. Not validated. Example:
ptext:sparseResidency* → Only use this macro when necessary. |
tlink: |
Generates a cross-reference or link to the definition of the OpenXR type in the macro argument. Example: tlink:PFN_xrVoidFunction → PFN_xrVoidFunction. This is only used for function pointer types at present. |
tname: |
Formats the macro argument like tlink:. Does not
generate a cross-reference. Example:
tname:PFN_xrVoidFunction →
Only use this macro when necessary. |
dlink: |
Generates a cross-reference or link to the definition of the OpenXR C macro in the macro argument. Example: dlink:XR_NULL_HANDLE → XR_NULL_HANDLE. There are only a few macros in the OpenXR API, described in the “e” appendix of the OpenXR API Specification |
dname: |
Formats the macro argument like dlink:. Does not generate a cross-reference. Only use this macro when necessary. |
basetype: |
Formats the macro argument like a basic scalar type.
Example:
basetype:XrBool32 → |
apiext: |
Generates a cross-reference or link to the target as an extension. |
code: |
Formats the macro argument as a code sample. Primarily
used for SPIR-V keywords and builtin C types. Examples:
code:uint32_t → |
pathname: |
Formats the macro argument as a full semantic path name string. Example: pathname:/user/hand/left → /user/hand/left. |
subpathname: |
Formats the macro argument as a substring of a semantic path name. Example: subpathname:/click → …/click |
actionname: |
Formats the macro argument as the characters of an action name.
Example:
actionname:hold → |
When referring to a compound name (function-parameter, or structure-member),
combine the macros separated by two colons, resulting in
xrCreateInstance::info
and
XrInstanceCreateInfo::flags
.
This is often done when referring to a particular parameter or member in a
part of the document other than the description of the corresponding
function or structure.
flink:xrCreateInstance::pname:info
slink:XrInstanceCreateInfo::pname:flags.
When To Use *name: Macros
Only use the fname:, sname:, tname:, and dname: macros if no
definition of the target type with a corresponding anchor exists in the
document.
Anchors are automatically defined when including the generated API interface
definitions under specification/generated/api/…/*txt
.
If an anchor does exist, use the corresponding *link: macro.
When To Use *text: Macros
Only use the ftext:, stext:, etext:, and ptext: macros when describing something something that should be rendered like a command, structure, enumerant, or parameter name, respectively, but is not actually one. Typically these macros are used for wildcards describing multiple API names with common prefixes or suffixes, or common subsets of API names.
Other Markup
Uses of standard Asciidoc markup are less common.
Occasional asterisk markup is used for emphasis.
Underscores are used for glossary terms, as well as placeholder text.
Backtick markup is used for filenames, literal character sequences, code
that does not fit one of the more specific macros above, and entities (such
as previous names of extensions) that should be excluded from verification
by toolchain scripts.
The C NULL
macro is marked up using the code:
macro.
*emphasis*
_semantic path_
`extensions/__extension_name__.adoc`
`openxr.h`
code:NULL
Glossary Terms
Glossary terms are currently marked up using underscore markup where they are defined in the documents, as well as being added to the formal Glossary appendix in the OpenXR API Specification. However, we will probably change to using custom macros soon, to enable linkage between the glossary and definitions in the spec body.
_Glossary terms_
4.3.2. Normative Terminology
Normative terminology is precisely defined in section 1.6 of the OpenXR API Specification, and is used to visually tag terms which express mandatory and optional behavior of OpenXR implementations, and of applications using OpenXR.
Whenever one of these terms appears in the OpenXR API Specification, it must be tagged using the macros, to indicate that its use has been carefully considered and is consistent with the definitions in section 1.6. This is extremely important for determining IP that is in and out of Scope during Ratification reviews. The normative terminology macros are defined in the following table:
Macro Name | Output |
---|---|
can: |
can |
cannot: |
cannot |
may: |
may |
may: not |
may not |
must: |
must |
must: not |
must not |
optional: |
optional |
optionally: |
optionally: |
required: |
required |
should: |
should |
should: not |
should not |
Note that the macros are lower-case only, so language should be written such that these terms do not appear at the beginning of a sentence (if really necessary, additional capitalized macros could be added).
Optional Behavior
If a described behavior of the implementation is not necessary for conformance, use the terms may: or optional: to describe it.
If a described usage pattern by the application is allowed but not necessary, use the term can: to describe it.
If language flows more logically using the term "may not", use the term may: not to describe it.
Optional Functionality
If functionality (rather than behavior) is optional, it should be described as
not required:
Implementations are not mandated to support functionality which is not required, but if they do, they must behave as described by the OpenXR API Specification. The term functionality includes API features, extensions, and layers.
4.4. Informative, Editing and Implementor’s Notes
There are several possible types of notes. Depending on the type of output, they are rendered in different styles, but always include a note title, and are usually set off in a box or with an icon. While asciidoc supports a wide set of admonition paragraphs such as TIP, IMPORTANT, WARNING, and CAUTION, we always use the NOTE form, augmented by a note title. Each type of note is discussed below.
4.4.1. Informative Notes
Informative notes always appear as part of the document, but are considered non-normative. They usually describe usage advice for applications, and are always given the title Note, as in the following example:
Note
This is an informative note. |
[NOTE]
.Note
====
This is an informative note.
====
If an entire chapter or section is considered informative, it should begin with the sentence:
This chapter/section is Informative.
4.4.2. Editing Notes
Editing notes usually only appear in internal (non-published) versions of
documents, via asciidoc conditionals.
If they are not resolved, or are internal issues that should not be visible
in public, they should be removed from the source before pushing content to
a canonical (1.0
or per-extension) public repository.
They usually tag places where an outstanding Gitlab/GitHub issue is being
worked, and are always given the title editing-note, as in the following
example:
ifdef::editing-notes[]
[NOTE]
.editing-note
====
Contents of an editing note go here.
It is good practice to include a Gitlab/GitHub issue number, or link to the
issue, in the editing note.
====
endif::editing-notes[]
4.4.3. Implementor’s Notes
Implementor’s notes may or may not appear in published versions of documents, via asciidoc conditionals. They describe suggested approaches or guidelines for people writing OpenXR implementations, and are rare because the hardware being targeted varies so widely. They are always given the title Implementor’s Note, as in the following example:
ifdef::implementation-guide[]
.Implementor's Note
====
Contents of an implementor's note go here.
====
endif::implementation-guide[]
4.5. Word Choices
There are a variety of common terms that have several equivalent word choices. Always use the words in the first column instead of the alternate terms. This list may not be comprehensive; when in doubt, be guided by the existing OpenXR API Specification.
Use This | Instead Of | Comments |
---|---|---|
application |
client |
|
bitmask |
bit field |
Technically correct. OpenXR bitmasks are just integers and are not logically addressable at the bit level. |
command |
function |
Except when talking about function pointers returned by
|
create |
allocate |
When describing objects resulting from |
depth/stencil |
packed (interleaved, combined, other prefix) depth/stencil, depth-stencil, DepthStencil, etc. |
Combined format implicit in the name. |
graphics device |
GPU |
Implementations on non-GPU devices are possible. |
heterogeneous |
heterogenous |
More common |
homogeneous |
homogenous |
More common |
host endianness |
platform endianness |
|
image subresource |
subresource |
Except when referring to host-accessible subresources |
implementation |
system |
|
indices |
indexes |
More common |
member |
field |
|
|
|
In rare cases when are or if are not grammatically appropriate, specifies may be used instead. |
|
the value of |
In rare cases, the value of is appropriate. See the existing specification language for examples. |
begins / begun |
starts / started |
For |
finishes / finished |
ends / ended |
For |
used |
referenced |
When describing attachments specified in a subpass description. |
statically used |
referenced |
When describing resources or push constants accessed by shader code |
a more specific term |
referenced |
For all other situations. |
component |
channel |
Specifically this refers to color channels/components |
4.5.1. Avoid Contractions
Contractions make the specification sound less formal and using them would be inconsistent with the many non-contraction forms already in use in the spec.
Use This | Instead Of |
---|---|
are not |
aren’t |
cannot: |
can’t |
does not |
doesn’t |
do not |
don’t |
has not |
hasn’t |
is not |
isn’t |
it is |
it’s |
that is |
that’s |
there is |
there’s |
we are |
we’re |
will not |
won’t |
4.5.2. Terms to Use With Caution
The term subset is sometimes used to refer to a strict subset, and sometimes used to refer to a subset which may be equal to the entire set. This is particularly likely to come up when describing bitmasks. Make sure to use either subset or strict subset as appropriate.
4.5.3. Terms to Avoid
Do not describe anything in the documentation using vague or wishy-washy terms. Our goal is to precisely describe behavior of implementations.
The normative terms may:, optional:, and should: are available when implementations may make choices of behavior, but when such choices are allowed, each choice still must have well-defined behavior.
Bad Term | Comments |
---|---|
expect |
And variants such as expected |
likely |
And variants such as will likely |
allowed, could, generally, might, probably, perhaps |
And all other such terms of choice. Use may: or can: depending on the context. |
may: or may: not |
Just use may:. |
5. Writing Style
5.1. Miscellaneous Grammar, Spelling, and Punctuation Issues
5.1.1. Use the Oxford Comma (Serial Comma)
When writing a sentence listing a series of items, include a comma before the “and” separating the last item.
Correct: The red, green, blue, and alpha components.
Incorrect: The red, green, blue and alpha components.
5.1.2. Date Format
Whenever possible, write dates in the ISO 8601 format: YYYY-MM-DD.
If needed for consistency with existing dates, e.g. in appendix changelogs, you can also write “Month DD, YYYY” where “Month” is the English name of the month.
Never use ambiguous formats such as “09/12/16”.
* 2016-09-12
* September 12, 2016
5.1.3. A/An and Markup Macros
Use “a” and “an” correctly, based on the sound of the letter beginning the following word.
It is easy to get this wrong when talking about OpenXR API names tagged with the markup macros. For example, if you wanted to say:
An xrCreateInstance call
the correct way to mark this up in asciidoc would be:
An flink:xrCreateInstance call
However, on first glance at this it appears wrong, because the “word” following “an” is the macro name, “flink:”. This word does not start with a vowel, so the temptation is to say
A flink:xrCreateInstance call
What matters here is how the output document is formatted.
The checkMarkup
script, executed as a part of the CI process, checks this
automatically.
5.1.4. Numbers in Text
When describing the need for a small number of objects, smaller than ten, spell the number out (e.g. “one”). If you are describing a literal value that is a small number, you may use a numeric value (e.g. “1”).
For example, instead of writing that a bitmask “contains 1 or more bits”, write that it “contains one or more bits”. A counter example is that it is okay to write “For non-stereoscopic-3D applications, this value is 1.”
5.1.5. Use American Spelling Conventions
In case of conflict, use American rather than British spelling conventions, except for noted exceptions in the table below.
Use Spelling | Instead Of | Comments |
---|---|---|
color |
colour |
|
behavior |
behaviour |
|
signaled |
signalled |
|
tessellation |
tesselation |
Historical exception |
5.1.6. Compound Words and Preferred Orthography
Unless there is longstanding precedent in computer science literature, or the word is a noted exception in the table below, do not arbitrarily cram terms together.
This does not apply to parameter names in the API, where capitalization is
used to distinguish words.
For example, it is proper to refer to the use of a colorSpace
member
of a structure as a “color space” value.
Use Spelling | Instead Of | Comments |
---|---|---|
bit plane |
bitplane |
|
compile time |
compile-time |
Per Wikipedia “compile time” |
color space |
colorspace |
|
double-buffer |
doublebuffer |
|
entry point |
entry-point |
Except if needed to disambiguate from surrounding terms |
flat shading |
flatshading |
|
GitHub |
Github |
Site’s preferred spelling |
LOD |
lod |
Acronym for “Level of Detail” |
mip level |
miplevel |
“mipmap term” may be used in time |
Exceptions |
||
mipmap |
mip map |
Exception for historical reasons |
|
|
|
swapchain |
swap chain |
Exception due to heavy use in WSI extensions |
happen-before |
happen before |
As used in concurrent languages such as C++11, Java and OpenCL C. |
Words With "Pre-" Prefixes
When using the prefix “pre” to indicate “prior to”, such as in the words “preinitialized”, “preprocess”, and “pretransform”, do not separate the prefix from the word with a hyphen. This list is not intended to be complete.
5.2. Describing Commands and Parameters
The OpenXR API Specification describes API commands followed by descriptions of their parameters, which are usually simple scalar types, handles or pointers to OpenXR objects or arrays of objects, enumerated types specifying values or bitmasks which affect the operation of a command; or structures containing combinations of scalar types and objects. The templates and examples shown and annotated here are based on the OpenXR API Specification. Do not vary from them without compelling need.
Normative parts of the OpenXR API Specification should describe what something does, rather than how or why an application would want to use it or how or why a runtime should implement it.
When explicitly allowed by the Specification, the reserved value NULL
may be used for pointer parameters and members, and the reserved value
XR_NULL_HANDLE
may be used for OpenXR object handle parameters and
members.
Otherwise, pointers and handles must refer to valid memory and valid OpenXR
objects, respectively.
Guideline
As a simple example, say “To create an instance, call rather than “You/The application/The user can create an instance by calling
|
Explanations of why and how should largely be confined to reference documentation, sample code, tutorials, and other such documents. Occasional non-normative explanations can be included in the OpenXR API Specification using informative notes.
5.3. Math Markup
There are two ways of marking up math expressions, described below.
5.3.1. Asciidoc Math Markup
Where possible, math is marked up using straight asciidoc features.
For commonality with LaTeX math (see below), some common LaTeX operators and
names are defined as asciidoc attributes using the same names, expanding to
the corresponding Unicode entities.
The complete set of these attributes is found in config/attribs.adoc
.
Feature | Result | Sample Markup |
---|---|---|
Subscripts |
ax |
[eq]#a~x~# |
Superscripts |
-2(b-1) |
[eq]#-2^(b-1)^# |
Struct/parameter names as variables |
2 |
[eq]#2^pname:bits^# |
Greek Letters (selected) |
α, β, γ, δ, Δ, ε, λ, ρ, τ |
[eq]#{alpha}, {beta}, {gamma}, {delta}, {DeltaUpper}, {epsilon}, {lambda}, {rho}, {tau}# |
Fractions |
¼ + ½ |
[eq]#{onequarter} {plus} {onehalf}# |
Closed Ranges |
[0,1] |
[eq]#[0,1]# |
Open Ranges |
[0,1) |
[eq]#[0,1)# |
Arithmetic and Relational Operators |
a × b, a ≤ b, a ≠ b, a ≥ b, |x| |
[eq]#a {times} b#, [eq]#a {leq} b#, [eq]#a {neq} b#, [eq]#a {geq} b#, [eq]#{vert}x{vert}# |
Floor |
⌊w - ½⌋ |
[eq]#{lfloor}w - {onehalf}{rfloor}# |
Ceiling |
⌈log2(max( |
[eq]#{lceil}log~2~(max(pname:width, pname:height)){rceil} {plus} 1# |
Logical and Set Operators |
∧ ¬ ∨ ⊕ ∈ |
[eq]#{land} {lnot} {lor} {oplus} {elem}# |
Partial Derivatives |
∂rx / ∂x = 0 |
[eq]#{partial}r~x~ / {partial}x = 0# |
Matrix/Vector Parameter Names |
P = t P1 + (1-t) P2 |
[eq]#**P** = t **P**~1~ {plus} (1-t) **P**~2~# |
5.3.2. LaTeX Math Markup
If we find we need math markup more complex than easily supported in straight asciidoc markup, we can re-introduce the use of KaTeX in-browser rendering script for HTML outputs, and asciidoctor-mathematical for PDF outputs, based on the latest usage in Vulkan. KaTeX code was removed from the OpenXR repo to simplify build and packaging because it was unused.
5.4. Describing Structure Chains
When describing a chained structure which is passed to a command by placing
it in the next
chain of a structure parameter of that command,
introduce the structure description in this fashion:
When *performing an operation described by the chained struct*, add
the slink:XrExtensionStructNameID to the pname:next chain of the
slink:XrBaseExtensionStructName structure passed to the
flink:xrBaseFunctionName command *saying what the chained struct
does*.
Note that while some (outdated) text still calls these extension structures, it is more accurate to call them chained structures, since there are cases where structures are chained entirely within the core specification. Wording in the spec conflating chained structures and extensions has been gradually corrected over time, but older references may still make this error.
5.5. An Example Command Description
The next section is a sample based on the OpenXR API Specification, and describes a command in enough detail to see the different usage patterns and layout / markup used. Informative notes discussing markup and guidelines are interspersed with the example description to explain how and why it looks as it does.
5.6. Sample Command Description: Creating an Instance
The xrCreateInstance function is defined as:
// Provided by XR_VERSION_1_0
XrResult xrCreateInstance(
const XrInstanceCreateInfo* createInfo,
XrInstance* instance);
Guideline
Begin the command description with an open block delimiting the contents as a reference page. The open block contains several required attribute values, as described for automatic extraction into a reference page. Prefer a short, active sentence when describing what commands do, instead of more passive phrasing like “An instance is created by calling:” or “The application may create an instance by calling:”. However, many start with "<entity> is defined as", where "<entity>" is the function, structure, or type name, which was accepted by the group. After the description, include the autogenerated prototype for the command
from the
Note that each autogenerated command, enumeration, flag, or structure
definition include file also defines a corresponding asciidoc anchor which
is the base name of the file.
In this case, the anchor is named |
xrCreateInstance creates the XrInstance, then enables and
initializes global API layers and extensions requested by the application.
If an extension is provided by an API layer, both the API layer and
extension must be specified at xrCreateInstance time.
If a specified API layer cannot be found, no XrInstance will be
created and the function will return XR_ERROR_API_LAYER_NOT_PRESENT
.
Likewise, if a specified extension cannot be found, the call must return
XR_ERROR_EXTENSION_NOT_PRESENT
and no XrInstance will be
created.
(Additional prose excluded from example.)
Guideline
Each command parameter is described in a separate bullet list entry, followed by validity rules, then detailed descriptions of any new structures, flags, or enumerations introduced by this command. Each parameter should appear as a separate bullet list item beginning with the parameter name, in the same order as parameters appear in the command. This aids in extracting short descriptions of parameters for inclusion in annotated headers and similar documentation. Make sure to tag each parameter with the pname: macro. Strive for compact notation, and in particular always try to use the phrasing “pname:param is” rather than wordier forms such as “pname:param specifies” or “The pname:param parameter specifies”. In general there is no need to describe a parameter which is an OpenXR object handle as a handle; for example, say “pname:device is the logical device” rather than “pname:device is a handle to the logical device”. An exception is object creation functions, where a pointer to a handle of the proper type is used to return the newly created object. |
Guideline
Some parameter and member validation language for commands and structures is
implicit (autogenerated from
End the open block surrounding the command description after the implicit validity include. All content within the block will be extracted for the corresponding reference page. |
Guideline
Open blocks delimiting reference page content should not themselves contain section headers, as asciidoctor cannot render such nested content correctly. Reference pages should in general be relatively short, so this limitation is not severe. |
The XrInstanceCreateInfo structure is defined as:
typedef struct XrInstanceCreateInfo {
XrStructureType type;
const void* next;
XrInstanceCreateFlags createFlags;
XrApplicationInfo applicationInfo;
uint32_t enabledApiLayerCount;
const char* const* enabledApiLayerNames;
uint32_t enabledExtensionCount;
const char* const* enabledExtensionNames;
} XrInstanceCreateInfo;
Guideline
Begin the structure description with an open block delimiting the contents as a reference page, in the same fashion as described above for commands. The open block contains several required attribute values, as described for automatic extraction into a reference page. Use a short paragraph to introduce the structure, usually just “The
After the description, include the autogenerated definition for the
structure from the
|
Guideline
Each structure member is described in a separate bullet list entry.
There is standard boilerplate for the Regarding the
These entries should be short and functional, without describing details of e.g. new enumerant values, function of individual parameter settings, etc. They can refer to other types using the appropriate *link: macros or to related sections of the specification using asciidoc xrefs. In rare cases, an entry will cover multiple paragraphs. In these cases the normal list nesting and indentation guidelines cannot be applied due to limitations of the asciidoc parser. It is usually best to append a continuation block following the first paragraph of such a list item. |
Guideline
In addition to implicit validity language, there may be additional validation language which is explicit. This is rare in OpenXR, as such requirements are usually in prose instead. Such language is written in a separate block in the specification, preceding the validity include. Prose description of the structure also goes here, if the prose associated with the command is insufficient. The example above does not have any explicit validity language or additional prose. |
Guideline
Following the definition of structure members, include a prose description of structure usage, if appropriate. Though it is not common in OpenXR, any explicit validity language would be added next. See the Vulkan style guide for guidance on phrasing explicit validity. This is followed by including the implicit (automatically generated) validity language include for this structure:
Be clear on the distinction between a “valid pointer” and a “pointer to a valid object” when writing spec language. Any explicit Valid Usage statements must be assigned Valid Usage ID tags before publication. This process is normally performed only when preparing to integrate functionality into the OpenXR Specification prior to publication. It is something authors of new functionality should be aware of, but are not themselves responsible for. |
5.7. Markup For Automatic Reference Page Extraction
The OpenXR reference pages are (mostly) being extracted from corresponding sections of the API Specification. This requires that the markup and writing conventions described above be adhered to rigidly.
The extraction scripts for a given page rely on the existence of an asciidoc
open
block surrounding markup describing that page, with attributes used
to specify properties of the reference page.
Additional heuristics and non-asciidoc tags, described below, are used to
identify subsections of a reference page in some cases.
In general the open block introduction will look like:
[open,refpage='name',desc='short description',type='pagetype',xrefs='xrefs']
--
Attributes which can be set on the block are:
-
refpage - the name of the reference page, e.g. the Vulkan interface (command, structure, enumerant, handle, etc.) name. This attribute is required.
-
desc - short description / summary of the page, used in the page title. This attribute is required.
-
type - type of the interface, which must match the directory name following
api/
in the interfaceinclude::
line within the block, and must be one ofbasetypes
,defines
,enums
,flags
,funcpointers
,handles
,protos
, orstructs
. This attribute is required. -
xrefs - list of whitespace-separated names of other reference pages which should be added to the
See Also
section of this page. Most cross-references are automatically generated based on the immediate dependency information inxr.xml
, but in some cases, such as referring between*FlagBits
and*Flags
types, this additional tagging is useful. This attribute is optional.
Attributes of the open block must be written in this format, using single quotes as delimiters (even though asciidoc markup also allows double quotes), and escape single quotes in e.g. the desc attribute value with backquotes.
After the open block is started, the following markup should be provided:
-
A single paragraph of text describing the definition of the interface. This paragraph is optional, but strongly recommended.
-
The
include
line for the interface, which must be consistent with the page name and type in the open block attributes. This paragraph is required. -
A bullet list describing function parameters, structure members, enumerants in an enumerated type, etc. This list should contain no empty lines, as the extraction script classifies the uninterrupted block of text following the
include
directive as theParameters
orMembers
section of the ref page. This list is required, unless the interface has nothing to describe, such as an empty structure or enumeration, or a function with no parameters. -
Paragraphs of text making up the
Description
section of the ref page. This section is optional. If it is necessary due to constraints of asciidoc markup to have an empty line in the bullet list section1, add a// refBody
comment immediately following the bullet list and preceding this section: -
A paragraph of text introducing the definition of the interface. If the
refBegin
comment does not exist, this paragraph must be present. -
The
include
line for the interface, which must be consistent with the interface name in the comment line. -
A bullet list describing function parameters, structure members, enumerants in an enumerated type, etc. This list should contain no empty lines, as the extraction script classifies the uninterrupted block of text following the
include
directive as theParameters
orMembers
section of the ref page. -
Optional paragraphs of text making up the
Description
section of the ref page. If it is necessary due to constraints of asciidoc markup to have an empty line in the bullet list section1, add arefBody
comment immediately following the bullet list and preceding this section:// refBody name
-
The
include
line for the validity statement of commands and structures. This line is required for commands and structures, but not for interfaces such as enumerated types, which do not have implicit valid usage blocks. -
Finally, a two-dash asciidoc delimiter closing the open block:
--
All elements specifying an interface name (open block refpage
attributes,
interface include
lines, and validity include
lines) must use the same
interface name, if present.
Otherwise the extraction script is either unable to extract that page, or
will extract the wrong text - and the language will be structurally
incorrect, as well.
The extraction process is somewhat fragile, so care should be taken and the
results of reference page extraction verified after making changes to that
portion of the specification source.
6. Registry XML Schema
The definitive record of the OpenXR API is in part an XML file named
xr.xml
.
It contains a machine-readable description of the API, API release versions
(major and minor), and extensions.
The XML format and schema is based upon the format used by Vulkan and other
Khronos standards, with modifications to suit the specific needs of OpenXR.
It is used in the specification development process to generate headers,
snippets included in the specification prose and output, and portions of the
loader and conformance tests.
It is also consumed by a variety of non-Khronos projects that have a need
for a machine-readable definition of OpenXR.
Maintaining compatibility with Vulkan, with whom we share substantial
specification toolchain software, and with downstream consumers of the XML,
is very important and guides its development.
6.1. Machine Readable Schema Definitions
The schema is described in two ways within the specification source
(openxr
internal monorepo or OpenXR-Docs
public GitHub repo):
-
A Relax-NG schema (compact notation) constraining basic structure:
specification/registry/registry.rnc
-
The
specification/checkXml.sh
script verifies the XML against the Relax-NG schema. It requires tools to be installed and available on thePATH
: see the script for details. -
The same script performs verification that the Relax-NG schema itself is valid, but no tests to verify that it rejects specific invalid XML constructs are available.
-
-
A Schematron schema enforcing more detailed constraints and style rules:
registry.sch
-
Schematron allows us to check more complex requirements, as well as to write our own "error messages". Our use of the Schematron language is somewhere between a formal schema and a business-logic rules enforcer.
-
The
specification/checkSchematron.sh
script verifies the XML against the Schematron schema. It requires that a JRE be available on the path and that a "schXslt".jar
binary be present. If it is not present, the script will attempt to download it from an official release and check the hash. Seespecification/registry/schematron.sh
for details on the required.jar
. -
Tests to verify that the Schematron document accepts valid constructs (
pass.*.xml
files) and rejects specific invalid constructs (fail.*.xml
files) are located inspecification/registry/schematron_tests
and executed using GNU-compatible Make in that directory. Requirements, besides a GNU-compatible Make, are the same as for thecheckSchematron.sh
script. -
Additions of new rules/assertions to the Schematron schema should be accompanied by minimal pass and fail test documents demonstrating that the rules behave as intended.
-
6.2. XML Format Details
To avoid unnecessary maintenance burden, the meaning of the XML tags and attributes is in general deferred to the Vulkan schema documentation. It is incorporated here by reference, with the following changes.
-
Ignore section 5 and 6 ("Platform Name Blocks (
platforms
tag)" and "Platform Names (platform
tag)")-
We do not use the
platforms
orplatform
tags.
-
-
Modify section 10 ("API Type (
type
tag)") describingtype
tags insidetypes
blocks, to add the following additional attribute-
parentstruct
- Indicates a polymorphic parent struct for this type, usually ending inBaseHeader
, such that this type begins with the same members as the parent and may be used in place of theparentstruct
type. Only available for structures, that is, wherecategory="struct"
.
-
-
Modify section 11 ("Enumerant Blocks -
enums
tag")-
The default value for
bitwidth
in OpenXR is 64 (rather than 32 as in Vulkan): All our bitmasks are 64 bit by default.
-
-
Modify section 12 ("Enumerants (
enum
tag)")-
enum
tags insideenums
blocks may (and are encouraged to) have acomment=""
attribute, which is extracted for automatic use in the spec and which may be used by other tools operating on the XML.
-
-
Modify section 19 ("Required and Removed Interfaces (
require
andremove
tags)")-
OpenXR still uses the
extension
andfeature
attributes ofrequire
tags, rather than thedepends
attribute that replaced them in Vulkan 1.3.241. -
In "Contents of
require
andremove
tags", add:interaction_profile
Tags -
In "Contents of
require
andremove
tags", add:extend
Tags for interaction profile paths
-
-
Ignore sections 20, 21, 22, and 23 ("Formats (
formats
tag)", "Image Format (format
tag)", "Format Components (component
tag)", "Format Planes (plane
tag)")-
We do not use
formats
,format
,component
, orplane
tags as described for Vulkan.
-
-
Ignore sections 24-29 (all those with "SPIR-V" in their title)
-
We do not use any tags related to SPIR-V.
-
-
Ignore sections 30-34 (which all mention "Sync" in their title)
-
We do not use
syncstage
,syncaccess
,syncpipeline
,syncsupport
, orsyncequivalent
tags.
-
-
Add the following sections defining new tags related to interaction profiles:
OpenXR also defines interaction profile elements and adaptations of existing elements, which are currently not documented but which may be understood by looking at the existing usages and schemas.
6.2.1. Interaction Profile Blocks (interaction_profiles
tag)
An interaction_profiles
tag contains definitions of interaction profile
paths and their associated valid component paths exposed through the API.
Attributes of interaction_profiles
tags
None.
Contents of interaction_profiles
Zero or more interaction_profile
tags, in arbitrary order.
6.2.2. Interaction Profiles (interaction_profile
tag)
An interaction_profile
tag defines an interaction profile path, the user
paths it is valid for, and the valid component subpaths and their action
types.
Attributes of interaction_profile
tags
-
name
- required. Full interaction profile path (starting with /interaction_profiles/) -
title
- required. Human readable description of the physical controller/device this interaction profile corresponds to, if applicable.
Contents of interaction_profiles
tags
One or more user_path
tags, and zero or more component
tags, in
arbitrary order.
The user_path
tag or tags are typically placed before all components.
6.2.3. Interaction Profile User Paths (user_path
tag)
A user_path
tag denotes a top-level user path, also known as a sub-action
path, for which the enclosing interaction profile is accepted.
Attributes of user_path
tags
-
path
- required. Full top-level user path (starting with /user/)
Contents of user_path
tags
None.
6.2.4. Interaction Profile Component (component
tag)
A component
tag denotes a component subpath for the enclosing interaction
profile that is valid on at least one of its user paths.
Attributes of component
tags
-
subpath
- required. Subpath string to append to the end of the interaction profile path (starts with either/input/
or/output
) -
type
- required. An enumerant value fromXrActionType
describing the most specific use of the component path. (For example, an path corresponding to an analog axis would useXR_ACTION_TYPE_FLOAT_INPUT
, even though it may be used as a suggested binding for an action of typeXR_ACTION_TYPE_BOOLEAN_INPUT
, according to the conversion rules in the specification.) -
system
- optional. If"true"
, applications are advised that the given component path may not be available for normal application use. -
user_path
- optional. If present, must correspond to one of the paths in theuser_path
tags for this interaction profile. Indicates that the component path is only available when suggesting bindings for this particular user path, rather than all indicated user paths as default.
Contents of user_path
tags
None.
6.2.5. Contents of require
: interaction_profile
Tags
Specifies a required interaction profile, by path, defined by an
interaction_profile
block within an interaction_profiles
block.
Valid only in require
blocks.
Attributes of interaction_profile
tags in require
blocks
-
name
- required. Full interaction profile path (starting with /interaction_profiles/). Must match thename
attribute of aninteraction_profile
block within aninteraction_profiles
block.
Contents of interaction_profile
tags in require
blocks
None.
6.2.6. Contents of require
: extend
Tags for interaction profiles
Specifies additional component paths to accept in an interaction profile
previously included in the specification by a dependency of this block’s
parent.
Valid only in require
blocks.
Attributes of interaction profile extend
tags in require
blocks
-
interaction_profile_path
- required. Full interaction profile path to extend (starting with /interaction_profiles/). Must match thename
attribute of aninteraction_profile
block within aninteraction_profiles
block.
Contents of interaction_profile
tags in require
blocks
One or more component
tags, in the
same schema used directly within an interaction_profile
block.
7. Still To Be Done
-
Something about verb tenses in the writing chapter.
-
Something about the use of abbreviations and acronyms.
8. Revision History
-
2017-06-14 - Branch from Vulkan Style Guide for initial commit. Some basic edits.
-
2017-07-07 - Changing more things to OpenXR examples. Adding OpenXR issues in most TODOs.
-
2020-03-12 - Major revisions in preparation for release.
-
Other small changes aligning document with working group practice.
-
2021-05-10 - Reference the extension process document on extending bitmasks, remove obsolete references to old Vulkan development models.
-
2022-08-26 - Update to reflect Vulkan script sync and moving all generated files into a single directory whose path is accessed using the AsciiDoc attribute
{generated}
-
2023-03-17 - Clarify that USB vendor ID, not PCI vendor ID, should be used in OpenXR.
-
2023-06-15 - Require vendor suffix in interaction profile paths introduced by extensions.
-
2023-07-13 - Document standing recommendation to discourage callbacks in OpenXR API design, other small changes to align more closely with existing working group practice.
-
2023-08-02 - Document the XML schema and how it differs from the Vulkan equivalent.