Add OpenXR 1.0.22 to thirdparty libraries

Will be compiled and used in the next commit.

Co-authored-by: Rémi Verschelde <rverschelde@gmail.com>
This commit is contained in:
Bastiaan Olij 2021-12-08 18:31:06 +11:00 committed by Rémi Verschelde
parent fcf8c2006d
commit 65bae5a341
59 changed files with 23956 additions and 1 deletions

View File

@ -361,12 +361,16 @@ Comment: Multi-channel signed distance field generator
Copyright: 2016, Viktor Chlumsky
License: MIT
Files: ./thirdparty/oidn/
Comment: Intel Open Image Denoise
Copyright: 2009-2019, Intel Corporation
License: Apache-2.0
Files: ./thirdparty/openxr/
Comment: OpenXR Loader
Copyright: 2020-2022, The Khronos Group Inc.
License: Apache-2.0
Files: ./thirdparty/pcre2/
Comment: PCRE2
Copyright: 1997-2021, University of Cambridge

25
thirdparty/README.md vendored
View File

@ -474,6 +474,7 @@ Files extracted from the upstream source:
- Files in `core/` folder.
- `LICENSE.txt` and `CHANGELOG.md`
## oidn
- Upstream: https://github.com/OpenImageDenoise/oidn
@ -505,6 +506,30 @@ Patch files are provided in `oidn/patches/`.
- scripts/resource_to_cpp.py (used in modules/denoise/resource_to_cpp.py)
## openxr
- Upstream: https://github.com/KhronosGroup/OpenXR-SDK
- Version: 1.0.22 (458984d7f59d1ae6dc1b597d94b02e4f7132eaba, 2022)
- License: Apache 2.0
Files extracted from upstream source:
- include/
- src/common/
- src/loader/
- src/*.{c,h}
- src/external/jsoncpp/include/
- src/external/jsoncpp/src/lib_json/
- LICENSE and COPYING.adoc
Exclude:
- src/external/android-jni-wrappers and src/external/jnipp (not used yet)
- All CMake stuff: cmake/, CMakeLists.txt and *.cmake
- All Gradle stuff: *gradle*, AndroidManifest.xml
- All following files (and their .license files): *.{def,in,json,map,pom,rc}
## pcre2
- Upstream: http://www.pcre.org

123
thirdparty/openxr/COPYING.adoc vendored Normal file
View File

@ -0,0 +1,123 @@
= COPYING.adoc for the Khronos Group OpenXR projects
// Copyright (c) 2020-2022, The Khronos Group Inc.
//
// SPDX-License-Identifier: CC-BY-4.0
This document is shared across a number of OpenXR GitHub projects, as the
set of files in those projects is partially overlapping.
(There is a single "source of truth" internal Khronos GitLab repo these
GitHub repositories interact with.)
== Licenses
The OpenXR GitHub projects use several licenses.
In general, we work to maintain compliance with the
https://reuse.software/spec/[REUSE 3.0 specification] with clear copyright
holders and license identifier listed for each file, preferably in each
file.
Where this is not possible, or e.g. when we are using files unmodified from
other open-source projects, license data is listed:
* in an adjacent file of the same name, with the additional extension
"`.license`"
* in the repository-wide "`.reuse/dep5`" copyright description
https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/["DEP5"
machine-readable copyright data] file.
The https://github.com/fsfe/reuse-tool["`reuse`" command line tool] can be
used to create a software bill of materials in SPDX format from this data.
Note that this tool will typically exclude the generated files, so if the
BOM is important to you, you may consider using the
https://github.com/KhronosGroup/OpenXR-SDK[OpenXR-SDK] repository that
contains the API headers and the loader source with all generated files
pre-generated.
The data in/adjacent to each file is the authoritative license and copyright
data.
However, for ease of understanding, the following general practices can be
observed.
(If in doubt, or if the following summary conflicts with the per-file data,
the per-file data remains authoritative.)
* The source files (in asciidoctor and other formats) for the OpenXR
Specification, reference pages, and supporting documentation are licensed
under the Creative Commons Attribution 4.0 International License (SPDX
license identifier "`CC-BY-4.0`").
* Header files, scripts, programs, XML files, and other tooling used or
generated as part of the build process is licensed under the Apache
License, Version 2.0.
* For compatibility with external developers working in GPLed projects who
have requested it, the main OpenXR headers, XML registry, and loader
source are licensed under a dual license with the SPDX license identifier
"`Apache-2.0 OR MIT`" .
Relevant files include:
** "`specification/registry/xr.xml`"
** "`include/openxr/openxr_platform_defines.h`"
** The generated OpenXR headers "`openxr.h`", "`openxr_platform.h`", and
"`openxr_reflection.h`".
** Source files in "`src/loader/`", and a few files in "`src/common/`".
** Generated source files used by the loader (including pre-generated in
OpenXR-SDK): "`common_config.h`", "`xr_generated_loader.cpp`", and
"`xr_generated_loader.hpp`".
* There are a few files adopted from other open source projects.
Such files continue under their original licenses, and appropriately
annotated in accordance with REUSE.
* Some generated, transient files produced during the course of building the
specification, headers, or other targets may not have copyrights.
These are typically very short asciidoc fragments describing parts of the
OpenXR API, and are incorporated by reference into specification or
reference page builds.
Users outside Khronos who create and post OpenXR Specifications, whether
modified or not, should use the CC-BY-4.0 license on the output documents
(HTML, PDF, etc.) they generate.
== Frequently Asked Questions
Q: Why are the HTML and PDF Specifications posted on Khronos' website under
a license which is neither CC-BY-4.0 nor Apache 2.0?
A: The Specifications posted by Khronos in the OpenXR Registry are licensed
under the proprietary Khronos Specification License.
Only these Specifications are Ratified by the Khronos Board of Promoters,
and therefore they are the only Specifications covered by the Khronos
Intellectual Property Rights Policy.
Q: Does Khronos allow the creation and distribution of modified versions of
the OpenXR Specification, such as translations to other languages?
A: Yes.
Such modified Specifications, since they are not created by Khronos, should
be placed under the CC-BY-4.0 license.
If you believe your modifications are of general interest, consider
contributing them back by making a pull request (PR) on the OpenXR-Docs
project.
Q: Can I contribute changes to the OpenXR Specification?
A: Yes, by opening an Issue or Pull Request (PR) on the
link:https://github.com/KhronosGroup/OpenXR-Docs/[OpenXR-Docs] GitHub
project.
You must execute a click-through Contributor License Agreement, which brings
your changes under the umbrella of the Khronos IP policy.
Q: Can you change the license on your files so they're compatible with my
license?
A: We are using a dual license license on `xr.xml`, the main API headers,
and the loader source files, to make them compatible with GPL-2.0- and
LGPL-2.0/2.1-licensed projects.
This replaces earlier approaches of an MIT-like license on the XML and
Apache 2.0 on all headers, and allows use of the SPDX license identifier
"`Apache-2.0 OR MIT`" to denote the license.
If you *require* this same compatibility for use of other Apache-2.0
licensed files in our repository, please raise an issue identifying the
files and we will consider changing those specific files to the dual license
as well.

202
thirdparty/openxr/LICENSE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

3925
thirdparty/openxr/include/openxr/openxr.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,675 @@
#ifndef OPENXR_PLATFORM_H_
#define OPENXR_PLATFORM_H_ 1
/*
** Copyright (c) 2017-2022, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_thread_settings 1
#define XR_KHR_android_thread_settings_SPEC_VERSION 5
#define XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME "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;
typedef XrResult (XRAPI_PTR *PFN_xrSetAndroidApplicationThreadKHR)(XrSession session, XrAndroidThreadTypeKHR threadType, uint32_t threadId);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR(
XrSession session,
XrAndroidThreadTypeKHR threadType,
uint32_t threadId);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_surface_swapchain 1
#define XR_KHR_android_surface_swapchain_SPEC_VERSION 4
#define XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME "XR_KHR_android_surface_swapchain"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchainAndroidSurfaceKHR)(XrSession session, const XrSwapchainCreateInfo* info, XrSwapchain* swapchain, jobject* surface);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR(
XrSession session,
const XrSwapchainCreateInfo* info,
XrSwapchain* swapchain,
jobject* surface);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_android_create_instance 1
#define XR_KHR_android_create_instance_SPEC_VERSION 3
#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance"
// XrInstanceCreateInfoAndroidKHR extends XrInstanceCreateInfo
typedef struct XrInstanceCreateInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationActivity;
} XrInstanceCreateInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_swapchain_format_list 1
#define XR_KHR_vulkan_swapchain_format_list_SPEC_VERSION 4
#define XR_KHR_VULKAN_SWAPCHAIN_FORMAT_LIST_EXTENSION_NAME "XR_KHR_vulkan_swapchain_format_list"
typedef struct XrVulkanSwapchainFormatListCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
uint32_t viewFormatCount;
const VkFormat* viewFormats;
} XrVulkanSwapchainFormatListCreateInfoKHR;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_OPENGL
#define XR_KHR_opengl_enable 1
#define XR_KHR_opengl_enable_SPEC_VERSION 10
#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
#ifdef XR_USE_PLATFORM_WIN32
// XrGraphicsBindingOpenGLWin32KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLWin32KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
HDC hDC;
HGLRC hGLRC;
} XrGraphicsBindingOpenGLWin32KHR;
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_PLATFORM_XLIB
// XrGraphicsBindingOpenGLXlibKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLXlibKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
Display* xDisplay;
uint32_t visualid;
GLXFBConfig glxFBConfig;
GLXDrawable glxDrawable;
GLXContext glxContext;
} XrGraphicsBindingOpenGLXlibKHR;
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
// XrGraphicsBindingOpenGLXcbKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLXcbKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
xcb_connection_t* connection;
uint32_t screenNumber;
xcb_glx_fbconfig_t fbconfigid;
xcb_visualid_t visualid;
xcb_glx_drawable_t glxDrawable;
xcb_glx_context_t glxContext;
} XrGraphicsBindingOpenGLXcbKHR;
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_WAYLAND
// XrGraphicsBindingOpenGLWaylandKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLWaylandKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
struct wl_display* display;
} XrGraphicsBindingOpenGLWaylandKHR;
#endif // XR_USE_PLATFORM_WAYLAND
typedef struct XrSwapchainImageOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLKHR;
typedef struct XrGraphicsRequirementsOpenGLKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_OPENGL */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_KHR_opengl_es_enable 1
#define XR_KHR_opengl_es_enable_SPEC_VERSION 8
#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable"
#ifdef XR_USE_PLATFORM_ANDROID
// XrGraphicsBindingOpenGLESAndroidKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingOpenGLESAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingOpenGLESAndroidKHR;
#endif // XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainImageOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t image;
} XrSwapchainImageOpenGLESKHR;
typedef struct XrGraphicsRequirementsOpenGLESKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsOpenGLESKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable 1
#define XR_KHR_vulkan_enable_SPEC_VERSION 8
#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable"
// XrGraphicsBindingVulkanKHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingVulkanKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t queueFamilyIndex;
uint32_t queueIndex;
} XrGraphicsBindingVulkanKHR;
typedef struct XrSwapchainImageVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
} XrSwapchainImageVulkanKHR;
typedef struct XrGraphicsRequirementsVulkanKHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
XrVersion minApiVersionSupported;
XrVersion maxApiVersionSupported;
} XrGraphicsRequirementsVulkanKHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDeviceKHR)(XrInstance instance, XrSystemId systemId, VkInstance vkInstance, VkPhysicalDevice* vkPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
XrInstance instance,
XrSystemId systemId,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDeviceKHR(
XrInstance instance,
XrSystemId systemId,
VkInstance vkInstance,
VkPhysicalDevice* vkPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_GRAPHICS_API_D3D11
#define XR_KHR_D3D11_enable 1
#define XR_KHR_D3D11_enable_SPEC_VERSION 8
#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable"
// XrGraphicsBindingD3D11KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingD3D11KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D11Device* device;
} XrGraphicsBindingD3D11KHR;
typedef struct XrSwapchainImageD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D11Texture2D* texture;
} XrSwapchainImageD3D11KHR;
typedef struct XrGraphicsRequirementsD3D11KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D11KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D11GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D11KHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_D3D11 */
#ifdef XR_USE_GRAPHICS_API_D3D12
#define XR_KHR_D3D12_enable 1
#define XR_KHR_D3D12_enable_SPEC_VERSION 8
#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable"
// XrGraphicsBindingD3D12KHR extends XrSessionCreateInfo
typedef struct XrGraphicsBindingD3D12KHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
ID3D12Device* device;
ID3D12CommandQueue* queue;
} XrGraphicsBindingD3D12KHR;
typedef struct XrSwapchainImageD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
ID3D12Resource* texture;
} XrSwapchainImageD3D12KHR;
typedef struct XrGraphicsRequirementsD3D12KHR {
XrStructureType type;
void* XR_MAY_ALIAS next;
LUID adapterLuid;
D3D_FEATURE_LEVEL minFeatureLevel;
} XrGraphicsRequirementsD3D12KHR;
typedef XrResult (XRAPI_PTR *PFN_xrGetD3D12GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsD3D12KHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_D3D12 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_KHR_win32_convert_performance_counter_time 1
#define XR_KHR_win32_convert_performance_counter_time_SPEC_VERSION 1
#define XR_KHR_WIN32_CONVERT_PERFORMANCE_COUNTER_TIME_EXTENSION_NAME "XR_KHR_win32_convert_performance_counter_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertWin32PerformanceCounterToTimeKHR)(XrInstance instance, const LARGE_INTEGER* performanceCounter, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToWin32PerformanceCounterKHR)(XrInstance instance, XrTime time, LARGE_INTEGER* performanceCounter);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertWin32PerformanceCounterToTimeKHR(
XrInstance instance,
const LARGE_INTEGER* performanceCounter,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToWin32PerformanceCounterKHR(
XrInstance instance,
XrTime time,
LARGE_INTEGER* performanceCounter);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_TIMESPEC
#define XR_KHR_convert_timespec_time 1
#define XR_KHR_convert_timespec_time_SPEC_VERSION 1
#define XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME "XR_KHR_convert_timespec_time"
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimespecTimeToTimeKHR)(XrInstance instance, const struct timespec* timespecTime, XrTime* time);
typedef XrResult (XRAPI_PTR *PFN_xrConvertTimeToTimespecTimeKHR)(XrInstance instance, XrTime time, struct timespec* timespecTime);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimespecTimeToTimeKHR(
XrInstance instance,
const struct timespec* timespecTime,
XrTime* time);
XRAPI_ATTR XrResult XRAPI_CALL xrConvertTimeToTimespecTimeKHR(
XrInstance instance,
XrTime time,
struct timespec* timespecTime);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_TIMESPEC */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_loader_init_android 1
#define XR_KHR_loader_init_android_SPEC_VERSION 1
#define XR_KHR_LOADER_INIT_ANDROID_EXTENSION_NAME "XR_KHR_loader_init_android"
typedef struct XrLoaderInitInfoAndroidKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
void* XR_MAY_ALIAS applicationVM;
void* XR_MAY_ALIAS applicationContext;
} XrLoaderInitInfoAndroidKHR;
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_KHR_vulkan_enable2 1
#define XR_KHR_vulkan_enable2_SPEC_VERSION 2
#define XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME "XR_KHR_vulkan_enable2"
typedef XrFlags64 XrVulkanInstanceCreateFlagsKHR;
// Flag bits for XrVulkanInstanceCreateFlagsKHR
typedef XrFlags64 XrVulkanDeviceCreateFlagsKHR;
// Flag bits for XrVulkanDeviceCreateFlagsKHR
typedef struct XrVulkanInstanceCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
XrVulkanInstanceCreateFlagsKHR createFlags;
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
const VkInstanceCreateInfo* vulkanCreateInfo;
const VkAllocationCallbacks* vulkanAllocator;
} XrVulkanInstanceCreateInfoKHR;
typedef struct XrVulkanDeviceCreateInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
XrVulkanDeviceCreateFlagsKHR createFlags;
PFN_vkGetInstanceProcAddr pfnGetInstanceProcAddr;
VkPhysicalDevice vulkanPhysicalDevice;
const VkDeviceCreateInfo* vulkanCreateInfo;
const VkAllocationCallbacks* vulkanAllocator;
} XrVulkanDeviceCreateInfoKHR;
typedef XrGraphicsBindingVulkanKHR XrGraphicsBindingVulkan2KHR;
typedef struct XrVulkanGraphicsDeviceGetInfoKHR {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrSystemId systemId;
VkInstance vulkanInstance;
} XrVulkanGraphicsDeviceGetInfoKHR;
typedef XrSwapchainImageVulkanKHR XrSwapchainImageVulkan2KHR;
typedef XrGraphicsRequirementsVulkanKHR XrGraphicsRequirementsVulkan2KHR;
typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanInstanceKHR)(XrInstance instance, const XrVulkanInstanceCreateInfoKHR* createInfo, VkInstance* vulkanInstance, VkResult* vulkanResult);
typedef XrResult (XRAPI_PTR *PFN_xrCreateVulkanDeviceKHR)(XrInstance instance, const XrVulkanDeviceCreateInfoKHR* createInfo, VkDevice* vulkanDevice, VkResult* vulkanResult);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsDevice2KHR)(XrInstance instance, const XrVulkanGraphicsDeviceGetInfoKHR* getInfo, VkPhysicalDevice* vulkanPhysicalDevice);
typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanGraphicsRequirements2KHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanInstanceKHR(
XrInstance instance,
const XrVulkanInstanceCreateInfoKHR* createInfo,
VkInstance* vulkanInstance,
VkResult* vulkanResult);
XRAPI_ATTR XrResult XRAPI_CALL xrCreateVulkanDeviceKHR(
XrInstance instance,
const XrVulkanDeviceCreateInfoKHR* createInfo,
VkDevice* vulkanDevice,
VkResult* vulkanResult);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsDevice2KHR(
XrInstance instance,
const XrVulkanGraphicsDeviceGetInfoKHR* getInfo,
VkPhysicalDevice* vulkanPhysicalDevice);
XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanGraphicsRequirements2KHR(
XrInstance instance,
XrSystemId systemId,
XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_PLATFORM_EGL
#define XR_MNDX_egl_enable 1
#define XR_MNDX_egl_enable_SPEC_VERSION 1
#define XR_MNDX_EGL_ENABLE_EXTENSION_NAME "XR_MNDX_egl_enable"
// XrGraphicsBindingEGLMNDX extends XrSessionCreateInfo
typedef struct XrGraphicsBindingEGLMNDX {
XrStructureType type;
const void* XR_MAY_ALIAS next;
PFNEGLGETPROCADDRESSPROC getProcAddress;
EGLDisplay display;
EGLConfig config;
EGLContext context;
} XrGraphicsBindingEGLMNDX;
#endif /* XR_USE_PLATFORM_EGL */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_perception_anchor_interop 1
#define XR_MSFT_perception_anchor_interop_SPEC_VERSION 1
#define XR_MSFT_PERCEPTION_ANCHOR_INTEROP_EXTENSION_NAME "XR_MSFT_perception_anchor_interop"
typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT)(XrSession session, IUnknown* perceptionAnchor, XrSpatialAnchorMSFT* anchor);
typedef XrResult (XRAPI_PTR *PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT)(XrSession session, XrSpatialAnchorMSFT anchor, IUnknown** perceptionAnchor);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPerceptionAnchorMSFT(
XrSession session,
IUnknown* perceptionAnchor,
XrSpatialAnchorMSFT* anchor);
XRAPI_ATTR XrResult XRAPI_CALL xrTryGetPerceptionAnchorFromSpatialAnchorMSFT(
XrSession session,
XrSpatialAnchorMSFT anchor,
IUnknown** perceptionAnchor);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_MSFT_holographic_window_attachment 1
#define XR_MSFT_holographic_window_attachment_SPEC_VERSION 1
#define XR_MSFT_HOLOGRAPHIC_WINDOW_ATTACHMENT_EXTENSION_NAME "XR_MSFT_holographic_window_attachment"
#ifdef XR_USE_PLATFORM_WIN32
// XrHolographicWindowAttachmentMSFT extends XrSessionCreateInfo
typedef struct XrHolographicWindowAttachmentMSFT {
XrStructureType type;
const void* XR_MAY_ALIAS next;
IUnknown* holographicSpace;
IUnknown* coreWindow;
} XrHolographicWindowAttachmentMSFT;
#endif // XR_USE_PLATFORM_WIN32
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_FB_android_surface_swapchain_create 1
#define XR_FB_android_surface_swapchain_create_SPEC_VERSION 1
#define XR_FB_ANDROID_SURFACE_SWAPCHAIN_CREATE_EXTENSION_NAME "XR_FB_android_surface_swapchain_create"
typedef XrFlags64 XrAndroidSurfaceSwapchainFlagsFB;
// Flag bits for XrAndroidSurfaceSwapchainFlagsFB
static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB = 0x00000001;
static const XrAndroidSurfaceSwapchainFlagsFB XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB = 0x00000002;
#ifdef XR_USE_PLATFORM_ANDROID
// XrAndroidSurfaceSwapchainCreateInfoFB extends XrSwapchainCreateInfo
typedef struct XrAndroidSurfaceSwapchainCreateInfoFB {
XrStructureType type;
const void* XR_MAY_ALIAS next;
XrAndroidSurfaceSwapchainFlagsFB createFlags;
} XrAndroidSurfaceSwapchainCreateInfoFB;
#endif // XR_USE_PLATFORM_ANDROID
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_PLATFORM_WIN32
#define XR_OCULUS_audio_device_guid 1
#define XR_OCULUS_audio_device_guid_SPEC_VERSION 1
#define XR_OCULUS_AUDIO_DEVICE_GUID_EXTENSION_NAME "XR_OCULUS_audio_device_guid"
#define XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS 128
typedef XrResult (XRAPI_PTR *PFN_xrGetAudioOutputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
typedef XrResult (XRAPI_PTR *PFN_xrGetAudioInputDeviceGuidOculus)(XrInstance instance, wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioOutputDeviceGuidOculus(
XrInstance instance,
wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
XRAPI_ATTR XrResult XRAPI_CALL xrGetAudioInputDeviceGuidOculus(
XrInstance instance,
wchar_t buffer[XR_MAX_AUDIO_DEVICE_STR_SIZE_OCULUS]);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#endif /* XR_USE_PLATFORM_WIN32 */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_FB_foveation_vulkan 1
#define XR_FB_foveation_vulkan_SPEC_VERSION 1
#define XR_FB_FOVEATION_VULKAN_EXTENSION_NAME "XR_FB_foveation_vulkan"
// XrSwapchainImageFoveationVulkanFB extends XrSwapchainImageVulkanKHR
typedef struct XrSwapchainImageFoveationVulkanFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkImage image;
uint32_t width;
uint32_t height;
} XrSwapchainImageFoveationVulkanFB;
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_FB_swapchain_update_state_android_surface 1
#define XR_FB_swapchain_update_state_android_surface_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_ANDROID_SURFACE_EXTENSION_NAME "XR_FB_swapchain_update_state_android_surface"
#ifdef XR_USE_PLATFORM_ANDROID
typedef struct XrSwapchainStateAndroidSurfaceDimensionsFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
uint32_t width;
uint32_t height;
} XrSwapchainStateAndroidSurfaceDimensionsFB;
#endif // XR_USE_PLATFORM_ANDROID
#endif /* XR_USE_PLATFORM_ANDROID */
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#define XR_FB_swapchain_update_state_opengl_es 1
#define XR_FB_swapchain_update_state_opengl_es_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME "XR_FB_swapchain_update_state_opengl_es"
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
typedef struct XrSwapchainStateSamplerOpenGLESFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
EGLenum minFilter;
EGLenum magFilter;
EGLenum wrapModeS;
EGLenum wrapModeT;
EGLenum swizzleRed;
EGLenum swizzleGreen;
EGLenum swizzleBlue;
EGLenum swizzleAlpha;
float maxAnisotropy;
XrColor4f borderColor;
} XrSwapchainStateSamplerOpenGLESFB;
#endif // XR_USE_GRAPHICS_API_OPENGL_ES
#endif /* XR_USE_GRAPHICS_API_OPENGL_ES */
#ifdef XR_USE_GRAPHICS_API_VULKAN
#define XR_FB_swapchain_update_state_vulkan 1
#define XR_FB_swapchain_update_state_vulkan_SPEC_VERSION 1
#define XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME "XR_FB_swapchain_update_state_vulkan"
#ifdef XR_USE_GRAPHICS_API_VULKAN
typedef struct XrSwapchainStateSamplerVulkanFB {
XrStructureType type;
void* XR_MAY_ALIAS next;
VkFilter minFilter;
VkFilter magFilter;
VkSamplerMipmapMode mipmapMode;
VkSamplerAddressMode wrapModeS;
VkSamplerAddressMode wrapModeT;
VkComponentSwizzle swizzleRed;
VkComponentSwizzle swizzleGreen;
VkComponentSwizzle swizzleBlue;
VkComponentSwizzle swizzleAlpha;
float maxAnisotropy;
XrColor4f borderColor;
} XrSwapchainStateSamplerVulkanFB;
#endif // XR_USE_GRAPHICS_API_VULKAN
#endif /* XR_USE_GRAPHICS_API_VULKAN */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,110 @@
/*
** Copyright (c) 2017-2022, The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#ifndef OPENXR_PLATFORM_DEFINES_H_
#define OPENXR_PLATFORM_DEFINES_H_ 1
#ifdef __cplusplus
extern "C" {
#endif
/* Platform-specific calling convention macros.
*
* Platforms should define these so that OpenXR clients call OpenXR functions
* with the same calling conventions that the OpenXR implementation expects.
*
* XRAPI_ATTR - Placed before the return type in function declarations.
* Useful for C++11 and GCC/Clang-style function attribute syntax.
* XRAPI_CALL - Placed after the return type in function declarations.
* Useful for MSVC-style calling convention syntax.
* XRAPI_PTR - Placed between the '(' and '*' in function pointer types.
*
* Function declaration: XRAPI_ATTR void XRAPI_CALL xrFunction(void);
* Function pointer type: typedef void (XRAPI_PTR *PFN_xrFunction)(void);
*/
#if defined(_WIN32)
#define XRAPI_ATTR
// On Windows, functions use the stdcall convention
#define XRAPI_CALL __stdcall
#define XRAPI_PTR XRAPI_CALL
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
#error "API not supported for the 'armeabi' NDK ABI"
#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
// On Android 32-bit ARM targets, functions use the "hardfloat"
// calling convention, i.e. float parameters are passed in registers. This
// is true even if the rest of the application passes floats on the stack,
// as it does by default when compiling for the armeabi-v7a NDK ABI.
#define XRAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define XRAPI_CALL
#define XRAPI_PTR XRAPI_ATTR
#else
// On other platforms, use the default calling convention
#define XRAPI_ATTR
#define XRAPI_CALL
#define XRAPI_PTR
#endif
#include <stddef.h>
#if !defined(XR_NO_STDINT_H)
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif // !defined( XR_NO_STDINT_H )
// XR_PTR_SIZE (in bytes)
#if (defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__))
#define XR_PTR_SIZE 8
#else
#define XR_PTR_SIZE 4
#endif
// Needed so we can use clang __has_feature portably.
#if !defined(XR_COMPILER_HAS_FEATURE)
#if defined(__clang__)
#define XR_COMPILER_HAS_FEATURE(x) __has_feature(x)
#else
#define XR_COMPILER_HAS_FEATURE(x) 0
#endif
#endif
// Identifies if the current compiler has C++11 support enabled.
// Does not by itself identify if any given C++11 feature is present.
#if !defined(XR_CPP11_ENABLED) && defined(__cplusplus)
#if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__)
#define XR_CPP11_ENABLED 1
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
#define XR_CPP11_ENABLED 1
#elif (__cplusplus >= 201103L) // 201103 is the first C++11 version.
#define XR_CPP11_ENABLED 1
#endif
#endif
// Identifies if the current compiler supports C++11 nullptr.
#if !defined(XR_CPP_NULLPTR_SUPPORTED)
#if defined(XR_CPP11_ENABLED) && \
((defined(__clang__) && XR_COMPILER_HAS_FEATURE(cxx_nullptr)) || \
(defined(__GNUC__) && (((__GNUC__ * 1000) + __GNUC_MINOR__) >= 4006)) || \
(defined(_MSC_VER) && (_MSC_VER >= 1600)) || \
(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403)))
#define XR_CPP_NULLPTR_SUPPORTED 1
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

10
thirdparty/openxr/src/.clang-format vendored Normal file
View File

@ -0,0 +1,10 @@
---
# Copyright (c) 2017-2022, The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
# Use defaults from the Google style with the following exceptions:
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 132
SortIncludes: false
...

View File

@ -0,0 +1,47 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
/*!
* @file
*
* Additional functions along the lines of the standard library algorithms.
*/
#pragma once
#include <algorithm>
#include <vector>
/// Like std::remove_if, except it works on associative containers and it actually removes this.
///
/// The iterator stuff in here is subtle - .erase() invalidates only that iterator, but it returns a non-invalidated iterator to the
/// next valid element which we can use instead of incrementing.
template <typename T, typename Pred>
static inline void map_erase_if(T &container, Pred &&predicate) {
for (auto it = container.begin(); it != container.end();) {
if (predicate(*it)) {
it = container.erase(it);
} else {
++it;
}
}
}
/*!
* Moves all elements matching the predicate to the end of the vector then erases them.
*
* Combines the two parts of the erase-remove idiom to simplify things and avoid accidentally using the wrong erase overload.
*/
template <typename T, typename Alloc, typename Pred>
static inline void vector_remove_if_and_erase(std::vector<T, Alloc> &vec, Pred &&predicate) {
auto b = vec.begin();
auto e = vec.end();
vec.erase(std::remove_if(b, e, std::forward<Pred>(predicate)), e);
}

View File

@ -0,0 +1,322 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>
// Nat Brown <natb@valvesoftware.com>
//
#include "filesystem_utils.hpp"
#include "platform_utils.hpp"
#include <cstring>
#include <string>
#if defined DISABLE_STD_FILESYSTEM
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#else
#include "stdfs_conditions.h"
#endif
#if USE_FINAL_FS == 1
#include <filesystem>
#define FS_PREFIX std::filesystem
#elif USE_EXPERIMENTAL_FS == 1
#include <experimental/filesystem>
#define FS_PREFIX std::experimental::filesystem
#elif defined(XR_USE_PLATFORM_WIN32)
// Windows fallback includes
#include <stdint.h>
#include <direct.h>
#else
// Linux/Apple fallback includes
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <dirent.h>
#endif
#if defined(XR_USE_PLATFORM_WIN32)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
#define ALTERNATE_DIRECTORY_SYMBOL '/'
#else
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#endif
#if (USE_FINAL_FS == 1) || (USE_EXPERIMENTAL_FS == 1)
// We can use one of the C++ filesystem packages
bool FileSysUtilsIsRegularFile(const std::string& path) { return FS_PREFIX::is_regular_file(path); }
bool FileSysUtilsIsDirectory(const std::string& path) { return FS_PREFIX::is_directory(path); }
bool FileSysUtilsPathExists(const std::string& path) { return FS_PREFIX::exists(path); }
bool FileSysUtilsIsAbsolutePath(const std::string& path) {
FS_PREFIX::path file_path(path);
return file_path.is_absolute();
}
bool FileSysUtilsGetCurrentPath(std::string& path) {
FS_PREFIX::path cur_path = FS_PREFIX::current_path();
path = cur_path.string();
return true;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
FS_PREFIX::path path_var(file_path);
parent_path = path_var.parent_path().string();
return true;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
absolute = FS_PREFIX::absolute(path).string();
return true;
}
bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {
#if defined(XR_USE_PLATFORM_WIN32)
// std::filesystem::canonical fails on UWP and must be avoided. Further, PathCchCanonicalize is not available on Windows 7 and
// PathCanonicalizeW is not available on UWP. However, symbolic links are not important on Windows since the loader uses the
// registry for indirection instead, and so this function can be a no-op on Windows.
canonical = path;
#else
canonical = FS_PREFIX::canonical(path).string();
#endif
return true;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
FS_PREFIX::path parent_path(parent);
FS_PREFIX::path child_path(child);
FS_PREFIX::path full_path = parent_path / child_path;
combined = full_path.string();
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
for (auto& dir_iter : FS_PREFIX::directory_iterator(path)) {
files.push_back(dir_iter.path().filename().string());
}
return true;
}
#elif defined(XR_OS_WINDOWS)
// For pre C++17 compiler that doesn't support experimental filesystem
bool FileSysUtilsIsRegularFile(const std::string& path) {
const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());
return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
}
bool FileSysUtilsIsDirectory(const std::string& path) {
const DWORD attr = GetFileAttributesW(utf8_to_wide(path).c_str());
return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
}
bool FileSysUtilsPathExists(const std::string& path) {
return (GetFileAttributesW(utf8_to_wide(path).c_str()) != INVALID_FILE_ATTRIBUTES);
}
bool FileSysUtilsIsAbsolutePath(const std::string& path) {
bool pathStartsWithDir = (path.size() >= 1) && ((path[0] == DIRECTORY_SYMBOL) || (path[0] == ALTERNATE_DIRECTORY_SYMBOL));
bool pathStartsWithDrive =
(path.size() >= 3) && (path[1] == ':' && (path[2] == DIRECTORY_SYMBOL || path[2] == ALTERNATE_DIRECTORY_SYMBOL));
return pathStartsWithDir || pathStartsWithDrive;
}
bool FileSysUtilsGetCurrentPath(std::string& path) {
wchar_t tmp_path[MAX_PATH];
if (nullptr != _wgetcwd(tmp_path, MAX_PATH - 1)) {
path = wide_to_utf8(tmp_path);
return true;
}
return false;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
std::string full_path;
if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);
parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);
return true;
}
return false;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
wchar_t tmp_path[MAX_PATH];
if (0 != GetFullPathNameW(utf8_to_wide(path).c_str(), MAX_PATH, tmp_path, NULL)) {
absolute = wide_to_utf8(tmp_path);
return true;
}
return false;
}
bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& absolute) {
// PathCchCanonicalize is not available on Windows 7 and PathCanonicalizeW is not available on UWP. However, symbolic links are
// not important on Windows since the loader uses the registry for indirection instead, and so this function can be a no-op on
// Windows.
absolute = path;
return true;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
std::string::size_type parent_len = parent.length();
if (0 == parent_len || "." == parent || ".\\" == parent || "./" == parent) {
combined = child;
return true;
}
char last_char = parent[parent_len - 1];
if ((last_char == DIRECTORY_SYMBOL) || (last_char == ALTERNATE_DIRECTORY_SYMBOL)) {
parent_len--;
}
combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
std::string searchPath;
FileSysUtilsCombinePaths(path, "*", searchPath);
WIN32_FIND_DATAW file_data;
HANDLE file_handle = FindFirstFileW(utf8_to_wide(searchPath).c_str(), &file_data);
if (file_handle != INVALID_HANDLE_VALUE) {
do {
if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
files.push_back(wide_to_utf8(file_data.cFileName));
}
} while (FindNextFileW(file_handle, &file_data));
return true;
}
return false;
}
#else // XR_OS_LINUX/XR_OS_APPLE fallback
// simple POSIX-compatible implementation of the <filesystem> pieces used by OpenXR
bool FileSysUtilsIsRegularFile(const std::string& path) {
struct stat path_stat;
stat(path.c_str(), &path_stat);
return S_ISREG(path_stat.st_mode);
}
bool FileSysUtilsIsDirectory(const std::string& path) {
struct stat path_stat;
stat(path.c_str(), &path_stat);
return S_ISDIR(path_stat.st_mode);
}
bool FileSysUtilsPathExists(const std::string& path) { return (access(path.c_str(), F_OK) != -1); }
bool FileSysUtilsIsAbsolutePath(const std::string& path) { return (path[0] == DIRECTORY_SYMBOL); }
bool FileSysUtilsGetCurrentPath(std::string& path) {
char tmp_path[PATH_MAX];
if (nullptr != getcwd(tmp_path, PATH_MAX - 1)) {
path = tmp_path;
return true;
}
return false;
}
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path) {
std::string full_path;
if (FileSysUtilsGetAbsolutePath(file_path, full_path)) {
std::string::size_type lastSeparator = full_path.find_last_of(DIRECTORY_SYMBOL);
parent_path = (lastSeparator == 0) ? full_path : full_path.substr(0, lastSeparator);
return true;
}
return false;
}
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute) {
// canonical path is absolute
return FileSysUtilsGetCanonicalPath(path, absolute);
}
bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical) {
char buf[PATH_MAX];
if (nullptr != realpath(path.c_str(), buf)) {
canonical = buf;
return true;
}
return false;
}
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined) {
std::string::size_type parent_len = parent.length();
if (0 == parent_len || "." == parent || "./" == parent) {
combined = child;
return true;
}
char last_char = parent[parent_len - 1];
if (last_char == DIRECTORY_SYMBOL) {
parent_len--;
}
combined = parent.substr(0, parent_len) + DIRECTORY_SYMBOL + child;
return true;
}
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths) {
std::string::size_type start = 0;
std::string::size_type location = path_list.find(PATH_SEPARATOR);
while (location != std::string::npos) {
paths.push_back(path_list.substr(start, location));
start = location + 1;
location = path_list.find(PATH_SEPARATOR, start);
}
paths.push_back(path_list.substr(start, location));
return true;
}
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files) {
DIR* dir = opendir(path.c_str());
if (dir == nullptr) {
return false;
}
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
files.emplace_back(entry->d_name);
}
closedir(dir);
return true;
}
#endif

View File

@ -0,0 +1,46 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <string>
#include <vector>
// Determine if the path indicates a regular file (not a directory or symbolic link)
bool FileSysUtilsIsRegularFile(const std::string& path);
// Determine if the path indicates a directory
bool FileSysUtilsIsDirectory(const std::string& path);
// Determine if the provided path exists on the filesystem
bool FileSysUtilsPathExists(const std::string& path);
// Get the current directory
bool FileSysUtilsGetCurrentPath(std::string& path);
// Get the parent path of a file
bool FileSysUtilsGetParentPath(const std::string& file_path, std::string& parent_path);
// Determine if the provided path is an absolute path
bool FileSysUtilsIsAbsolutePath(const std::string& path);
// Get the absolute path for a provided file
bool FileSysUtilsGetAbsolutePath(const std::string& path, std::string& absolute);
// Get the absolute path for a provided file
bool FileSysUtilsGetCanonicalPath(const std::string& path, std::string& canonical);
// Combine a parent and child directory
bool FileSysUtilsCombinePaths(const std::string& parent, const std::string& child, std::string& combined);
// Parse out individual paths in a path list
bool FileSysUtilsParsePathList(std::string& path_list, std::vector<std::string>& paths);
// Record all the filenames for files found in the provided path.
bool FileSysUtilsFindFilesInPath(const std::string& path, std::vector<std::string>& files);

View File

@ -0,0 +1,108 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
/*!
* @file
*
* Some utilities, primarily for working with OpenXR handles in a generic way.
*/
#pragma once
#include <openxr/openxr.h>
#include <string>
#include <stdint.h>
inline std::string to_hex(const uint8_t* const data, size_t bytes) {
std::string out(2 + bytes * 2, '?');
out[0] = '0';
out[1] = 'x';
static const char* hex = "0123456789abcdef";
auto ch = out.end();
for (size_t i = 0; i < bytes; ++i) {
auto b = data[i];
*--ch = hex[(b >> 0) & 0xf];
*--ch = hex[(b >> 4) & 0xf];
}
return out;
}
template <typename T>
inline std::string to_hex(const T& data) {
return to_hex(reinterpret_cast<const uint8_t* const>(&data), sizeof(data));
}
#if XR_PTR_SIZE == 8
/// Convert a handle into a same-sized integer.
template <typename T>
static inline uint64_t MakeHandleGeneric(T handle) {
return reinterpret_cast<uint64_t>(handle);
}
/// Treat an integer as a handle
template <typename T>
static inline T& TreatIntegerAsHandle(uint64_t& handle) {
return reinterpret_cast<T&>(handle);
}
/// @overload
template <typename T>
static inline T const& TreatIntegerAsHandle(uint64_t const& handle) {
return reinterpret_cast<T const&>(handle);
}
/// Does a correctly-sized integer represent a null handle?
static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == reinterpret_cast<void*>(handle); }
#else
/// Convert a handle into a same-sized integer: no-op on 32-bit systems
static inline uint64_t MakeHandleGeneric(uint64_t handle) { return handle; }
/// Treat an integer as a handle: no-op on 32-bit systems
template <typename T>
static inline T& TreatIntegerAsHandle(uint64_t& handle) {
return handle;
}
/// @overload
template <typename T>
static inline T const& TreatIntegerAsHandle(uint64_t const& handle) {
return handle;
}
/// Does a correctly-sized integer represent a null handle?
static inline bool IsIntegerNullHandle(uint64_t handle) { return XR_NULL_HANDLE == handle; }
#endif
/// Turns a uint64_t into a string formatted as hex.
///
/// The core of the HandleToHexString implementation is in here.
inline std::string Uint64ToHexString(uint64_t val) { return to_hex(val); }
/// Turns a uint32_t into a string formatted as hex.
inline std::string Uint32ToHexString(uint32_t val) { return to_hex(val); }
/// Turns an OpenXR handle into a string formatted as hex.
template <typename T>
inline std::string HandleToHexString(T handle) {
return to_hex(handle);
}
/// Turns a pointer-sized integer into a string formatted as hex.
inline std::string UintptrToHexString(uintptr_t val) { return to_hex(val); }
/// Convert a pointer to a string formatted as hex.
template <typename T>
inline std::string PointerToHexString(T const* ptr) {
return to_hex(ptr);
}

View File

@ -0,0 +1,114 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <openxr/openxr.h>
#ifdef __cplusplus
extern "C" {
#endif
// Forward declare.
typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo;
// Function pointer prototype for the xrCreateApiLayerInstance function used in place of xrCreateInstance.
// This function allows us to pass special API layer information to each layer during the process of creating an Instance.
typedef XrResult(XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo *info,
const XrApiLayerCreateInfo *apiLayerInfo, XrInstance *instance);
// Loader/API Layer Interface versions
// 1 - First version, introduces negotiation structure and functions
#define XR_CURRENT_LOADER_API_LAYER_VERSION 1
// Loader/Runtime Interface versions
// 1 - First version, introduces negotiation structure and functions
#define XR_CURRENT_LOADER_RUNTIME_VERSION 1
// Version negotiation values
typedef enum XrLoaderInterfaceStructs {
XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0,
XR_LOADER_INTERFACE_STRUCT_LOADER_INFO,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST,
XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO,
} XrLoaderInterfaceStructs;
#define XR_LOADER_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateLoaderInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_LOADER_INFO
uint32_t structVersion; // XR_LOADER_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateLoaderInfo)
uint32_t minInterfaceVersion;
uint32_t maxInterfaceVersion;
XrVersion minApiVersion;
XrVersion maxApiVersion;
} XrNegotiateLoaderInfo;
#define XR_API_LAYER_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateApiLayerRequest {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST
uint32_t structVersion; // XR_API_LAYER_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateApiLayerRequest)
uint32_t layerInterfaceVersion; // CURRENT_LOADER_API_LAYER_VERSION
XrVersion layerApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
PFN_xrCreateApiLayerInstance createApiLayerInstance;
} XrNegotiateApiLayerRequest;
#define XR_RUNTIME_INFO_STRUCT_VERSION 1
typedef struct XrNegotiateRuntimeRequest {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST
uint32_t structVersion; // XR_RUNTIME_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrNegotiateRuntimeRequest)
uint32_t runtimeInterfaceVersion; // CURRENT_LOADER_RUNTIME_VERSION
XrVersion runtimeApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
} XrNegotiateRuntimeRequest;
// Function used to negotiate an interface betewen the loader and an API layer. Each library exposing one or
// more API layers needs to expose at least this function.
typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo *loaderInfo,
const char *apiLayerName,
XrNegotiateApiLayerRequest *apiLayerRequest);
// Function used to negotiate an interface betewen the loader and a runtime. Each runtime should expose
// at least this function.
typedef XrResult(XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo *loaderInfo,
XrNegotiateRuntimeRequest *runtimeRequest);
// Forward declare.
typedef struct XrApiLayerNextInfo XrApiLayerNextInfo;
#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1
struct XrApiLayerNextInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO
uint32_t structVersion; // XR_API_LAYER_NEXT_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrApiLayerNextInfo)
char layerName[XR_MAX_API_LAYER_NAME_SIZE]; // Name of API layer which should receive this info
PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr; // Pointer to next API layer's xrGetInstanceProcAddr
PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance; // Pointer to next API layer's xrCreateApiLayerInstance
XrApiLayerNextInfo *next; // Pointer to the next API layer info in the sequence
};
#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512
#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1
typedef struct XrApiLayerCreateInfo {
XrLoaderInterfaceStructs structType; // XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO
uint32_t structVersion; // XR_API_LAYER_CREATE_INFO_STRUCT_VERSION
size_t structSize; // sizeof(XrApiLayerCreateInfo)
void *loaderInstance; // Pointer to the LoaderInstance class
char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE]; // Location to the found settings file (or empty '\0')
XrApiLayerNextInfo *nextInfo; // Pointer to the next API layer's Info
} XrApiLayerCreateInfo;
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -0,0 +1,276 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>
// Ryan Pavlik <ryan.pavlik@collabora.com>
// Dave Houlton <daveh@lunarg.com>
//
#include "object_info.h"
#include "extra_algorithms.h"
#include "hex_and_handles.h"
#include <openxr/openxr.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "memory.h"
std::string XrSdkLogObjectInfo::ToString() const {
std::ostringstream oss;
oss << Uint64ToHexString(handle);
if (!name.empty()) {
oss << " (" << name << ")";
}
return oss.str();
}
void ObjectInfoCollection::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
// If name is empty, we should erase it
if (object_name.empty()) {
RemoveObject(object_handle, object_type);
return;
}
// Otherwise, add it or update the name
XrSdkLogObjectInfo new_obj = {object_handle, object_type};
// If it already exists, update the name
auto lookup_info = LookUpStoredObjectInfo(new_obj);
if (lookup_info != nullptr) {
lookup_info->name = object_name;
return;
}
// It doesn't exist, so add a new info block
new_obj.name = object_name;
object_info_.push_back(new_obj);
}
void ObjectInfoCollection::RemoveObject(uint64_t object_handle, XrObjectType object_type) {
vector_remove_if_and_erase(
object_info_, [=](XrSdkLogObjectInfo const& info) { return info.handle == object_handle && info.type == object_type; });
}
XrSdkLogObjectInfo const* ObjectInfoCollection::LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) const {
auto e = object_info_.end();
auto it = std::find_if(object_info_.begin(), e, [&](XrSdkLogObjectInfo const& stored) { return Equivalent(stored, info); });
if (it != e) {
return &(*it);
}
return nullptr;
}
XrSdkLogObjectInfo* ObjectInfoCollection::LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) {
auto e = object_info_.end();
auto it = std::find_if(object_info_.begin(), e, [&](XrSdkLogObjectInfo const& stored) { return Equivalent(stored, info); });
if (it != e) {
return &(*it);
}
return nullptr;
}
bool ObjectInfoCollection::LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const {
auto info_lookup = LookUpStoredObjectInfo(info.objectHandle, info.objectType);
if (info_lookup != nullptr) {
info.objectName = info_lookup->name.c_str();
return true;
}
return false;
}
bool ObjectInfoCollection::LookUpObjectName(XrSdkLogObjectInfo& info) const {
auto info_lookup = LookUpStoredObjectInfo(info);
if (info_lookup != nullptr) {
info.name = info_lookup->name;
return true;
}
return false;
}
static std::vector<XrDebugUtilsObjectNameInfoEXT> PopulateObjectNameInfo(std::vector<XrSdkLogObjectInfo> const& obj) {
std::vector<XrDebugUtilsObjectNameInfoEXT> ret;
ret.reserve(obj.size());
std::transform(obj.begin(), obj.end(), std::back_inserter(ret), [](XrSdkLogObjectInfo const& info) {
return XrDebugUtilsObjectNameInfoEXT{XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, nullptr, info.type, info.handle,
info.name.c_str()};
});
return ret;
}
NamesAndLabels::NamesAndLabels(std::vector<XrSdkLogObjectInfo> obj, std::vector<XrDebugUtilsLabelEXT> lab)
: sdk_objects(std::move(obj)), objects(PopulateObjectNameInfo(sdk_objects)), labels(std::move(lab)) {}
void NamesAndLabels::PopulateCallbackData(XrDebugUtilsMessengerCallbackDataEXT& callback_data) const {
callback_data.objects = objects.empty() ? nullptr : const_cast<XrDebugUtilsObjectNameInfoEXT*>(objects.data());
callback_data.objectCount = static_cast<uint32_t>(objects.size());
callback_data.sessionLabels = labels.empty() ? nullptr : const_cast<XrDebugUtilsLabelEXT*>(labels.data());
callback_data.sessionLabelCount = static_cast<uint32_t>(labels.size());
}
void DebugUtilsData::LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const {
auto session_label_iterator = session_labels_.find(session);
if (session_label_iterator != session_labels_.end()) {
auto& XrSdkSessionLabels = *session_label_iterator->second;
// Copy the debug utils labels in reverse order in the the labels vector.
std::transform(XrSdkSessionLabels.rbegin(), XrSdkSessionLabels.rend(), std::back_inserter(labels),
[](XrSdkSessionLabelPtr const& label) { return label->debug_utils_label; });
}
}
XrSdkSessionLabel::XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, bool individual)
: label_name(label_info.labelName), debug_utils_label(label_info), is_individual_label(individual) {
// Update the c string pointer to the one we hold.
debug_utils_label.labelName = label_name.c_str();
}
XrSdkSessionLabelPtr XrSdkSessionLabel::make(const XrDebugUtilsLabelEXT& label_info, bool individual) {
XrSdkSessionLabelPtr ret(new XrSdkSessionLabel(label_info, individual));
return ret;
}
void DebugUtilsData::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
object_info_.AddObjectName(object_handle, object_type, object_name);
}
// We always want to remove the old individual label before we do anything else.
// So, do that in it's own method
void DebugUtilsData::RemoveIndividualLabel(XrSdkSessionLabelList& label_vec) {
if (!label_vec.empty() && label_vec.back()->is_individual_label) {
label_vec.pop_back();
}
}
XrSdkSessionLabelList* DebugUtilsData::GetSessionLabelList(XrSession session) {
auto session_label_iterator = session_labels_.find(session);
if (session_label_iterator == session_labels_.end()) {
return nullptr;
}
return session_label_iterator->second.get();
}
XrSdkSessionLabelList& DebugUtilsData::GetOrCreateSessionLabelList(XrSession session) {
XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr == nullptr) {
std::unique_ptr<XrSdkSessionLabelList> vec(new XrSdkSessionLabelList);
vec_ptr = vec.get();
session_labels_[session] = std::move(vec);
}
return *vec_ptr;
}
void DebugUtilsData::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT& label_info) {
auto& vec = GetOrCreateSessionLabelList(session);
// Individual labels do not stay around in the transition into a new label region
RemoveIndividualLabel(vec);
// Start the new label region
vec.emplace_back(XrSdkSessionLabel::make(label_info, false));
}
void DebugUtilsData::EndLabelRegion(XrSession session) {
XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr == nullptr) {
return;
}
// Individual labels do not stay around in the transition out of label region
RemoveIndividualLabel(*vec_ptr);
// Remove the last label region
if (!vec_ptr->empty()) {
vec_ptr->pop_back();
}
}
void DebugUtilsData::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT& label_info) {
auto& vec = GetOrCreateSessionLabelList(session);
// Remove any individual layer that might already be there
RemoveIndividualLabel(vec);
// Insert a new individual label
vec.emplace_back(XrSdkSessionLabel::make(label_info, true));
}
void DebugUtilsData::DeleteObject(uint64_t object_handle, XrObjectType object_type) {
object_info_.RemoveObject(object_handle, object_type);
if (object_type == XR_OBJECT_TYPE_SESSION) {
auto session = TreatIntegerAsHandle<XrSession>(object_handle);
XrSdkSessionLabelList* vec_ptr = GetSessionLabelList(session);
if (vec_ptr != nullptr) {
session_labels_.erase(session);
}
}
}
void DebugUtilsData::DeleteSessionLabels(XrSession session) { session_labels_.erase(session); }
NamesAndLabels DebugUtilsData::PopulateNamesAndLabels(std::vector<XrSdkLogObjectInfo> objects) const {
std::vector<XrDebugUtilsLabelEXT> labels;
for (auto& obj : objects) {
// Check for any names that have been associated with the objects and set them up here
object_info_.LookUpObjectName(obj);
// If this is a session, see if there are any labels associated with it for us to add
// to the callback content.
if (XR_OBJECT_TYPE_SESSION == obj.type) {
LookUpSessionLabels(obj.GetTypedHandle<XrSession>(), labels);
}
}
return {objects, labels};
}
void DebugUtilsData::WrapCallbackData(AugmentedCallbackData* aug_data,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) const {
// If there's nothing to add, just return the original data as the augmented copy
aug_data->exported_data = callback_data;
if (object_info_.Empty() || callback_data->objectCount == 0) {
return;
}
// Inspect each of the callback objects
bool name_found = false;
for (uint32_t obj = 0; obj < callback_data->objectCount; ++obj) {
auto& current_obj = callback_data->objects[obj];
name_found |= (nullptr != object_info_.LookUpStoredObjectInfo(current_obj.objectHandle, current_obj.objectType));
// If this is a session, record any labels associated with it
if (XR_OBJECT_TYPE_SESSION == current_obj.objectType) {
XrSession session = TreatIntegerAsHandle<XrSession>(current_obj.objectHandle);
LookUpSessionLabels(session, aug_data->labels);
}
}
// If we found nothing to add, return the original data
if (!name_found && aug_data->labels.empty()) {
return;
}
// Found additional data - modify an internal copy and return that as the exported data
memcpy(&aug_data->modified_data, callback_data, sizeof(XrDebugUtilsMessengerCallbackDataEXT));
aug_data->new_objects.assign(callback_data->objects, callback_data->objects + callback_data->objectCount);
// Record (overwrite) the names of all incoming objects provided in our internal list
for (auto& obj : aug_data->new_objects) {
object_info_.LookUpObjectName(obj);
}
// Update local copy & point export to it
aug_data->modified_data.objects = aug_data->new_objects.data();
aug_data->modified_data.sessionLabelCount = static_cast<uint32_t>(aug_data->labels.size());
aug_data->modified_data.sessionLabels = aug_data->labels.empty() ? nullptr : aug_data->labels.data();
aug_data->exported_data = &aug_data->modified_data;
return;
}

View File

@ -0,0 +1,229 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// Copyright (c) 2019 Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>, Ryan Pavlik <ryan.pavlik@collabora.com
//
/*!
* @file
*
* The core of an XR_EXT_debug_utils implementation, used/shared by the loader and several SDK layers.
*/
#pragma once
#include "hex_and_handles.h"
#include <openxr/openxr.h>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
struct XrSdkGenericObject {
//! Type-erased handle value
uint64_t handle;
//! Kind of object this handle refers to
XrObjectType type;
/// Un-erase the type of the handle and get it properly typed again.
///
/// Note: Does not check the type before doing it!
template <typename HandleType>
HandleType& GetTypedHandle() {
return TreatIntegerAsHandle<HandleType&>(handle);
}
//! @overload
template <typename HandleType>
HandleType const& GetTypedHandle() const {
return TreatIntegerAsHandle<HandleType&>(handle);
}
//! Create from a typed handle and object type
template <typename T>
XrSdkGenericObject(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
//! Create from an untyped handle value (integer) and object type
XrSdkGenericObject(uint64_t h, XrObjectType t) : handle(h), type(t) {}
};
struct XrSdkLogObjectInfo {
//! Type-erased handle value
uint64_t handle;
//! Kind of object this handle refers to
XrObjectType type;
//! To be assigned by the application - not part of this object's identity
std::string name;
/// Un-erase the type of the handle and get it properly typed again.
///
/// Note: Does not check the type before doing it!
template <typename HandleType>
HandleType& GetTypedHandle() {
return TreatIntegerAsHandle<HandleType&>(handle);
}
//! @overload
template <typename HandleType>
HandleType const& GetTypedHandle() const {
return TreatIntegerAsHandle<HandleType&>(handle);
}
XrSdkLogObjectInfo() = default;
//! Create from a typed handle and object type
template <typename T>
XrSdkLogObjectInfo(T h, XrObjectType t) : handle(MakeHandleGeneric(h)), type(t) {}
//! Create from an untyped handle value (integer) and object type
XrSdkLogObjectInfo(uint64_t h, XrObjectType t) : handle(h), type(t) {}
//! Create from an untyped handle value (integer), object type, and name
XrSdkLogObjectInfo(uint64_t h, XrObjectType t, const char* n) : handle(h), type(t), name(n == nullptr ? "" : n) {}
std::string ToString() const;
};
//! True if the two object infos have the same handle value and handle type
static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrSdkLogObjectInfo const& b) {
return a.handle == b.handle && a.type == b.type;
}
//! @overload
static inline bool Equivalent(XrDebugUtilsObjectNameInfoEXT const& a, XrSdkLogObjectInfo const& b) {
return a.objectHandle == b.handle && a.objectType == b.type;
}
//! @overload
static inline bool Equivalent(XrSdkLogObjectInfo const& a, XrDebugUtilsObjectNameInfoEXT const& b) { return Equivalent(b, a); }
/// Object info registered with calls to xrSetDebugUtilsObjectNameEXT
class ObjectInfoCollection {
public:
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
void RemoveObject(uint64_t object_handle, XrObjectType object_type);
//! Find the stored object info, if any, matching handle and type.
//! Return nullptr if not found.
XrSdkLogObjectInfo const* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info) const;
//! Find the stored object info, if any, matching handle and type.
//! Return nullptr if not found.
XrSdkLogObjectInfo* LookUpStoredObjectInfo(XrSdkLogObjectInfo const& info);
//! Find the stored object info, if any.
//! Return nullptr if not found.
XrSdkLogObjectInfo const* LookUpStoredObjectInfo(uint64_t handle, XrObjectType type) const {
return LookUpStoredObjectInfo({handle, type});
}
//! Find the object name, if any, and update debug utils info accordingly.
//! Return true if found and updated.
bool LookUpObjectName(XrDebugUtilsObjectNameInfoEXT& info) const;
//! Find the object name, if any, and update logging info accordingly.
//! Return true if found and updated.
bool LookUpObjectName(XrSdkLogObjectInfo& info) const;
//! Is the collection empty?
bool Empty() const { return object_info_.empty(); }
private:
// Object names that have been set for given objects
std::vector<XrSdkLogObjectInfo> object_info_;
};
struct XrSdkSessionLabel;
using XrSdkSessionLabelPtr = std::unique_ptr<XrSdkSessionLabel>;
using XrSdkSessionLabelList = std::vector<XrSdkSessionLabelPtr>;
struct XrSdkSessionLabel {
static XrSdkSessionLabelPtr make(const XrDebugUtilsLabelEXT& label_info, bool individual);
std::string label_name;
XrDebugUtilsLabelEXT debug_utils_label;
bool is_individual_label;
private:
XrSdkSessionLabel(const XrDebugUtilsLabelEXT& label_info, bool individual);
};
/// The metadata for a collection of objects. Must persist unmodified during the entire debug messenger call!
struct NamesAndLabels {
NamesAndLabels() = default;
NamesAndLabels(std::vector<XrSdkLogObjectInfo> obj, std::vector<XrDebugUtilsLabelEXT> lab);
/// C++ structure owning the data (strings) backing the objects vector.
std::vector<XrSdkLogObjectInfo> sdk_objects;
std::vector<XrDebugUtilsObjectNameInfoEXT> objects;
std::vector<XrDebugUtilsLabelEXT> labels;
/// Populate the debug utils callback data structure.
void PopulateCallbackData(XrDebugUtilsMessengerCallbackDataEXT& data) const;
// XrDebugUtilsMessengerCallbackDataEXT MakeCallbackData() const;
};
struct AugmentedCallbackData {
std::vector<XrDebugUtilsLabelEXT> labels;
std::vector<XrDebugUtilsObjectNameInfoEXT> new_objects;
XrDebugUtilsMessengerCallbackDataEXT modified_data;
const XrDebugUtilsMessengerCallbackDataEXT* exported_data;
};
/// Tracks all the data (handle names and session labels) required to fully augment XR_EXT_debug_utils-related calls.
class DebugUtilsData {
public:
DebugUtilsData() = default;
DebugUtilsData(const DebugUtilsData&) = delete;
DebugUtilsData& operator=(const DebugUtilsData&) = delete;
bool Empty() const { return object_info_.Empty() && session_labels_.empty(); }
//! Core of implementation for xrSetDebugUtilsObjectNameEXT
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
/// Core of implementation for xrSessionBeginDebugUtilsLabelRegionEXT
void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT& label_info);
/// Core of implementation for xrSessionEndDebugUtilsLabelRegionEXT
void EndLabelRegion(XrSession session);
/// Core of implementation for xrSessionInsertDebugUtilsLabelEXT
void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT& label_info);
/// Removes all labels associated with a session - call in xrDestroySession and xrDestroyInstance (for all child sessions)
void DeleteSessionLabels(XrSession session);
/// Retrieve labels for the given session, if any, and push them in reverse order on the vector.
void LookUpSessionLabels(XrSession session, std::vector<XrDebugUtilsLabelEXT>& labels) const;
/// Removes all data related to this object - including session labels if it's a session.
///
/// Does not take care of handling child objects - you must do this yourself.
void DeleteObject(uint64_t object_handle, XrObjectType object_type);
/// Given the collection of objects, populate their names and list of labels
NamesAndLabels PopulateNamesAndLabels(std::vector<XrSdkLogObjectInfo> objects) const;
void WrapCallbackData(AugmentedCallbackData* aug_data,
const XrDebugUtilsMessengerCallbackDataEXT* provided_callback_data) const;
private:
void RemoveIndividualLabel(XrSdkSessionLabelList& label_vec);
XrSdkSessionLabelList* GetSessionLabelList(XrSession session);
XrSdkSessionLabelList& GetOrCreateSessionLabelList(XrSession session);
// Session labels: one vector of them per session.
std::unordered_map<XrSession, std::unique_ptr<XrSdkSessionLabelList>> session_labels_;
// Names for objects.
ObjectInfoCollection object_info_;
};

View File

@ -0,0 +1,345 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
//
#pragma once
#include "xr_dependencies.h"
#include <string>
#include <stdlib.h>
// OpenXR paths and registry key locations
#define OPENXR_RELATIVE_PATH "openxr/"
#define OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/implicit.d"
#define OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH "/api_layers/explicit.d"
#ifdef XR_OS_WINDOWS
#define OPENXR_REGISTRY_LOCATION "SOFTWARE\\Khronos\\OpenXR\\"
#define OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Implicit"
#define OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION "\\ApiLayers\\Explicit"
#endif
// OpenXR Loader environment variables of interest
#define OPENXR_RUNTIME_JSON_ENV_VAR "XR_RUNTIME_JSON"
#define OPENXR_API_LAYER_PATH_ENV_VAR "XR_API_LAYER_PATH"
// This is a CMake generated file with #defines for any functions/includes
// that it found present and build-time configuration.
// If you don't have this file, on non-Windows you'll need to define
// one of HAVE_SECURE_GETENV or HAVE___SECURE_GETENV depending on which
// of secure_getenv or __secure_getenv are present
#ifdef OPENXR_HAVE_COMMON_CONFIG
#include "common_config.h"
#endif // OPENXR_HAVE_COMMON_CONFIG
// Environment variables
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE)
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
namespace detail {
static inline char* ImplGetEnv(const char* name) { return getenv(name); }
static inline int ImplSetEnv(const char* name, const char* value, int overwrite) { return setenv(name, value, overwrite); }
static inline char* ImplGetSecureEnv(const char* name) {
#ifdef HAVE_SECURE_GETENV
return secure_getenv(name);
#elif defined(HAVE___SECURE_GETENV)
return __secure_getenv(name);
#else
#pragma message( \
"Warning: Falling back to non-secure getenv for environmental" \
"lookups! Consider updating to a different libc.")
return ImplGetEnv(name);
#endif
}
} // namespace detail
#endif // defined(XR_OS_LINUX) || defined(XR_OS_APPLE)
#if defined(XR_OS_LINUX)
static inline std::string PlatformUtilsGetEnv(const char* name) {
auto str = detail::ImplGetEnv(name);
if (str == nullptr) {
return {};
}
return str;
}
static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
auto str = detail::ImplGetSecureEnv(name);
if (str == nullptr) {
return {};
}
return str;
}
static inline bool PlatformUtilsGetEnvSet(const char* name) { return detail::ImplGetEnv(name) != nullptr; }
static inline bool PlatformUtilsSetEnv(const char* name, const char* value) {
const int shouldOverwrite = 1;
int result = detail::ImplSetEnv(name, value, shouldOverwrite);
return (result == 0);
}
#elif defined(XR_OS_APPLE)
static inline std::string PlatformUtilsGetEnv(const char* name) {
auto str = detail::ImplGetEnv(name);
if (str == nullptr) {
return {};
}
return str;
}
static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
auto str = detail::ImplGetSecureEnv(name);
if (str == nullptr) {
return {};
}
return str;
}
static inline bool PlatformUtilsGetEnvSet(const char* name) { return detail::ImplGetEnv(name) != nullptr; }
static inline bool PlatformUtilsSetEnv(const char* name, const char* value) {
const int shouldOverwrite = 1;
int result = detail::ImplSetEnv(name, value, shouldOverwrite);
return (result == 0);
}
// Prefix for the Apple global runtime JSON file name
static const std::string rt_dir_prefix = "/usr/local/share/openxr/";
static const std::string rt_filename = "/active_runtime.json";
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) {
file_name = rt_dir_prefix;
file_name += std::to_string(major_version);
file_name += rt_filename;
return true;
}
#elif defined(XR_OS_WINDOWS)
#if !defined(NDEBUG)
inline void LogError(const std::string& error) { OutputDebugStringA(error.c_str()); }
#else
#define LogError(x)
#endif
inline std::wstring utf8_to_wide(const std::string& utf8Text) {
if (utf8Text.empty()) {
return {};
}
std::wstring wideText;
const int wideLength = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), nullptr, 0);
if (wideLength == 0) {
LogError("utf8_to_wide get size error: " + std::to_string(::GetLastError()));
return {};
}
// MultiByteToWideChar returns number of chars of the input buffer, regardless of null terminitor
wideText.resize(wideLength, 0);
wchar_t* wideString = const_cast<wchar_t*>(wideText.data()); // mutable data() only exists in c++17
const int length = ::MultiByteToWideChar(CP_UTF8, 0, utf8Text.data(), (int)utf8Text.size(), wideString, wideLength);
if (length != wideLength) {
LogError("utf8_to_wide convert string error: " + std::to_string(::GetLastError()));
return {};
}
return wideText;
}
inline std::string wide_to_utf8(const std::wstring& wideText) {
if (wideText.empty()) {
return {};
}
std::string narrowText;
int narrowLength = ::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), nullptr, 0, nullptr, nullptr);
if (narrowLength == 0) {
LogError("wide_to_utf8 get size error: " + std::to_string(::GetLastError()));
return {};
}
// WideCharToMultiByte returns number of chars of the input buffer, regardless of null terminitor
narrowText.resize(narrowLength, 0);
char* narrowString = const_cast<char*>(narrowText.data()); // mutable data() only exists in c++17
const int length =
::WideCharToMultiByte(CP_UTF8, 0, wideText.data(), (int)wideText.size(), narrowString, narrowLength, nullptr, nullptr);
if (length != narrowLength) {
LogError("wide_to_utf8 convert string error: " + std::to_string(::GetLastError()));
return {};
}
return narrowText;
}
// Returns true if the current process has an integrity level > SECURITY_MANDATORY_MEDIUM_RID.
static inline bool IsHighIntegrityLevel() {
// Execute this check once and save the value as a static bool.
static bool isHighIntegrityLevel = ([] {
HANDLE processToken;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_QUERY_SOURCE, &processToken)) {
// Maximum possible size of SID_AND_ATTRIBUTES is maximum size of a SID + size of attributes DWORD.
uint8_t mandatoryLabelBuffer[SECURITY_MAX_SID_SIZE + sizeof(DWORD)]{};
DWORD bufferSize;
if (GetTokenInformation(processToken, TokenIntegrityLevel, mandatoryLabelBuffer, sizeof(mandatoryLabelBuffer),
&bufferSize) != 0) {
const auto mandatoryLabel = reinterpret_cast<const TOKEN_MANDATORY_LABEL*>(mandatoryLabelBuffer);
if (mandatoryLabel->Label.Sid != 0) {
const DWORD subAuthorityCount = *GetSidSubAuthorityCount(mandatoryLabel->Label.Sid);
const DWORD integrityLevel = *GetSidSubAuthority(mandatoryLabel->Label.Sid, subAuthorityCount - 1);
CloseHandle(processToken);
return integrityLevel > SECURITY_MANDATORY_MEDIUM_RID;
}
}
CloseHandle(processToken);
}
return false;
})();
return isHighIntegrityLevel;
}
// Returns true if the given environment variable exists.
// The name is a case-sensitive UTF8 string.
static inline bool PlatformUtilsGetEnvSet(const char* name) {
const std::wstring wname = utf8_to_wide(name);
const DWORD valSize = ::GetEnvironmentVariableW(wname.c_str(), nullptr, 0);
// GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error.
return 0 != valSize;
}
// Returns the environment variable value for the given name.
// Returns an empty string if the environment variable doesn't exist or if it exists but is empty.
// Use PlatformUtilsGetEnvSet to tell if it exists.
// The name is a case-sensitive UTF8 string.
static inline std::string PlatformUtilsGetEnv(const char* name) {
const std::wstring wname = utf8_to_wide(name);
const DWORD valSize = ::GetEnvironmentVariableW(wname.c_str(), nullptr, 0);
// GetEnvironmentVariable returns 0 when environment variable does not exist or there is an error.
// The size includes the null-terminator, so a size of 1 is means the variable was explicitly set to empty.
if (valSize == 0 || valSize == 1) {
return {};
}
// GetEnvironmentVariable returns size including null terminator for "query size" call.
std::wstring wValue(valSize, 0);
wchar_t* wValueData = &wValue[0];
// GetEnvironmentVariable returns string length, excluding null terminator for "get value"
// call if there was enough capacity. Else it returns the required capacity (including null terminator).
const DWORD length = ::GetEnvironmentVariableW(wname.c_str(), wValueData, (DWORD)wValue.size());
if ((length == 0) || (length >= wValue.size())) { // If error or the variable increased length between calls...
LogError("GetEnvironmentVariable get value error: " + std::to_string(::GetLastError()));
return {};
}
wValue.resize(length); // Strip the null terminator.
return wide_to_utf8(wValue);
}
// Acts the same as PlatformUtilsGetEnv except returns an empty string if IsHighIntegrityLevel.
static inline std::string PlatformUtilsGetSecureEnv(const char* name) {
// Do not allow high integrity processes to act on data that can be controlled by medium integrity processes.
if (IsHighIntegrityLevel()) {
return {};
}
// No secure version for Windows so the above integrity check is needed.
return PlatformUtilsGetEnv(name);
}
// Sets an environment variable via UTF8 strings.
// The name is case-sensitive.
// Overwrites the variable if it already exists.
// Returns true if it could be set.
static inline bool PlatformUtilsSetEnv(const char* name, const char* value) {
const std::wstring wname = utf8_to_wide(name);
const std::wstring wvalue = utf8_to_wide(value);
BOOL result = ::SetEnvironmentVariableW(wname.c_str(), wvalue.c_str());
return (result != 0);
}
#elif defined(XR_OS_ANDROID)
static inline bool PlatformUtilsGetEnvSet(const char* /* name */) {
// Stub func
return false;
}
static inline std::string PlatformUtilsGetEnv(const char* /* name */) {
// Stub func
return {};
}
static inline std::string PlatformUtilsGetSecureEnv(const char* /* name */) {
// Stub func
return {};
}
static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* value */) {
// Stub func
return false;
}
#include <sys/stat.h>
// Intended to be only used as a fallback on Android, with a more open, "native" technique used in most cases
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t major_version, std::string& file_name) {
// Prefix for the runtime JSON file name
static const char* rt_dir_prefixes[] = {"/oem", "/vendor", "/system"};
static const std::string rt_filename = "/active_runtime.json";
static const std::string subdir = "/etc/openxr/";
for (const auto prefix : rt_dir_prefixes) {
auto path = prefix + subdir + std::to_string(major_version) + rt_filename;
struct stat buf;
if (0 == stat(path.c_str(), &buf)) {
file_name = path;
return true;
}
}
return false;
}
#else // Not Linux, Apple, nor Windows
static inline bool PlatformUtilsGetEnvSet(const char* /* name */) {
// Stub func
return false;
}
static inline std::string PlatformUtilsGetEnv(const char* /* name */) {
// Stub func
return {};
}
static inline std::string PlatformUtilsGetSecureEnv(const char* /* name */) {
// Stub func
return {};
}
static inline bool PlatformUtilsSetEnv(const char* /* name */, const char* /* value */) {
// Stub func
return false;
}
static inline bool PlatformGetGlobalRuntimeFileName(uint16_t /* major_version */, std::string const& /* file_name */) {
// Stub func
return false;
}
#endif

View File

@ -0,0 +1,45 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
#ifndef _STDFS_CONDITIONS_H
#define _STDFS_CONDITIONS_H
// If the C++ macro is set to the version containing C++17, it must support
// the final C++17 package
#if __cplusplus >= 201703L
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#elif defined(_MSC_VER) && _MSC_VER >= 1900
#if defined(_HAS_CXX17) && _HAS_CXX17
// When MSC supports c++17 use <filesystem> package.
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#endif // !_HAS_CXX17
// GCC supports the experimental filesystem items starting in GCC 6
#elif (__GNUC__ >= 6)
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
// If Clang, check for feature support
#elif defined(__clang__) && (__cpp_lib_filesystem || __cpp_lib_experimental_filesystem)
#if __cpp_lib_filesystem
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 1
#else
#define USE_EXPERIMENTAL_FS 1
#define USE_FINAL_FS 0
#endif
// If all above fails, fall back to standard C++ and OS-specific items
#else
#define USE_EXPERIMENTAL_FS 0
#define USE_FINAL_FS 0
#endif
#endif // !_STDFS_CONDITIONS_H

View File

@ -0,0 +1,89 @@
// Copyright (c) 2018-2022, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// This file includes headers with types which openxr.h depends on in order
// to compile when platforms, graphics apis, and the like are enabled.
#pragma once
#ifdef XR_USE_PLATFORM_ANDROID
#include <android/native_window.h>
#include <android/window.h>
#include <android/native_window_jni.h>
#endif // XR_USE_PLATFORM_ANDROID
#ifdef XR_USE_PLATFORM_WIN32
#include <winapifamily.h>
#if !(WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM))
// Enable desktop partition APIs, such as RegOpenKeyEx, LoadLibraryEx, PathFileExists etc.
#undef WINAPI_PARTITION_DESKTOP
#define WINAPI_PARTITION_DESKTOP 1
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif // !NOMINMAX
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif // !WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <unknwn.h>
#endif // XR_USE_PLATFORM_WIN32
#ifdef XR_USE_GRAPHICS_API_D3D11
#include <d3d11.h>
#endif // XR_USE_GRAPHICS_API_D3D11
#ifdef XR_USE_GRAPHICS_API_D3D12
#include <d3d12.h>
#endif // XR_USE_GRAPHICS_API_D3D12
#ifdef XR_USE_PLATFORM_XLIB
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef Success
#undef Success
#endif // Success
#ifdef Always
#undef Always
#endif // Always
#ifdef None
#undef None
#endif // None
#endif // XR_USE_PLATFORM_XLIB
#ifdef XR_USE_PLATFORM_XCB
#include <xcb/xcb.h>
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_GRAPHICS_API_OPENGL
#if defined(XR_USE_PLATFORM_XLIB) || defined(XR_USE_PLATFORM_XCB)
#include <GL/glx.h>
#endif // (XR_USE_PLATFORM_XLIB || XR_USE_PLATFORM_XCB)
#ifdef XR_USE_PLATFORM_XCB
#include <xcb/glx.h>
#endif // XR_USE_PLATFORM_XCB
#ifdef XR_USE_PLATFORM_MACOS
#include <CL/cl_gl_ext.h>
#endif // XR_USE_PLATFORM_MACOS
#endif // XR_USE_GRAPHICS_API_OPENGL
#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
#include <EGL/egl.h>
#endif // XR_USE_GRAPHICS_API_OPENGL_ES
#ifdef XR_USE_GRAPHICS_API_VULKAN
#include <vulkan/vulkan.h>
#endif // XR_USE_GRAPHICS_API_VULKAN
#ifdef XR_USE_PLATFORM_WAYLAND
#include "wayland-client.h"
#endif // XR_USE_PLATFORM_WAYLAND

787
thirdparty/openxr/src/common/xr_linear.h vendored Normal file
View File

@ -0,0 +1,787 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2016 Oculus VR, LLC.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: J.M.P. van Waveren
//
#ifndef XR_LINEAR_H_
#define XR_LINEAR_H_
#if defined(OS_LINUX_XCB) || defined(OS_LINUX_XCB_GLX) || defined(OS_LINUX_WAYLAND)
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#include <openxr/openxr.h>
/*
================================================================================================
Description : Vector, matrix and quaternion math.
Author : J.M.P. van Waveren
Date : 12/10/2016
Language : C99
Format : Indent 4 spaces - no tabs.
Copyright : Copyright (c) 2016 Oculus VR, LLC. All Rights reserved.
DESCRIPTION
===========
All matrices are column-major.
INTERFACE
=========
XrVector2f
XrVector3f
XrVector4f
XrQuaternionf
XrMatrix4x4f
inline static void XrVector3f_Set(XrVector3f* v, const float value);
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b);
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value);
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction);
inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor);
inline static void XrVector3f_Normalize(XrVector3f* v);
inline static float XrVector3f_Length(const XrVector3f* v);
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction);
inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b;
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result);
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ);
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z);
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale);
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, const float tanAngleLeft, const float tanAngleRight,
const float tanAngleUp, float const tanAngleDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, const float fovDegreesLeft, const float fovDegreesRight,
const float fovDegreeUp, const float fovDegreesDown, const float nearZ,
const float farZ);
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* src);
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs);
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon);
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon);
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b);
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src);
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v);
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v);
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs);
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs);
================================================================================================
*/
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#define MATH_PI 3.14159265358979323846f
#define DEFAULT_NEAR_Z 0.015625f // exact floating point representation
#define INFINITE_FAR_Z 0.0f
static const XrColor4f XrColorRed = {1.0f, 0.0f, 0.0f, 1.0f};
static const XrColor4f XrColorGreen = {0.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorBlue = {0.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorYellow = {1.0f, 1.0f, 0.0f, 1.0f};
static const XrColor4f XrColorPurple = {1.0f, 0.0f, 1.0f, 1.0f};
static const XrColor4f XrColorCyan = {0.0f, 1.0f, 1.0f, 1.0f};
static const XrColor4f XrColorLightGrey = {0.7f, 0.7f, 0.7f, 1.0f};
static const XrColor4f XrColorDarkGrey = {0.3f, 0.3f, 0.3f, 1.0f};
enum GraphicsAPI { GRAPHICS_VULKAN, GRAPHICS_OPENGL, GRAPHICS_OPENGL_ES, GRAPHICS_D3D };
// Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience.
struct XrMatrix4x4f {
float m[16];
};
inline static float XrRcpSqrt(const float x) {
const float SMALLEST_NON_DENORMAL = 1.1754943508222875e-038f; // ( 1U << 23 )
const float rcp = (x >= SMALLEST_NON_DENORMAL) ? 1.0f / sqrtf(x) : 1.0f;
return rcp;
}
inline static void XrVector3f_Set(XrVector3f* v, const float value) {
v->x = value;
v->y = value;
v->z = value;
}
inline static void XrVector3f_Add(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x + b->x;
result->y = a->y + b->y;
result->z = a->z + b->z;
}
inline static void XrVector3f_Sub(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->x - b->x;
result->y = a->y - b->y;
result->z = a->z - b->z;
}
inline static void XrVector3f_Min(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x < b->x) ? a->x : b->x;
result->y = (a->y < b->y) ? a->y : b->y;
result->z = (a->z < b->z) ? a->z : b->z;
}
inline static void XrVector3f_Max(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = (a->x > b->x) ? a->x : b->x;
result->y = (a->y > b->y) ? a->y : b->y;
result->z = (a->z > b->z) ? a->z : b->z;
}
inline static void XrVector3f_Decay(XrVector3f* result, const XrVector3f* a, const float value) {
result->x = (fabsf(a->x) > value) ? ((a->x > 0.0f) ? (a->x - value) : (a->x + value)) : 0.0f;
result->y = (fabsf(a->y) > value) ? ((a->y > 0.0f) ? (a->y - value) : (a->y + value)) : 0.0f;
result->z = (fabsf(a->z) > value) ? ((a->z > 0.0f) ? (a->z - value) : (a->z + value)) : 0.0f;
}
inline static void XrVector3f_Lerp(XrVector3f* result, const XrVector3f* a, const XrVector3f* b, const float fraction) {
result->x = a->x + fraction * (b->x - a->x);
result->y = a->y + fraction * (b->y - a->y);
result->z = a->z + fraction * (b->z - a->z);
}
inline static void XrVector3f_Scale(XrVector3f* result, const XrVector3f* a, const float scaleFactor) {
result->x = a->x * scaleFactor;
result->y = a->y * scaleFactor;
result->z = a->z * scaleFactor;
}
inline static float XrVector3f_Dot(const XrVector3f* a, const XrVector3f* b) { return a->x * b->x + a->y * b->y + a->z * b->z; }
// Compute cross product, which generates a normal vector.
// Direction vector can be determined by right-hand rule: Pointing index finder in
// direction a and middle finger in direction b, thumb will point in Cross(a, b).
inline static void XrVector3f_Cross(XrVector3f* result, const XrVector3f* a, const XrVector3f* b) {
result->x = a->y * b->z - a->z * b->y;
result->y = a->z * b->x - a->x * b->z;
result->z = a->x * b->y - a->y * b->x;
}
inline static void XrVector3f_Normalize(XrVector3f* v) {
const float lengthRcp = XrRcpSqrt(v->x * v->x + v->y * v->y + v->z * v->z);
v->x *= lengthRcp;
v->y *= lengthRcp;
v->z *= lengthRcp;
}
inline static float XrVector3f_Length(const XrVector3f* v) { return sqrtf(v->x * v->x + v->y * v->y + v->z * v->z); }
inline static void XrQuaternionf_CreateFromAxisAngle(XrQuaternionf* result, const XrVector3f* axis, const float angleInRadians) {
float s = sinf(angleInRadians / 2.0f);
float lengthRcp = XrRcpSqrt(axis->x * axis->x + axis->y * axis->y + axis->z * axis->z);
result->x = s * axis->x * lengthRcp;
result->y = s * axis->y * lengthRcp;
result->z = s * axis->z * lengthRcp;
result->w = cosf(angleInRadians / 2.0f);
}
inline static void XrQuaternionf_Lerp(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b, const float fraction) {
const float s = a->x * b->x + a->y * b->y + a->z * b->z + a->w * b->w;
const float fa = 1.0f - fraction;
const float fb = (s < 0.0f) ? -fraction : fraction;
const float x = a->x * fa + b->x * fb;
const float y = a->y * fa + b->y * fb;
const float z = a->z * fa + b->z * fb;
const float w = a->w * fa + b->w * fb;
const float lengthRcp = XrRcpSqrt(x * x + y * y + z * z + w * w);
result->x = x * lengthRcp;
result->y = y * lengthRcp;
result->z = z * lengthRcp;
result->w = w * lengthRcp;
}
inline static void XrQuaternionf_Multiply(XrQuaternionf* result, const XrQuaternionf* a, const XrQuaternionf* b) {
result->x = (b->w * a->x) + (b->x * a->w) + (b->y * a->z) - (b->z * a->y);
result->y = (b->w * a->y) - (b->x * a->z) + (b->y * a->w) + (b->z * a->x);
result->z = (b->w * a->z) + (b->x * a->y) - (b->y * a->x) + (b->z * a->w);
result->w = (b->w * a->w) - (b->x * a->x) - (b->y * a->y) - (b->z * a->z);
}
// Use left-multiplication to accumulate transformations.
inline static void XrMatrix4x4f_Multiply(XrMatrix4x4f* result, const XrMatrix4x4f* a, const XrMatrix4x4f* b) {
result->m[0] = a->m[0] * b->m[0] + a->m[4] * b->m[1] + a->m[8] * b->m[2] + a->m[12] * b->m[3];
result->m[1] = a->m[1] * b->m[0] + a->m[5] * b->m[1] + a->m[9] * b->m[2] + a->m[13] * b->m[3];
result->m[2] = a->m[2] * b->m[0] + a->m[6] * b->m[1] + a->m[10] * b->m[2] + a->m[14] * b->m[3];
result->m[3] = a->m[3] * b->m[0] + a->m[7] * b->m[1] + a->m[11] * b->m[2] + a->m[15] * b->m[3];
result->m[4] = a->m[0] * b->m[4] + a->m[4] * b->m[5] + a->m[8] * b->m[6] + a->m[12] * b->m[7];
result->m[5] = a->m[1] * b->m[4] + a->m[5] * b->m[5] + a->m[9] * b->m[6] + a->m[13] * b->m[7];
result->m[6] = a->m[2] * b->m[4] + a->m[6] * b->m[5] + a->m[10] * b->m[6] + a->m[14] * b->m[7];
result->m[7] = a->m[3] * b->m[4] + a->m[7] * b->m[5] + a->m[11] * b->m[6] + a->m[15] * b->m[7];
result->m[8] = a->m[0] * b->m[8] + a->m[4] * b->m[9] + a->m[8] * b->m[10] + a->m[12] * b->m[11];
result->m[9] = a->m[1] * b->m[8] + a->m[5] * b->m[9] + a->m[9] * b->m[10] + a->m[13] * b->m[11];
result->m[10] = a->m[2] * b->m[8] + a->m[6] * b->m[9] + a->m[10] * b->m[10] + a->m[14] * b->m[11];
result->m[11] = a->m[3] * b->m[8] + a->m[7] * b->m[9] + a->m[11] * b->m[10] + a->m[15] * b->m[11];
result->m[12] = a->m[0] * b->m[12] + a->m[4] * b->m[13] + a->m[8] * b->m[14] + a->m[12] * b->m[15];
result->m[13] = a->m[1] * b->m[12] + a->m[5] * b->m[13] + a->m[9] * b->m[14] + a->m[13] * b->m[15];
result->m[14] = a->m[2] * b->m[12] + a->m[6] * b->m[13] + a->m[10] * b->m[14] + a->m[14] * b->m[15];
result->m[15] = a->m[3] * b->m[12] + a->m[7] * b->m[13] + a->m[11] * b->m[14] + a->m[15] * b->m[15];
}
// Creates the transpose of the given matrix.
inline static void XrMatrix4x4f_Transpose(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = src->m[12];
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = src->m[13];
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = src->m[14];
result->m[12] = src->m[3];
result->m[13] = src->m[7];
result->m[14] = src->m[11];
result->m[15] = src->m[15];
}
// Returns a 3x3 minor of a 4x4 matrix.
inline static float XrMatrix4x4f_Minor(const XrMatrix4x4f* matrix, int r0, int r1, int r2, int c0, int c1, int c2) {
return matrix->m[4 * r0 + c0] *
(matrix->m[4 * r1 + c1] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c1] * matrix->m[4 * r1 + c2]) -
matrix->m[4 * r0 + c1] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c2] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c2]) +
matrix->m[4 * r0 + c2] *
(matrix->m[4 * r1 + c0] * matrix->m[4 * r2 + c1] - matrix->m[4 * r2 + c0] * matrix->m[4 * r1 + c1]);
}
// Calculates the inverse of a 4x4 matrix.
inline static void XrMatrix4x4f_Invert(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
const float rcpDet =
1.0f / (src->m[0] * XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) - src->m[1] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) +
src->m[2] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) - src->m[3] * XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2));
result->m[0] = XrMatrix4x4f_Minor(src, 1, 2, 3, 1, 2, 3) * rcpDet;
result->m[1] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 1, 2, 3) * rcpDet;
result->m[2] = XrMatrix4x4f_Minor(src, 0, 1, 3, 1, 2, 3) * rcpDet;
result->m[3] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 1, 2, 3) * rcpDet;
result->m[4] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 2, 3) * rcpDet;
result->m[5] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 2, 3) * rcpDet;
result->m[6] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 2, 3) * rcpDet;
result->m[7] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 2, 3) * rcpDet;
result->m[8] = XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 3) * rcpDet;
result->m[9] = -XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 3) * rcpDet;
result->m[10] = XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 3) * rcpDet;
result->m[11] = -XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 3) * rcpDet;
result->m[12] = -XrMatrix4x4f_Minor(src, 1, 2, 3, 0, 1, 2) * rcpDet;
result->m[13] = XrMatrix4x4f_Minor(src, 0, 2, 3, 0, 1, 2) * rcpDet;
result->m[14] = -XrMatrix4x4f_Minor(src, 0, 1, 3, 0, 1, 2) * rcpDet;
result->m[15] = XrMatrix4x4f_Minor(src, 0, 1, 2, 0, 1, 2) * rcpDet;
}
// Calculates the inverse of a rigid body transform.
inline static void XrMatrix4x4f_InvertRigidBody(XrMatrix4x4f* result, const XrMatrix4x4f* src) {
result->m[0] = src->m[0];
result->m[1] = src->m[4];
result->m[2] = src->m[8];
result->m[3] = 0.0f;
result->m[4] = src->m[1];
result->m[5] = src->m[5];
result->m[6] = src->m[9];
result->m[7] = 0.0f;
result->m[8] = src->m[2];
result->m[9] = src->m[6];
result->m[10] = src->m[10];
result->m[11] = 0.0f;
result->m[12] = -(src->m[0] * src->m[12] + src->m[1] * src->m[13] + src->m[2] * src->m[14]);
result->m[13] = -(src->m[4] * src->m[12] + src->m[5] * src->m[13] + src->m[6] * src->m[14]);
result->m[14] = -(src->m[8] * src->m[12] + src->m[9] * src->m[13] + src->m[10] * src->m[14]);
result->m[15] = 1.0f;
}
// Creates an identity matrix.
inline static void XrMatrix4x4f_CreateIdentity(XrMatrix4x4f* result) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a translation matrix.
inline static void XrMatrix4x4f_CreateTranslation(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = 1.0f;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = 1.0f;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = 1.0f;
result->m[11] = 0.0f;
result->m[12] = x;
result->m[13] = y;
result->m[14] = z;
result->m[15] = 1.0f;
}
// Creates a rotation matrix.
// If -Z=forward, +Y=up, +X=right, then degreesX=pitch, degreesY=yaw, degreesZ=roll.
inline static void XrMatrix4x4f_CreateRotation(XrMatrix4x4f* result, const float degreesX, const float degreesY,
const float degreesZ) {
const float sinX = sinf(degreesX * (MATH_PI / 180.0f));
const float cosX = cosf(degreesX * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationX = {{1, 0, 0, 0, 0, cosX, sinX, 0, 0, -sinX, cosX, 0, 0, 0, 0, 1}};
const float sinY = sinf(degreesY * (MATH_PI / 180.0f));
const float cosY = cosf(degreesY * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationY = {{cosY, 0, -sinY, 0, 0, 1, 0, 0, sinY, 0, cosY, 0, 0, 0, 0, 1}};
const float sinZ = sinf(degreesZ * (MATH_PI / 180.0f));
const float cosZ = cosf(degreesZ * (MATH_PI / 180.0f));
const XrMatrix4x4f rotationZ = {{cosZ, sinZ, 0, 0, -sinZ, cosZ, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}};
XrMatrix4x4f rotationXY;
XrMatrix4x4f_Multiply(&rotationXY, &rotationY, &rotationX);
XrMatrix4x4f_Multiply(result, &rotationZ, &rotationXY);
}
// Creates a scale matrix.
inline static void XrMatrix4x4f_CreateScale(XrMatrix4x4f* result, const float x, const float y, const float z) {
result->m[0] = x;
result->m[1] = 0.0f;
result->m[2] = 0.0f;
result->m[3] = 0.0f;
result->m[4] = 0.0f;
result->m[5] = y;
result->m[6] = 0.0f;
result->m[7] = 0.0f;
result->m[8] = 0.0f;
result->m[9] = 0.0f;
result->m[10] = z;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a matrix from a quaternion.
inline static void XrMatrix4x4f_CreateFromQuaternion(XrMatrix4x4f* result, const XrQuaternionf* quat) {
const float x2 = quat->x + quat->x;
const float y2 = quat->y + quat->y;
const float z2 = quat->z + quat->z;
const float xx2 = quat->x * x2;
const float yy2 = quat->y * y2;
const float zz2 = quat->z * z2;
const float yz2 = quat->y * z2;
const float wx2 = quat->w * x2;
const float xy2 = quat->x * y2;
const float wz2 = quat->w * z2;
const float xz2 = quat->x * z2;
const float wy2 = quat->w * y2;
result->m[0] = 1.0f - yy2 - zz2;
result->m[1] = xy2 + wz2;
result->m[2] = xz2 - wy2;
result->m[3] = 0.0f;
result->m[4] = xy2 - wz2;
result->m[5] = 1.0f - xx2 - zz2;
result->m[6] = yz2 + wx2;
result->m[7] = 0.0f;
result->m[8] = xz2 + wy2;
result->m[9] = yz2 - wx2;
result->m[10] = 1.0f - xx2 - yy2;
result->m[11] = 0.0f;
result->m[12] = 0.0f;
result->m[13] = 0.0f;
result->m[14] = 0.0f;
result->m[15] = 1.0f;
}
// Creates a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_CreateTranslationRotationScale(XrMatrix4x4f* result, const XrVector3f* translation,
const XrQuaternionf* rotation, const XrVector3f* scale) {
XrMatrix4x4f scaleMatrix;
XrMatrix4x4f_CreateScale(&scaleMatrix, scale->x, scale->y, scale->z);
XrMatrix4x4f rotationMatrix;
XrMatrix4x4f_CreateFromQuaternion(&rotationMatrix, rotation);
XrMatrix4x4f translationMatrix;
XrMatrix4x4f_CreateTranslation(&translationMatrix, translation->x, translation->y, translation->z);
XrMatrix4x4f combinedMatrix;
XrMatrix4x4f_Multiply(&combinedMatrix, &rotationMatrix, &scaleMatrix);
XrMatrix4x4f_Multiply(result, &translationMatrix, &combinedMatrix);
}
// Creates a projection matrix based on the specified dimensions.
// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API.
// The far plane is placed at infinity if farZ <= nearZ.
// An infinite projection matrix is preferred for rasterization because, except for
// things *right* up against the near plane, it always provides better precision:
// "Tightening the Precision of Perspective Rendering"
// Paul Upchurch, Mathieu Desbrun
// Journal of Graphics Tools, Volume 16, Issue 1, 2012
inline static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const float tanAngleLeft,
const float tanAngleRight, const float tanAngleUp, float const tanAngleDown,
const float nearZ, const float farZ) {
const float tanAngleWidth = tanAngleRight - tanAngleLeft;
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan).
// Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal).
const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
if (farZ <= nearZ) {
// place the far plane at infinity
result->m[0] = 2.0f / tanAngleWidth;
result->m[4] = 0.0f;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0.0f;
result->m[1] = 0.0f;
result->m[5] = 2.0f / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0.0f;
result->m[2] = 0.0f;
result->m[6] = 0.0f;
result->m[10] = -1.0f;
result->m[14] = -(nearZ + offsetZ);
result->m[3] = 0.0f;
result->m[7] = 0.0f;
result->m[11] = -1.0f;
result->m[15] = 0.0f;
} else {
// normal projection
result->m[0] = 2.0f / tanAngleWidth;
result->m[4] = 0.0f;
result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth;
result->m[12] = 0.0f;
result->m[1] = 0.0f;
result->m[5] = 2.0f / tanAngleHeight;
result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight;
result->m[13] = 0.0f;
result->m[2] = 0.0f;
result->m[6] = 0.0f;
result->m[10] = -(farZ + offsetZ) / (farZ - nearZ);
result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ);
result->m[3] = 0.0f;
result->m[7] = 0.0f;
result->m[11] = -1.0f;
result->m[15] = 0.0f;
}
}
// Creates a projection matrix based on the specified FOV.
inline static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f* result, GraphicsAPI graphicsApi, const XrFovf fov,
const float nearZ, const float farZ) {
const float tanLeft = tanf(fov.angleLeft);
const float tanRight = tanf(fov.angleRight);
const float tanDown = tanf(fov.angleDown);
const float tanUp = tanf(fov.angleUp);
XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ);
}
// Creates a matrix that transforms the -1 to 1 cube to cover the given 'mins' and 'maxs' transformed with the given 'matrix'.
inline static void XrMatrix4x4f_CreateOffsetScaleForBounds(XrMatrix4x4f* result, const XrMatrix4x4f* matrix, const XrVector3f* mins,
const XrVector3f* maxs) {
const XrVector3f offset = {(maxs->x + mins->x) * 0.5f, (maxs->y + mins->y) * 0.5f, (maxs->z + mins->z) * 0.5f};
const XrVector3f scale = {(maxs->x - mins->x) * 0.5f, (maxs->y - mins->y) * 0.5f, (maxs->z - mins->z) * 0.5f};
result->m[0] = matrix->m[0] * scale.x;
result->m[1] = matrix->m[1] * scale.x;
result->m[2] = matrix->m[2] * scale.x;
result->m[3] = matrix->m[3] * scale.x;
result->m[4] = matrix->m[4] * scale.y;
result->m[5] = matrix->m[5] * scale.y;
result->m[6] = matrix->m[6] * scale.y;
result->m[7] = matrix->m[7] * scale.y;
result->m[8] = matrix->m[8] * scale.z;
result->m[9] = matrix->m[9] * scale.z;
result->m[10] = matrix->m[10] * scale.z;
result->m[11] = matrix->m[11] * scale.z;
result->m[12] = matrix->m[12] + matrix->m[0] * offset.x + matrix->m[4] * offset.y + matrix->m[8] * offset.z;
result->m[13] = matrix->m[13] + matrix->m[1] * offset.x + matrix->m[5] * offset.y + matrix->m[9] * offset.z;
result->m[14] = matrix->m[14] + matrix->m[2] * offset.x + matrix->m[6] * offset.y + matrix->m[10] * offset.z;
result->m[15] = matrix->m[15] + matrix->m[3] * offset.x + matrix->m[7] * offset.y + matrix->m[11] * offset.z;
}
// Returns true if the given matrix is affine.
inline static bool XrMatrix4x4f_IsAffine(const XrMatrix4x4f* matrix, const float epsilon) {
return fabsf(matrix->m[3]) <= epsilon && fabsf(matrix->m[7]) <= epsilon && fabsf(matrix->m[11]) <= epsilon &&
fabsf(matrix->m[15] - 1.0f) <= epsilon;
}
// Returns true if the given matrix is orthogonal.
inline static bool XrMatrix4x4f_IsOrthogonal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i != j) {
if (fabsf(matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2]) > epsilon) {
return false;
}
if (fabsf(matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j]) > epsilon) {
return false;
}
}
}
}
return true;
}
// Returns true if the given matrix is orthonormal.
inline static bool XrMatrix4x4f_IsOrthonormal(const XrMatrix4x4f* matrix, const float epsilon) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
const float kd = (i == j) ? 1.0f : 0.0f; // Kronecker delta
if (fabsf(kd - (matrix->m[4 * i + 0] * matrix->m[4 * j + 0] + matrix->m[4 * i + 1] * matrix->m[4 * j + 1] +
matrix->m[4 * i + 2] * matrix->m[4 * j + 2])) > epsilon) {
return false;
}
if (fabsf(kd - (matrix->m[4 * 0 + i] * matrix->m[4 * 0 + j] + matrix->m[4 * 1 + i] * matrix->m[4 * 1 + j] +
matrix->m[4 * 2 + i] * matrix->m[4 * 2 + j])) > epsilon) {
return false;
}
}
}
return true;
}
// Returns true if the given matrix is a rigid body transform.
inline static bool XrMatrix4x4f_IsRigidBody(const XrMatrix4x4f* matrix, const float epsilon) {
return XrMatrix4x4f_IsAffine(matrix, epsilon) && XrMatrix4x4f_IsOrthonormal(matrix, epsilon);
}
// Get the translation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetTranslation(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = src->m[12];
result->y = src->m[13];
result->z = src->m[14];
}
// Get the rotation from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetRotation(XrQuaternionf* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
const float rcpScaleX = XrRcpSqrt(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
const float rcpScaleY = XrRcpSqrt(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
const float rcpScaleZ = XrRcpSqrt(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
const float m[9] = {src->m[0] * rcpScaleX, src->m[1] * rcpScaleX, src->m[2] * rcpScaleX,
src->m[4] * rcpScaleY, src->m[5] * rcpScaleY, src->m[6] * rcpScaleY,
src->m[8] * rcpScaleZ, src->m[9] * rcpScaleZ, src->m[10] * rcpScaleZ};
if (m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] > 0.0f) {
float t = +m[0 * 3 + 0] + m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->w = s * t;
result->z = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->y = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->x = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[0 * 3 + 0] > m[1 * 3 + 1] && m[0 * 3 + 0] > m[2 * 3 + 2]) {
float t = +m[0 * 3 + 0] - m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->x = s * t;
result->y = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->z = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->w = (m[1 * 3 + 2] - m[2 * 3 + 1]) * s;
} else if (m[1 * 3 + 1] > m[2 * 3 + 2]) {
float t = -m[0 * 3 + 0] + m[1 * 3 + 1] - m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->y = s * t;
result->x = (m[0 * 3 + 1] + m[1 * 3 + 0]) * s;
result->w = (m[2 * 3 + 0] - m[0 * 3 + 2]) * s;
result->z = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
} else {
float t = -m[0 * 3 + 0] - m[1 * 3 + 1] + m[2 * 3 + 2] + 1.0f;
float s = XrRcpSqrt(t) * 0.5f;
result->z = s * t;
result->w = (m[0 * 3 + 1] - m[1 * 3 + 0]) * s;
result->x = (m[2 * 3 + 0] + m[0 * 3 + 2]) * s;
result->y = (m[1 * 3 + 2] + m[2 * 3 + 1]) * s;
}
}
// Get the scale from a combined translation(rotation(scale(object))) matrix.
inline static void XrMatrix4x4f_GetScale(XrVector3f* result, const XrMatrix4x4f* src) {
assert(XrMatrix4x4f_IsAffine(src, 1e-4f));
assert(XrMatrix4x4f_IsOrthogonal(src, 1e-4f));
result->x = sqrtf(src->m[0] * src->m[0] + src->m[1] * src->m[1] + src->m[2] * src->m[2]);
result->y = sqrtf(src->m[4] * src->m[4] + src->m[5] * src->m[5] + src->m[6] * src->m[6]);
result->z = sqrtf(src->m[8] * src->m[8] + src->m[9] * src->m[9] + src->m[10] * src->m[10]);
}
// Transforms a 3D vector.
inline static void XrMatrix4x4f_TransformVector3f(XrVector3f* result, const XrMatrix4x4f* m, const XrVector3f* v) {
const float w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15];
const float rcpW = 1.0f / w;
result->x = (m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12]) * rcpW;
result->y = (m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13]) * rcpW;
result->z = (m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14]) * rcpW;
}
// Transforms a 4D vector.
inline static void XrMatrix4x4f_TransformVector4f(XrVector4f* result, const XrMatrix4x4f* m, const XrVector4f* v) {
result->x = m->m[0] * v->x + m->m[4] * v->y + m->m[8] * v->z + m->m[12] * v->w;
result->y = m->m[1] * v->x + m->m[5] * v->y + m->m[9] * v->z + m->m[13] * v->w;
result->z = m->m[2] * v->x + m->m[6] * v->y + m->m[10] * v->z + m->m[14] * v->w;
result->w = m->m[3] * v->x + m->m[7] * v->y + m->m[11] * v->z + m->m[15] * v->w;
}
// Transforms the 'mins' and 'maxs' bounds with the given 'matrix'.
inline static void XrMatrix4x4f_TransformBounds(XrVector3f* resultMins, XrVector3f* resultMaxs, const XrMatrix4x4f* matrix,
const XrVector3f* mins, const XrVector3f* maxs) {
assert(XrMatrix4x4f_IsAffine(matrix, 1e-4f));
const XrVector3f center = {(mins->x + maxs->x) * 0.5f, (mins->y + maxs->y) * 0.5f, (mins->z + maxs->z) * 0.5f};
const XrVector3f extents = {maxs->x - center.x, maxs->y - center.y, maxs->z - center.z};
const XrVector3f newCenter = {matrix->m[0] * center.x + matrix->m[4] * center.y + matrix->m[8] * center.z + matrix->m[12],
matrix->m[1] * center.x + matrix->m[5] * center.y + matrix->m[9] * center.z + matrix->m[13],
matrix->m[2] * center.x + matrix->m[6] * center.y + matrix->m[10] * center.z + matrix->m[14]};
const XrVector3f newExtents = {
fabsf(extents.x * matrix->m[0]) + fabsf(extents.y * matrix->m[4]) + fabsf(extents.z * matrix->m[8]),
fabsf(extents.x * matrix->m[1]) + fabsf(extents.y * matrix->m[5]) + fabsf(extents.z * matrix->m[9]),
fabsf(extents.x * matrix->m[2]) + fabsf(extents.y * matrix->m[6]) + fabsf(extents.z * matrix->m[10])};
XrVector3f_Sub(resultMins, &newCenter, &newExtents);
XrVector3f_Add(resultMaxs, &newCenter, &newExtents);
}
// Returns true if the 'mins' and 'maxs' bounds is completely off to one side of the projection matrix.
inline static bool XrMatrix4x4f_CullBounds(const XrMatrix4x4f* mvp, const XrVector3f* mins, const XrVector3f* maxs) {
if (maxs->x <= mins->x && maxs->y <= mins->y && maxs->z <= mins->z) {
return false;
}
XrVector4f c[8];
for (int i = 0; i < 8; i++) {
const XrVector4f corner = {(i & 1) != 0 ? maxs->x : mins->x, (i & 2) != 0 ? maxs->y : mins->y,
(i & 4) != 0 ? maxs->z : mins->z, 1.0f};
XrMatrix4x4f_TransformVector4f(&c[i], mvp, &corner);
}
int i;
for (i = 0; i < 8; i++) {
if (c[i].x > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].x < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].y < c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z > -c[i].w) {
break;
}
}
if (i == 8) {
return true;
}
for (i = 0; i < 8; i++) {
if (c[i].z < c[i].w) {
break;
}
}
return i == 8;
}
#endif // XR_LINEAR_H_

View File

@ -0,0 +1,115 @@
Baptiste Lepilleur <blep@users.sourceforge.net>
Aaron Jacobs <aaronjjacobs@gmail.com>
Aaron Jacobs <jacobsa@google.com>
Adam Boseley <ABoseley@agjunction.com>
Adam Boseley <adam.boseley@gmail.com>
Aleksandr Derbenev <13alexac@gmail.com>
Alexander Gazarov <DrMetallius@users.noreply.github.com>
Alexander V. Brezgin <abrezgin@appliedtech.ru>
Alexandr Brezgin <albrezgin@mail.ru>
Alexey Kruchinin <alexey@mopals.com>
Anton Indrawan <anton.indrawan@gmail.com>
Baptiste Jonglez <git@bitsofnetworks.org>
Baptiste Lepilleur <baptiste.lepilleur@gmail.com>
Baruch Siach <baruch@tkos.co.il>
Ben Boeckel <mathstuf@gmail.com>
Benjamin Knecht <bknecht@logitech.com>
Bernd Kuhls <bernd.kuhls@t-online.de>
Billy Donahue <billydonahue@google.com>
Braden McDorman <bmcdorman@gmail.com>
Brandon Myers <bmyers1788@gmail.com>
Brendan Drew <brendan.drew@daqri.com>
chason <cxchao802@gmail.com>
chenguoping <chenguopingdota@163.com>
Chris Gilling <cgilling@iparadigms.com>
Christopher Dawes <christopher.dawes.1981@googlemail.com>
Christopher Dunn <cdunn2001@gmail.com>
Chuck Atkins <chuck.atkins@kitware.com>
Cody P Schafer <dev@codyps.com>
Connor Manning <connor@hobu.co>
Cory Quammen <cory.quammen@kitware.com>
Cristóvão B da Cruz e Silva <CrisXed@gmail.com>
Daniel Krügler <daniel.kruegler@gmail.com>
Dani-Hub <daniel.kruegler@googlemail.com>
Dan Liu <gzliudan>
datadiode <datadiode@users.noreply.github.com>
datadiode <jochen.neubeck@vodafone.de>
David Seifert <soap@gentoo.org>
David West <david-west@idexx.com>
dawesc <chris.dawes@eftlab.co.uk>
Devin Jeanpierre <jeanpierreda@google.com>
Dmitry Marakasov <amdmi3@amdmi3.ru>
dominicpezzuto <dom@dompezzuto.com>
Don Milham <dmilham@gmail.com>
drgler <daniel.kruegler@gmail.com>
ds283 <D.Seery@sussex.ac.uk>
Egor Tensin <Egor.Tensin@gmail.com>
eightnoteight <mr.eightnoteight@gmail.com>
Evince <baneyue@gmail.com>
filipjs <filipjs@users.noreply.github.com>
findblar <ft@finbarr.ca>
Florian Meier <florian.meier@koalo.de>
Gaëtan Lehmann <gaetan.lehmann@gmail.com>
Gaurav <g.gupta@samsung.com>
Gergely Nagy <ngg@ngg.hu>
Gida Pataki <gida.pataki@prezi.com>
I3ck <buckmartin@buckmartin.de>
Iñaki Baz Castillo <ibc@aliax.net>
Jacco <jacco@geul.net>
Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
Jonas Platte <mail@jonasplatte.de>
Jordan Bayles <bayles.jordan@gmail.com>
Jörg Krause <joerg.krause@embedded.rocks>
Keith Lea <keith@whamcitylights.com>
Kevin Grant <kbradleygrant@gmail.com>
Kirill V. Lyadvinsky <jia3ep@gmail.com>
Kirill V. Lyadvinsky <mail@codeatcpp.com>
Kobi Gurkan <kobigurk@gmail.com>
Magnus Bjerke Vik <mbvett@gmail.com>
Malay Shah <malays@users.sourceforge.net>
Mara Kim <hacker.root@gmail.com>
Marek Kotewicz <marek.kotewicz@gmail.com>
Mark Lakata <mark@lakata.org>
Mark Zeren <mzeren@vmware.com>
Martin Buck <buckmartin@buckmartin.de>
Martyn Gigg <martyn.gigg@gmail.com>
Mattes D <github@xoft.cz>
Matthias Loy <matthias.loy@hbm.com>
Merlyn Morgan-Graham <kavika@gmail.com>
Michael Shields <mshields@google.com>
Michał Górny <mgorny@gentoo.org>
Mike Naberezny <mike@naberezny.com>
mloy <matthias.loy@googlemail.com>
Motti <lanzkron@gmail.com>
nnkur <nnkur@mail.ru>
Omkar Wagh <owagh@owaghlinux.ny.tower-research.com>
paulo <paulobrizolara@users.noreply.github.com>
pavel.pimenov <pavel.pimenov@gmail.com>
Paweł Bylica <chfast@gmail.com>
Péricles Lopes Machado <pericles.raskolnikoff@gmail.com>
Peter Spiess-Knafl <psk@autistici.org>
pffang <pffang@vip.qq.com>
Rémi Verschelde <remi@verschelde.fr>
renu555 <renu.tyagi@samsung.com>
Robert Dailey <rcdailey@gmail.com>
Sam Clegg <sbc@chromium.org>
selaselah <selah@outlook.com>
Sergiy80 <sil2004@gmail.com>
sergzub <sergzub@gmail.com>
Stefan Schweter <stefan@schweter.it>
Stefano Fiorentino <stefano.fiore84@gmail.com>
Steffen Kieß <Steffen.Kiess@ipvs.uni-stuttgart.de>
Steven Hahn <hahnse@ornl.gov>
Stuart Eichert <stuart@fivemicro.com>
SuperManitu <supermanitu@gmail.com>
Techwolf <dring@g33kworld.net>
Tengiz Sharafiev <btolfa+github@gmail.com>
Tomasz Maciejewski <tmaciejewsk@gmail.com>
Vicente Olivert Riera <Vincent.Riera@imgtec.com>
xiaoyur347 <xiaoyur347@gmail.com>
ycqiu <429148848@qq.com>
yiqiju <fred_ju@selinc.com>
Yu Xiaolei <dreifachstein@gmail.com>
Google Inc.

View File

@ -0,0 +1,55 @@
The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...
Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
The JsonCpp Authors, and is released under the terms of the MIT License (see below).
In jurisdictions which recognize Public Domain property, the user of this
software may choose to accept it either as 1) Public Domain, 2) under the
conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.
The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:
http://en.wikipedia.org/wiki/MIT_License
The full text of the MIT License follows:
========================================================================
Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
========================================================================
(END LICENSE TEXT)
The MIT license is compatible with both the GPL and commercial
software, affording one all of the rights of Public Domain with the
minor nuisance of being required to keep the above copyright notice
and license text in the source code. Note also that by accepting the
Public Domain "license" you can re-license your copy using whatever
license you like.

View File

@ -0,0 +1,88 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_ALLOCATOR_H_INCLUDED
#define JSON_ALLOCATOR_H_INCLUDED
#include <cstring>
#include <memory>
#pragma pack(push, 8)
namespace Json {
template <typename T> class SecureAllocator {
public:
// Type definitions
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
/**
* Allocate memory for N items using the standard allocator.
*/
pointer allocate(size_type n) {
// allocate using "global operator new"
return static_cast<pointer>(::operator new(n * sizeof(T)));
}
/**
* Release memory which was allocated for N items at pointer P.
*
* The memory block is filled with zeroes before being released.
*/
void deallocate(pointer p, size_type n) {
// memset_s is used because memset may be optimized away by the compiler
memset_s(p, n * sizeof(T), 0, n * sizeof(T));
// free using "global operator delete"
::operator delete(p);
}
/**
* Construct an item in-place at pointer P.
*/
template <typename... Args> void construct(pointer p, Args&&... args) {
// construct using "placement new" and "perfect forwarding"
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
}
size_type max_size() const { return size_t(-1) / sizeof(T); }
pointer address(reference x) const { return std::addressof(x); }
const_pointer address(const_reference x) const { return std::addressof(x); }
/**
* Destroy an item in-place at pointer P.
*/
void destroy(pointer p) {
// destroy using "explicit destructor"
p->~T();
}
// Boilerplate
SecureAllocator() {}
template <typename U> SecureAllocator(const SecureAllocator<U>&) {}
template <typename U> struct rebind { using other = SecureAllocator<U>; };
};
template <typename T, typename U>
bool operator==(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return true;
}
template <typename T, typename U>
bool operator!=(const SecureAllocator<T>&, const SecureAllocator<U>&) {
return false;
}
} // namespace Json
#pragma pack(pop)
#endif // JSON_ALLOCATOR_H_INCLUDED

View File

@ -0,0 +1,61 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_ASSERTIONS_H_INCLUDED
#define JSON_ASSERTIONS_H_INCLUDED
#include <cstdlib>
#include <sstream>
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
/** It should not be possible for a maliciously designed file to
* cause an abort() or seg-fault, so these macros are used only
* for pre-condition violations and internal logic errors.
*/
#if JSON_USE_EXCEPTION
// @todo <= add detail about condition in exception
#define JSON_ASSERT(condition) \
do { \
if (!(condition)) { \
Json::throwLogicError("assert json failed"); \
} \
} while (0)
#define JSON_FAIL_MESSAGE(message) \
do { \
OStringStream oss; \
oss << message; \
Json::throwLogicError(oss.str()); \
abort(); \
} while (0)
#else // JSON_USE_EXCEPTION
#define JSON_ASSERT(condition) assert(condition)
// The call to assert() will show the failure message in debug builds. In
// release builds we abort, for a core-dump or debugger.
#define JSON_FAIL_MESSAGE(message) \
{ \
OStringStream oss; \
oss << message; \
assert(false && oss.str().c_str()); \
abort(); \
}
#endif
#define JSON_ASSERT_MESSAGE(condition, message) \
do { \
if (!(condition)) { \
JSON_FAIL_MESSAGE(message); \
} \
} while (0)
#endif // JSON_ASSERTIONS_H_INCLUDED

View File

@ -0,0 +1,150 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_CONFIG_H_INCLUDED
#define JSON_CONFIG_H_INCLUDED
#include <cstddef>
#include <cstdint>
#include <istream>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <type_traits>
// If non-zero, the library uses exceptions to report bad input instead of C
// assertion macros. The default is to use exceptions.
#ifndef JSON_USE_EXCEPTION
#define JSON_USE_EXCEPTION 1
#endif
// Temporary, tracked for removal with issue #982.
#ifndef JSON_USE_NULLREF
#define JSON_USE_NULLREF 1
#endif
/// If defined, indicates that the source file is amalgamated
/// to prevent private header inclusion.
/// Remarks: it is automatically defined in the generated amalgamated header.
// #define JSON_IS_AMALGAMATION
// Export macros for DLL visibility
#if defined(JSON_DLL_BUILD)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllexport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#elif defined(__GNUC__) || defined(__clang__)
#define JSON_API __attribute__((visibility("default")))
#endif // if defined(_MSC_VER)
#elif defined(JSON_DLL)
#if defined(_MSC_VER) || defined(__MINGW32__)
#define JSON_API __declspec(dllimport)
#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
#endif // if defined(_MSC_VER)
#endif // ifdef JSON_DLL_BUILD
#if !defined(JSON_API)
#define JSON_API
#endif
#if defined(_MSC_VER) && _MSC_VER < 1800
#error \
"ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
#endif
#if defined(_MSC_VER) && _MSC_VER < 1900
// As recommended at
// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
extern JSON_API int msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
const char* format, ...);
#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
#else
#define jsoncpp_snprintf std::snprintf
#endif
// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
// integer
// Storages, and 64 bits integer support is disabled.
// #define JSON_NO_INT64 1
// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
// C++11 should be used directly in JSONCPP.
#define JSONCPP_OVERRIDE override
#ifdef __clang__
#if __has_extension(attribute_deprecated_with_message)
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#elif defined(__GNUC__) // not clang (gcc comes later since clang emulates gcc)
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
#endif // GNUC version
#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates
// MSVC)
#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
#endif // __clang__ || __GNUC__ || _MSC_VER
#if !defined(JSONCPP_DEPRECATED)
#define JSONCPP_DEPRECATED(message)
#endif // if !defined(JSONCPP_DEPRECATED)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))
#define JSON_USE_INT64_DOUBLE_CONVERSION 1
#endif
#if !defined(JSON_IS_AMALGAMATION)
#include "allocator.h"
#include "version.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
using Int = int;
using UInt = unsigned int;
#if defined(JSON_NO_INT64)
using LargestInt = int;
using LargestUInt = unsigned int;
#undef JSON_HAS_INT64
#else // if defined(JSON_NO_INT64)
// For Microsoft Visual use specific types as long long is not supported
#if defined(_MSC_VER) // Microsoft Visual Studio
using Int64 = __int64;
using UInt64 = unsigned __int64;
#else // if defined(_MSC_VER) // Other platforms, use long long
using Int64 = int64_t;
using UInt64 = uint64_t;
#endif // if defined(_MSC_VER)
using LargestInt = Int64;
using LargestUInt = UInt64;
#define JSON_HAS_INT64
#endif // if defined(JSON_NO_INT64)
template <typename T>
using Allocator =
typename std::conditional<JSONCPP_USING_SECURE_MEMORY, SecureAllocator<T>,
std::allocator<T>>::type;
using String = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
using IStringStream =
std::basic_istringstream<String::value_type, String::traits_type,
String::allocator_type>;
using OStringStream =
std::basic_ostringstream<String::value_type, String::traits_type,
String::allocator_type>;
using IStream = std::istream;
using OStream = std::ostream;
} // namespace Json
// Legacy names (formerly macros).
using JSONCPP_STRING = Json::String;
using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
using JSONCPP_ISTREAM = Json::IStream;
using JSONCPP_OSTREAM = Json::OStream;
#endif // JSON_CONFIG_H_INCLUDED

View File

@ -0,0 +1,43 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_FORWARDS_H_INCLUDED
#define JSON_FORWARDS_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "config.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
namespace Json {
// writer.h
class StreamWriter;
class StreamWriterBuilder;
class Writer;
class FastWriter;
class StyledWriter;
class StyledStreamWriter;
// reader.h
class Reader;
class CharReader;
class CharReaderBuilder;
// json_features.h
class Features;
// value.h
using ArrayIndex = unsigned int;
class StaticString;
class Path;
class PathArgument;
class Value;
class ValueIteratorBase;
class ValueIterator;
class ValueConstIterator;
} // namespace Json
#endif // JSON_FORWARDS_H_INCLUDED

View File

@ -0,0 +1,15 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_JSON_H_INCLUDED
#define JSON_JSON_H_INCLUDED
#include "config.h"
#include "json_features.h"
#include "reader.h"
#include "value.h"
#include "writer.h"
#endif // JSON_JSON_H_INCLUDED

View File

@ -0,0 +1,61 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_FEATURES_H_INCLUDED
#define JSON_FEATURES_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#pragma pack(push, 8)
namespace Json {
/** \brief Configuration passed to reader and writer.
* This configuration object can be used to force the Reader or Writer
* to behave in a standard conforming way.
*/
class JSON_API Features {
public:
/** \brief A configuration that allows all features and assumes all strings
* are UTF-8.
* - C & C++ comments are allowed
* - Root object can be any JSON value
* - Assumes Value strings are encoded in UTF-8
*/
static Features all();
/** \brief A configuration that is strictly compatible with the JSON
* specification.
* - Comments are forbidden.
* - Root object must be either an array or an object value.
* - Assumes Value strings are encoded in UTF-8
*/
static Features strictMode();
/** \brief Initialize the configuration like JsonConfig::allFeatures;
*/
Features();
/// \c true if comments are allowed. Default: \c true.
bool allowComments_{true};
/// \c true if root must be either an array or an object value. Default: \c
/// false.
bool strictRoot_{false};
/// \c true if dropped null placeholders are allowed. Default: \c false.
bool allowDroppedNullPlaceholders_{false};
/// \c true if numeric object key are allowed. Default: \c false.
bool allowNumericKeys_{false};
};
} // namespace Json
#pragma pack(pop)
#endif // JSON_FEATURES_H_INCLUDED

View File

@ -0,0 +1,405 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_READER_H_INCLUDED
#define JSON_READER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "json_features.h"
#include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <deque>
#include <iosfwd>
#include <istream>
#include <stack>
#include <string>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
namespace Json {
/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
* Value.
*
* \deprecated Use CharReader and CharReaderBuilder.
*/
class JSON_API Reader {
public:
using Char = char;
using Location = const Char*;
/** \brief An error tagged with where in the JSON text it was encountered.
*
* The offsets give the [start, limit) range of bytes within the text. Note
* that this is bytes, not codepoints.
*/
struct StructuredError {
ptrdiff_t offset_start;
ptrdiff_t offset_limit;
String message;
};
/** \brief Constructs a Reader allowing all features for parsing.
* \deprecated Use CharReader and CharReaderBuilder.
*/
Reader();
/** \brief Constructs a Reader allowing the specified feature set for parsing.
* \deprecated Use CharReader and CharReaderBuilder.
*/
Reader(const Features& features);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document.
*
* \param document UTF-8 encoded string containing the document
* to read.
* \param[out] root Contains the root value of the document if it
* was successfully parsed.
* \param collectComments \c true to collect comment and allow writing
* them back during serialization, \c false to
* discard comments. This parameter is ignored
* if Features::allowComments_ is \c false.
* \return \c true if the document was successfully parsed, \c false if an
* error occurred.
*/
bool parse(const std::string& document, Value& root,
bool collectComments = true);
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document.
*
* \param beginDoc Pointer on the beginning of the UTF-8 encoded
* string of the document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string
* of the document to read. Must be >= beginDoc.
* \param[out] root Contains the root value of the document if it
* was successfully parsed.
* \param collectComments \c true to collect comment and allow writing
* them back during serialization, \c false to
* discard comments. This parameter is ignored
* if Features::allowComments_ is \c false.
* \return \c true if the document was successfully parsed, \c false if an
* error occurred.
*/
bool parse(const char* beginDoc, const char* endDoc, Value& root,
bool collectComments = true);
/// \brief Parse from input stream.
/// \see Json::operator>>(std::istream&, Json::Value&).
bool parse(IStream& is, Value& root, bool collectComments = true);
/** \brief Returns a user friendly string that list errors in the parsed
* document.
*
* \return Formatted error message with the list of errors with their
* location in the parsed document. An empty string is returned if no error
* occurred during parsing.
* \deprecated Use getFormattedErrorMessages() instead (typo fix).
*/
JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.")
String getFormatedErrorMessages() const;
/** \brief Returns a user friendly string that list errors in the parsed
* document.
*
* \return Formatted error message with the list of errors with their
* location in the parsed document. An empty string is returned if no error
* occurred during parsing.
*/
String getFormattedErrorMessages() const;
/** \brief Returns a vector of structured errors encountered while parsing.
*
* \return A (possibly empty) vector of StructuredError objects. Currently
* only one error can be returned, but the caller should tolerate multiple
* errors. This can occur if the parser recovers from a non-fatal parse
* error and then encounters additional errors.
*/
std::vector<StructuredError> getStructuredErrors() const;
/** \brief Add a semantic error message.
*
* \param value JSON Value location associated with the error
* \param message The error message.
* \return \c true if the error was successfully added, \c false if the Value
* offset exceeds the document size.
*/
bool pushError(const Value& value, const String& message);
/** \brief Add a semantic error message with extra context.
*
* \param value JSON Value location associated with the error
* \param message The error message.
* \param extra Additional JSON Value location to contextualize the error
* \return \c true if the error was successfully added, \c false if either
* Value offset exceeds the document size.
*/
bool pushError(const Value& value, const String& message, const Value& extra);
/** \brief Return whether there are any errors.
*
* \return \c true if there are no errors to report \c false if errors have
* occurred.
*/
bool good() const;
private:
enum TokenType {
tokenEndOfStream = 0,
tokenObjectBegin,
tokenObjectEnd,
tokenArrayBegin,
tokenArrayEnd,
tokenString,
tokenNumber,
tokenTrue,
tokenFalse,
tokenNull,
tokenArraySeparator,
tokenMemberSeparator,
tokenComment,
tokenError
};
class Token {
public:
TokenType type_;
Location start_;
Location end_;
};
class ErrorInfo {
public:
Token token_;
String message_;
Location extra_;
};
using Errors = std::deque<ErrorInfo>;
bool readToken(Token& token);
void skipSpaces();
bool match(const Char* pattern, int patternLength);
bool readComment();
bool readCStyleComment();
bool readCppStyleComment();
bool readString();
void readNumber();
bool readValue();
bool readObject(Token& token);
bool readArray(Token& token);
bool decodeNumber(Token& token);
bool decodeNumber(Token& token, Value& decoded);
bool decodeString(Token& token);
bool decodeString(Token& token, String& decoded);
bool decodeDouble(Token& token);
bool decodeDouble(Token& token, Value& decoded);
bool decodeUnicodeCodePoint(Token& token, Location& current, Location end,
unsigned int& unicode);
bool decodeUnicodeEscapeSequence(Token& token, Location& current,
Location end, unsigned int& unicode);
bool addError(const String& message, Token& token, Location extra = nullptr);
bool recoverFromError(TokenType skipUntilToken);
bool addErrorAndRecover(const String& message, Token& token,
TokenType skipUntilToken);
void skipUntilSpace();
Value& currentValue();
Char getNextChar();
void getLocationLineAndColumn(Location location, int& line,
int& column) const;
String getLocationLineAndColumn(Location location) const;
void addComment(Location begin, Location end, CommentPlacement placement);
void skipCommentTokens(Token& token);
static bool containsNewLine(Location begin, Location end);
static String normalizeEOL(Location begin, Location end);
using Nodes = std::stack<Value*>;
Nodes nodes_;
Errors errors_;
String document_;
Location begin_{};
Location end_{};
Location current_{};
Location lastValueEnd_{};
Value* lastValue_{};
String commentsBefore_;
Features features_;
bool collectComments_{};
}; // Reader
/** Interface for reading JSON from a char array.
*/
class JSON_API CharReader {
public:
virtual ~CharReader() = default;
/** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
* document. The document must be a UTF-8 encoded string containing the
* document to read.
*
* \param beginDoc Pointer on the beginning of the UTF-8 encoded string
* of the document to read.
* \param endDoc Pointer on the end of the UTF-8 encoded string of the
* document to read. Must be >= beginDoc.
* \param[out] root Contains the root value of the document if it was
* successfully parsed.
* \param[out] errs Formatted error messages (if not NULL) a user
* friendly string that lists errors in the parsed
* document.
* \return \c true if the document was successfully parsed, \c false if an
* error occurred.
*/
virtual bool parse(char const* beginDoc, char const* endDoc, Value* root,
String* errs) = 0;
class JSON_API Factory {
public:
virtual ~Factory() = default;
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual CharReader* newCharReader() const = 0;
}; // Factory
}; // CharReader
/** \brief Build a CharReader implementation.
*
* Usage:
* \code
* using namespace Json;
* CharReaderBuilder builder;
* builder["collectComments"] = false;
* Value value;
* String errs;
* bool ok = parseFromStream(builder, std::cin, &value, &errs);
* \endcode
*/
class JSON_API CharReaderBuilder : public CharReader::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
* These are case-sensitive.
* Available settings (case-sensitive):
* - `"collectComments": false or true`
* - true to collect comment and allow writing them back during
* serialization, false to discard comments. This parameter is ignored
* if allowComments is false.
* - `"allowComments": false or true`
* - true if comments are allowed.
* - `"allowTrailingCommas": false or true`
* - true if trailing commas in objects and arrays are allowed.
* - `"strictRoot": false or true`
* - true if root must be either an array or an object value
* - `"allowDroppedNullPlaceholders": false or true`
* - true if dropped null placeholders are allowed. (See
* StreamWriterBuilder.)
* - `"allowNumericKeys": false or true`
* - true if numeric object keys are allowed.
* - `"allowSingleQuotes": false or true`
* - true if '' are allowed for strings (both keys and values)
* - `"stackLimit": integer`
* - Exceeding stackLimit (recursive depth of `readValue()`) will cause an
* exception.
* - This is a security issue (seg-faults caused by deeply nested JSON), so
* the default is low.
* - `"failIfExtra": false or true`
* - If true, `parse()` returns false when extra non-whitespace trails the
* JSON value in the input string.
* - `"rejectDupKeys": false or true`
* - If true, `parse()` returns false when a key is duplicated within an
* object.
* - `"allowSpecialFloats": false or true`
* - If true, special float values (NaNs and infinities) are allowed and
* their values are lossfree restorable.
* - `"skipBom": false or true`
* - If true, if the input starts with the Unicode byte order mark (BOM),
* it is skipped.
*
* You can examine 'settings_` yourself to see the defaults. You can also
* write and read them just like any JSON Value.
* \sa setDefaults()
*/
Json::Value settings_;
CharReaderBuilder();
~CharReaderBuilder() override;
CharReader* newCharReader() const override;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** A simple way to update a specific setting.
*/
Value& operator[](const String& key);
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults
*/
static void setDefaults(Json::Value* settings);
/** Same as old Features::strictMode().
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode
*/
static void strictMode(Json::Value* settings);
};
/** Consume entire stream and use its begin/end.
* Someday we might have a real StreamReader, but for now this
* is convenient.
*/
bool JSON_API parseFromStream(CharReader::Factory const&, IStream&, Value* root,
String* errs);
/** \brief Read from 'sin' into 'root'.
*
* Always keep comments from the input JSON.
*
* This can be used to read a file into a particular sub-object.
* For example:
* \code
* Json::Value root;
* cin >> root["dir"]["file"];
* cout << root;
* \endcode
* Result:
* \verbatim
* {
* "dir": {
* "file": {
* // The input stream JSON would be nested here.
* }
* }
* }
* \endverbatim
* \throw std::exception on parse error.
* \see Json::operator<<()
*/
JSON_API IStream& operator>>(IStream&, Value&);
} // namespace Json
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_READER_H_INCLUDED

View File

@ -0,0 +1,935 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_H_INCLUDED
#define JSON_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "forwards.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
// Conditional NORETURN attribute on the throw functions would:
// a) suppress false positives from static code analysis
// b) possibly improve optimization opportunities.
#if !defined(JSONCPP_NORETURN)
#if defined(_MSC_VER) && _MSC_VER == 1800
#define JSONCPP_NORETURN __declspec(noreturn)
#else
#define JSONCPP_NORETURN [[noreturn]]
#endif
#endif
// Support for '= delete' with template declarations was a late addition
// to the c++11 standard and is rejected by clang 3.8 and Apple clang 8.2
// even though these declare themselves to be c++11 compilers.
#if !defined(JSONCPP_TEMPLATE_DELETE)
#if defined(__clang__) && defined(__apple_build_version__)
#if __apple_build_version__ <= 8000042
#define JSONCPP_TEMPLATE_DELETE
#endif
#elif defined(__clang__)
#if __clang_major__ == 3 && __clang_minor__ <= 8
#define JSONCPP_TEMPLATE_DELETE
#endif
#endif
#if !defined(JSONCPP_TEMPLATE_DELETE)
#define JSONCPP_TEMPLATE_DELETE = delete
#endif
#endif
#include <array>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <vector>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(push)
#pragma warning(disable : 4251 4275)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
/** \brief JSON (JavaScript Object Notation).
*/
namespace Json {
#if JSON_USE_EXCEPTION
/** Base class for all exceptions we throw.
*
* We use nothing but these internally. Of course, STL can throw others.
*/
class JSON_API Exception : public std::exception {
public:
Exception(String msg);
~Exception() noexcept override;
char const* what() const noexcept override;
protected:
String msg_;
};
/** Exceptions which the user cannot easily avoid.
*
* E.g. out-of-memory (when we use malloc), stack-overflow, malicious input
*
* \remark derived from Json::Exception
*/
class JSON_API RuntimeError : public Exception {
public:
RuntimeError(String const& msg);
};
/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros.
*
* These are precondition-violations (user bugs) and internal errors (our bugs).
*
* \remark derived from Json::Exception
*/
class JSON_API LogicError : public Exception {
public:
LogicError(String const& msg);
};
#endif
/// used internally
JSONCPP_NORETURN void throwRuntimeError(String const& msg);
/// used internally
JSONCPP_NORETURN void throwLogicError(String const& msg);
/** \brief Type of the value held by a Value object.
*/
enum ValueType {
nullValue = 0, ///< 'null' value
intValue, ///< signed integer value
uintValue, ///< unsigned integer value
realValue, ///< double value
stringValue, ///< UTF-8 string value
booleanValue, ///< bool value
arrayValue, ///< array value (ordered list)
objectValue ///< object value (collection of name/value pairs).
};
enum CommentPlacement {
commentBefore = 0, ///< a comment placed on the line before a value
commentAfterOnSameLine, ///< a comment just after a value on the same line
commentAfter, ///< a comment on the line after a value (only make sense for
/// root value)
numberOfCommentPlacement
};
/** \brief Type of precision for formatting of real values.
*/
enum PrecisionType {
significantDigits = 0, ///< we set max number of significant digits in string
decimalPlaces ///< we set max number of digits after "." in string
};
/** \brief Lightweight wrapper to tag static string.
*
* Value constructor and objectValue member assignment takes advantage of the
* StaticString and avoid the cost of string duplication when storing the
* string or the member name.
*
* Example of usage:
* \code
* Json::Value aValue( StaticString("some text") );
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
class JSON_API StaticString {
public:
explicit StaticString(const char* czstring) : c_str_(czstring) {}
operator const char*() const { return c_str_; }
const char* c_str() const { return c_str_; }
private:
const char* c_str_;
};
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
* This class is a discriminated union wrapper that can represents a:
* - signed integer [range: Value::minInt - Value::maxInt]
* - unsigned integer (range: 0 - Value::maxUInt)
* - double
* - UTF-8 string
* - boolean
* - 'null'
* - an ordered list of Value
* - collection of name/value pairs (javascript object)
*
* The type of the held value is represented by a #ValueType and
* can be obtained using type().
*
* Values of an #objectValue or #arrayValue can be accessed using operator[]()
* methods.
* Non-const methods will automatically create the a #nullValue element
* if it does not exist.
* The sequence of an #arrayValue will be automatically resized and initialized
* with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
*
* The get() methods can be used to obtain default value in the case the
* required element does not exist.
*
* It is possible to iterate over the list of member keys of an object using
* the getMemberNames() method.
*
* \note #Value string-length fit in size_t, but keys must be < 2^30.
* (The reason is an implementation detail.) A #CharReader will raise an
* exception if a bound is exceeded to avoid security holes in your app,
* but the Value API does *not* check bounds. That is the responsibility
* of the caller.
*/
class JSON_API Value {
friend class ValueIteratorBase;
public:
using Members = std::vector<String>;
using iterator = ValueIterator;
using const_iterator = ValueConstIterator;
using UInt = Json::UInt;
using Int = Json::Int;
#if defined(JSON_HAS_INT64)
using UInt64 = Json::UInt64;
using Int64 = Json::Int64;
#endif // defined(JSON_HAS_INT64)
using LargestInt = Json::LargestInt;
using LargestUInt = Json::LargestUInt;
using ArrayIndex = Json::ArrayIndex;
// Required for boost integration, e. g. BOOST_TEST
using value_type = std::string;
#if JSON_USE_NULLREF
// Binary compatibility kludges, do not use.
static const Value& null;
static const Value& nullRef;
#endif
// null and nullRef are deprecated, use this instead.
static Value const& nullSingleton();
/// Minimum signed integer value that can be stored in a Json::Value.
static constexpr LargestInt minLargestInt =
LargestInt(~(LargestUInt(-1) / 2));
/// Maximum signed integer value that can be stored in a Json::Value.
static constexpr LargestInt maxLargestInt = LargestInt(LargestUInt(-1) / 2);
/// Maximum unsigned integer value that can be stored in a Json::Value.
static constexpr LargestUInt maxLargestUInt = LargestUInt(-1);
/// Minimum signed int value that can be stored in a Json::Value.
static constexpr Int minInt = Int(~(UInt(-1) / 2));
/// Maximum signed int value that can be stored in a Json::Value.
static constexpr Int maxInt = Int(UInt(-1) / 2);
/// Maximum unsigned int value that can be stored in a Json::Value.
static constexpr UInt maxUInt = UInt(-1);
#if defined(JSON_HAS_INT64)
/// Minimum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 minInt64 = Int64(~(UInt64(-1) / 2));
/// Maximum signed 64 bits int value that can be stored in a Json::Value.
static constexpr Int64 maxInt64 = Int64(UInt64(-1) / 2);
/// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
static constexpr UInt64 maxUInt64 = UInt64(-1);
#endif // defined(JSON_HAS_INT64)
/// Default precision for real value for string representation.
static constexpr UInt defaultRealPrecision = 17;
// The constant is hard-coded because some compiler have trouble
// converting Value::maxUInt64 to a double correctly (AIX/xlC).
// Assumes that UInt64 is a 64 bits integer.
static constexpr double maxUInt64AsDouble = 18446744073709551615.0;
// Workaround for bug in the NVIDIAs CUDA 9.1 nvcc compiler
// when using gcc and clang backend compilers. CZString
// cannot be defined as private. See issue #486
#ifdef __NVCC__
public:
#else
private:
#endif
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
class CZString {
public:
enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
CZString(ArrayIndex index);
CZString(char const* str, unsigned length, DuplicationPolicy allocate);
CZString(CZString const& other);
CZString(CZString&& other) noexcept;
~CZString();
CZString& operator=(const CZString& other);
CZString& operator=(CZString&& other) noexcept;
bool operator<(CZString const& other) const;
bool operator==(CZString const& other) const;
ArrayIndex index() const;
// const char* c_str() const; ///< \deprecated
char const* data() const;
unsigned length() const;
bool isStaticString() const;
private:
void swap(CZString& other);
struct StringStorage {
unsigned policy_ : 2;
unsigned length_ : 30; // 1GB max
};
char const* cstr_; // actually, a prefixed string, unless policy is noDup
union {
ArrayIndex index_;
StringStorage storage_;
};
};
public:
typedef std::map<CZString, Value> ObjectValues;
#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
public:
/**
* \brief Create a default Value of the given type.
*
* This is a very useful constructor.
* To create an empty array, pass arrayValue.
* To create an empty object, pass objectValue.
* Another Value can then be set to this one by assignment.
* This is useful since clear() and resize() will not alter types.
*
* Examples:
* \code
* Json::Value null_value; // null
* Json::Value arr_value(Json::arrayValue); // []
* Json::Value obj_value(Json::objectValue); // {}
* \endcode
*/
Value(ValueType type = nullValue);
Value(Int value);
Value(UInt value);
#if defined(JSON_HAS_INT64)
Value(Int64 value);
Value(UInt64 value);
#endif // if defined(JSON_HAS_INT64)
Value(double value);
Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.)
Value(const char* begin, const char* end); ///< Copy all, incl zeroes.
/**
* \brief Constructs a value from a static string.
*
* Like other value string constructor but do not duplicate the string for
* internal storage. The given string must remain alive after the call to
* this constructor.
*
* \note This works only for null-terminated strings. (We cannot change the
* size of this class, so we have nowhere to store the length, which might be
* computed later for various operations.)
*
* Example of usage:
* \code
* static StaticString foo("some text");
* Json::Value aValue(foo);
* \endcode
*/
Value(const StaticString& value);
Value(const String& value);
Value(bool value);
Value(std::nullptr_t ptr) = delete;
Value(const Value& other);
Value(Value&& other) noexcept;
~Value();
/// \note Overwrite existing comments. To preserve comments, use
/// #swapPayload().
Value& operator=(const Value& other);
Value& operator=(Value&& other) noexcept;
/// Swap everything.
void swap(Value& other);
/// Swap values but leave comments and source offsets in place.
void swapPayload(Value& other);
/// copy everything.
void copy(const Value& other);
/// copy values but leave comments and source offsets in place.
void copyPayload(const Value& other);
ValueType type() const;
/// Compare payload only, not comments etc.
bool operator<(const Value& other) const;
bool operator<=(const Value& other) const;
bool operator>=(const Value& other) const;
bool operator>(const Value& other) const;
bool operator==(const Value& other) const;
bool operator!=(const Value& other) const;
int compare(const Value& other) const;
const char* asCString() const; ///< Embedded zeroes could cause you trouble!
#if JSONCPP_USING_SECURE_MEMORY
unsigned getCStringLength() const; // Allows you to understand the length of
// the CString
#endif
String asString() const; ///< Embedded zeroes are possible.
/** Get raw char* of string-value.
* \return false if !string. (Seg-fault if str or end are NULL.)
*/
bool getString(char const** begin, char const** end) const;
Int asInt() const;
UInt asUInt() const;
#if defined(JSON_HAS_INT64)
Int64 asInt64() const;
UInt64 asUInt64() const;
#endif // if defined(JSON_HAS_INT64)
LargestInt asLargestInt() const;
LargestUInt asLargestUInt() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
/// The `as<T>` and `is<T>` member function templates and specializations.
template <typename T> T as() const JSONCPP_TEMPLATE_DELETE;
template <typename T> bool is() const JSONCPP_TEMPLATE_DELETE;
bool isConvertibleTo(ValueType other) const;
/// Number of values in array or object
ArrayIndex size() const;
/// \brief Return true if empty array, empty object, or null;
/// otherwise, false.
bool empty() const;
/// Return !isNull()
explicit operator bool() const;
/// Remove all object members and array elements.
/// \pre type() is arrayValue, objectValue, or nullValue
/// \post type() is unchanged
void clear();
/// Resize the array to newSize elements.
/// New elements are initialized to null.
/// May only be called on nullValue or arrayValue.
/// \pre type() is arrayValue or nullValue
/// \post type() is arrayValue
void resize(ArrayIndex newSize);
//@{
/// Access an array element (zero based index). If the array contains less
/// than index element, then null value are inserted in the array so that
/// its size is index+1.
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
Value& operator[](ArrayIndex index);
Value& operator[](int index);
//@}
//@{
/// Access an array element (zero based index).
/// (You may need to say 'value[0u]' to get your compiler to distinguish
/// this from the operator[] which takes a string.)
const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const;
//@}
/// If the array contains at least index+1 elements, returns the element
/// value, otherwise returns defaultValue.
Value get(ArrayIndex index, const Value& defaultValue) const;
/// Return true if index < size().
bool isValidIndex(ArrayIndex index) const;
/// \brief Append value to array at the end.
///
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
Value& append(const Value& value);
Value& append(Value&& value);
/// \brief Insert value in array at specific index
bool insert(ArrayIndex index, const Value& newValue);
bool insert(ArrayIndex index, Value&& newValue);
/// Access an object value by name, create a null member if it does not exist.
/// \note Because of our implementation, keys are limited to 2^30 -1 chars.
/// Exceeding that will cause an exception.
Value& operator[](const char* key);
/// Access an object value by name, returns null if there is no member with
/// that name.
const Value& operator[](const char* key) const;
/// Access an object value by name, create a null member if it does not exist.
/// \param key may contain embedded nulls.
Value& operator[](const String& key);
/// Access an object value by name, returns null if there is no member with
/// that name.
/// \param key may contain embedded nulls.
const Value& operator[](const String& key) const;
/** \brief Access an object value by name, create a null member if it does not
* exist.
*
* If the object has no entry for that name, then the member name used to
* store the new entry is not duplicated.
* Example of use:
* \code
* Json::Value object;
* static const StaticString code("code");
* object[code] = 1234;
* \endcode
*/
Value& operator[](const StaticString& key);
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
Value get(const char* key, const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \note key may contain embedded nulls.
Value get(const char* begin, const char* end,
const Value& defaultValue) const;
/// Return the member named key if it exist, defaultValue otherwise.
/// \note deep copy
/// \param key may contain embedded nulls.
Value get(const String& key, const Value& defaultValue) const;
/// Most general and efficient version of isMember()const, get()const,
/// and operator[]const
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
Value const* find(char const* begin, char const* end) const;
/// Most general and efficient version of object-mutators.
/// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30
/// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue.
Value* demand(char const* begin, char const* end);
/// \brief Remove and return the named member.
///
/// Do nothing if it did not exist.
/// \pre type() is objectValue or nullValue
/// \post type() is unchanged
void removeMember(const char* key);
/// Same as removeMember(const char*)
/// \param key may contain embedded nulls.
void removeMember(const String& key);
/// Same as removeMember(const char* begin, const char* end, Value* removed),
/// but 'key' is null-terminated.
bool removeMember(const char* key, Value* removed);
/** \brief Remove the named map member.
*
* Update 'removed' iff removed.
* \param key may contain embedded nulls.
* \return true iff removed (no exceptions)
*/
bool removeMember(String const& key, Value* removed);
/// Same as removeMember(String const& key, Value* removed)
bool removeMember(const char* begin, const char* end, Value* removed);
/** \brief Remove the indexed array element.
*
* O(n) expensive operations.
* Update 'removed' iff removed.
* \return true if removed (no exceptions)
*/
bool removeIndex(ArrayIndex index, Value* removed);
/// Return true if the object has a member named key.
/// \note 'key' must be null-terminated.
bool isMember(const char* key) const;
/// Return true if the object has a member named key.
/// \param key may contain embedded nulls.
bool isMember(const String& key) const;
/// Same as isMember(String const& key)const
bool isMember(const char* begin, const char* end) const;
/// \brief Return a list of the member names.
///
/// If null, return an empty list.
/// \pre type() is objectValue or nullValue
/// \post if type() was nullValue, it remains nullValue
Members getMemberNames() const;
/// \deprecated Always pass len.
JSONCPP_DEPRECATED("Use setComment(String const&) instead.")
void setComment(const char* comment, CommentPlacement placement) {
setComment(String(comment, strlen(comment)), placement);
}
/// Comments must be //... or /* ... */
void setComment(const char* comment, size_t len, CommentPlacement placement) {
setComment(String(comment, len), placement);
}
/// Comments must be //... or /* ... */
void setComment(String comment, CommentPlacement placement);
bool hasComment(CommentPlacement placement) const;
/// Include delimiters and embedded newlines.
String getComment(CommentPlacement placement) const;
String toStyledString() const;
const_iterator begin() const;
const_iterator end() const;
iterator begin();
iterator end();
// Accessors for the [start, limit) range of bytes within the JSON text from
// which this value was parsed, if any.
void setOffsetStart(ptrdiff_t start);
void setOffsetLimit(ptrdiff_t limit);
ptrdiff_t getOffsetStart() const;
ptrdiff_t getOffsetLimit() const;
private:
void setType(ValueType v) {
bits_.value_type_ = static_cast<unsigned char>(v);
}
bool isAllocated() const { return bits_.allocated_; }
void setIsAllocated(bool v) { bits_.allocated_ = v; }
void initBasic(ValueType type, bool allocated = false);
void dupPayload(const Value& other);
void releasePayload();
void dupMeta(const Value& other);
Value& resolveReference(const char* key);
Value& resolveReference(const char* key, const char* end);
// struct MemberNamesTransform
//{
// typedef const char *result_type;
// const char *operator()( const CZString &name ) const
// {
// return name.c_str();
// }
//};
union ValueHolder {
LargestInt int_;
LargestUInt uint_;
double real_;
bool bool_;
char* string_; // if allocated_, ptr to { unsigned, char[] }.
ObjectValues* map_;
} value_;
struct {
// Really a ValueType, but types should agree for bitfield packing.
unsigned int value_type_ : 8;
// Unless allocated_, string_ must be null-terminated.
unsigned int allocated_ : 1;
} bits_;
class Comments {
public:
Comments() = default;
Comments(const Comments& that);
Comments(Comments&& that) noexcept;
Comments& operator=(const Comments& that);
Comments& operator=(Comments&& that) noexcept;
bool has(CommentPlacement slot) const;
String get(CommentPlacement slot) const;
void set(CommentPlacement slot, String comment);
private:
using Array = std::array<String, numberOfCommentPlacement>;
std::unique_ptr<Array> ptr_;
};
Comments comments_;
// [start, limit) byte offsets in the source JSON text from which this Value
// was extracted.
ptrdiff_t start_;
ptrdiff_t limit_;
};
template <> inline bool Value::as<bool>() const { return asBool(); }
template <> inline bool Value::is<bool>() const { return isBool(); }
template <> inline Int Value::as<Int>() const { return asInt(); }
template <> inline bool Value::is<Int>() const { return isInt(); }
template <> inline UInt Value::as<UInt>() const { return asUInt(); }
template <> inline bool Value::is<UInt>() const { return isUInt(); }
#if defined(JSON_HAS_INT64)
template <> inline Int64 Value::as<Int64>() const { return asInt64(); }
template <> inline bool Value::is<Int64>() const { return isInt64(); }
template <> inline UInt64 Value::as<UInt64>() const { return asUInt64(); }
template <> inline bool Value::is<UInt64>() const { return isUInt64(); }
#endif
template <> inline double Value::as<double>() const { return asDouble(); }
template <> inline bool Value::is<double>() const { return isDouble(); }
template <> inline String Value::as<String>() const { return asString(); }
template <> inline bool Value::is<String>() const { return isString(); }
/// These `as` specializations are type conversions, and do not have a
/// corresponding `is`.
template <> inline float Value::as<float>() const { return asFloat(); }
template <> inline const char* Value::as<const char*>() const {
return asCString();
}
/** \brief Experimental and untested: represents an element of the "path" to
* access a node.
*/
class JSON_API PathArgument {
public:
friend class Path;
PathArgument();
PathArgument(ArrayIndex index);
PathArgument(const char* key);
PathArgument(String key);
private:
enum Kind { kindNone = 0, kindIndex, kindKey };
String key_;
ArrayIndex index_{};
Kind kind_{kindNone};
};
/** \brief Experimental and untested: represents a "path" to access a node.
*
* Syntax:
* - "." => root node
* - ".[n]" => elements at index 'n' of root node (an array value)
* - ".name" => member named 'name' of root node (an object value)
* - ".name1.name2.name3"
* - ".[0][1][2].name1[3]"
* - ".%" => member name is provided as parameter
* - ".[%]" => index is provided as parameter
*/
class JSON_API Path {
public:
Path(const String& path, const PathArgument& a1 = PathArgument(),
const PathArgument& a2 = PathArgument(),
const PathArgument& a3 = PathArgument(),
const PathArgument& a4 = PathArgument(),
const PathArgument& a5 = PathArgument());
const Value& resolve(const Value& root) const;
Value resolve(const Value& root, const Value& defaultValue) const;
/// Creates the "path" to access the specified node and returns a reference on
/// the node.
Value& make(Value& root) const;
private:
using InArgs = std::vector<const PathArgument*>;
using Args = std::vector<PathArgument>;
void makePath(const String& path, const InArgs& in);
void addPathInArg(const String& path, const InArgs& in,
InArgs::const_iterator& itInArg, PathArgument::Kind kind);
static void invalidPath(const String& path, int location);
Args args_;
};
/** \brief base class for Value iterators.
*
*/
class JSON_API ValueIteratorBase {
public:
using iterator_category = std::bidirectional_iterator_tag;
using size_t = unsigned int;
using difference_type = int;
using SelfType = ValueIteratorBase;
bool operator==(const SelfType& other) const { return isEqual(other); }
bool operator!=(const SelfType& other) const { return !isEqual(other); }
difference_type operator-(const SelfType& other) const {
return other.computeDistance(*this);
}
/// Return either the index or the member name of the referenced value as a
/// Value.
Value key() const;
/// Return the index of the referenced Value, or -1 if it is not an
/// arrayValue.
UInt index() const;
/// Return the member name of the referenced Value, or "" if it is not an
/// objectValue.
/// \note Avoid `c_str()` on result, as embedded zeroes are possible.
String name() const;
/// Return the member name of the referenced Value. "" if it is not an
/// objectValue.
/// \deprecated This cannot be used for UTF-8 strings, since there can be
/// embedded nulls.
JSONCPP_DEPRECATED("Use `key = name();` instead.")
char const* memberName() const;
/// Return the member name of the referenced Value, or NULL if it is not an
/// objectValue.
/// \note Better version than memberName(). Allows embedded nulls.
char const* memberName(char const** end) const;
protected:
/*! Internal utility functions to assist with implementing
* other iterator functions. The const and non-const versions
* of the "deref" protected methods expose the protected
* current_ member variable in a way that can often be
* optimized away by the compiler.
*/
const Value& deref() const;
Value& deref();
void increment();
void decrement();
difference_type computeDistance(const SelfType& other) const;
bool isEqual(const SelfType& other) const;
void copy(const SelfType& other);
private:
Value::ObjectValues::iterator current_;
// Indicates that iterator is for a null value.
bool isNull_{true};
public:
// For some reason, BORLAND needs these at the end, rather
// than earlier. No idea why.
ValueIteratorBase();
explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
};
/** \brief const iterator for object and array value.
*
*/
class JSON_API ValueConstIterator : public ValueIteratorBase {
friend class Value;
public:
using value_type = const Value;
// typedef unsigned int size_t;
// typedef int difference_type;
using reference = const Value&;
using pointer = const Value*;
using SelfType = ValueConstIterator;
ValueConstIterator();
ValueConstIterator(ValueIterator const& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const ValueIteratorBase& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
reference operator*() const { return deref(); }
pointer operator->() const { return &deref(); }
};
/** \brief Iterator for object and array value.
*/
class JSON_API ValueIterator : public ValueIteratorBase {
friend class Value;
public:
using value_type = Value;
using size_t = unsigned int;
using difference_type = int;
using reference = Value&;
using pointer = Value*;
using SelfType = ValueIterator;
ValueIterator();
explicit ValueIterator(const ValueConstIterator& other);
ValueIterator(const ValueIterator& other);
private:
/*! \internal Use by Value to create an iterator.
*/
explicit ValueIterator(const Value::ObjectValues::iterator& current);
public:
SelfType& operator=(const SelfType& other);
SelfType operator++(int) {
SelfType temp(*this);
++*this;
return temp;
}
SelfType operator--(int) {
SelfType temp(*this);
--*this;
return temp;
}
SelfType& operator--() {
decrement();
return *this;
}
SelfType& operator++() {
increment();
return *this;
}
/*! The return value of non-const iterators can be
* changed, so the these functions are not const
* because the returned references/pointers can be used
* to change state of the base class.
*/
reference operator*() const { return const_cast<reference>(deref()); }
pointer operator->() const { return const_cast<pointer>(&deref()); }
};
inline void swap(Value& a, Value& b) { a.swap(b); }
} // namespace Json
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_H_INCLUDED

View File

@ -0,0 +1,28 @@
#ifndef JSON_VERSION_H_INCLUDED
#define JSON_VERSION_H_INCLUDED
// Note: version must be updated in three places when doing a release. This
// annoying process ensures that amalgamate, CMake, and meson all report the
// correct version.
// 1. /meson.build
// 2. /include/json/version.h
// 3. /CMakeLists.txt
// IMPORTANT: also update the SOVERSION!!
#define JSONCPP_VERSION_STRING "1.9.5"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 5
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.
#endif // JSON_VERSION_H_INCLUDED

View File

@ -0,0 +1,369 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef JSON_WRITER_H_INCLUDED
#define JSON_WRITER_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include "value.h"
#endif // if !defined(JSON_IS_AMALGAMATION)
#include <ostream>
#include <string>
#include <vector>
// Disable warning C4251: <data member>: <type> needs to have dll-interface to
// be used by...
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) && defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4251)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma pack(push, 8)
namespace Json {
class Value;
/**
*
* Usage:
* \code
* using namespace Json;
* void writeToStdout(StreamWriter::Factory const& factory, Value const& value)
* { std::unique_ptr<StreamWriter> const writer( factory.newStreamWriter());
* writer->write(value, &std::cout);
* std::cout << std::endl; // add lf and flush
* }
* \endcode
*/
class JSON_API StreamWriter {
protected:
OStream* sout_; // not owned; will not delete
public:
StreamWriter();
virtual ~StreamWriter();
/** Write Value into document as configured in sub-class.
* Do not take ownership of sout, but maintain a reference during function.
* \pre sout != NULL
* \return zero on success (For now, we always return zero, so check the
* stream instead.) \throw std::exception possibly, depending on
* configuration
*/
virtual int write(Value const& root, OStream* sout) = 0;
/** \brief A simple abstract factory.
*/
class JSON_API Factory {
public:
virtual ~Factory();
/** \brief Allocate a CharReader via operator new().
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
virtual StreamWriter* newStreamWriter() const = 0;
}; // Factory
}; // StreamWriter
/** \brief Write into stringstream, then return string, for convenience.
* A StreamWriter will be created from the factory, used, and then deleted.
*/
String JSON_API writeString(StreamWriter::Factory const& factory,
Value const& root);
/** \brief Build a StreamWriter implementation.
* Usage:
* \code
* using namespace Json;
* Value value = ...;
* StreamWriterBuilder builder;
* builder["commentStyle"] = "None";
* builder["indentation"] = " "; // or whatever you like
* std::unique_ptr<Json::StreamWriter> writer(
* builder.newStreamWriter());
* writer->write(value, &std::cout);
* std::cout << std::endl; // add lf and flush
* \endcode
*/
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
public:
// Note: We use a Json::Value so that we can add data-members to this class
// without a major version bump.
/** Configuration of this builder.
* Available settings (case-sensitive):
* - "commentStyle": "None" or "All"
* - "indentation": "<anything>".
* - Setting this to an empty string also omits newline characters.
* - "enableYAMLCompatibility": false or true
* - slightly change the whitespace around colons
* - "dropNullPlaceholders": false or true
* - Drop the "null" string from the writer's output for nullValues.
* Strictly speaking, this is not valid JSON. But when the output is being
* fed to a browser's JavaScript, it makes for smaller output and the
* browser can handle the output just fine.
* - "useSpecialFloats": false or true
* - If true, outputs non-finite floating point values in the following way:
* NaN values as "NaN", positive infinity as "Infinity", and negative
* infinity as "-Infinity".
* - "precision": int
* - Number of precision digits for formatting of real values.
* - "precisionType": "significant"(default) or "decimal"
* - Type of precision for formatting of real values.
* - "emitUTF8": false or true
* - If true, outputs raw UTF8 strings instead of escaping them.
* You can examine 'settings_` yourself
* to see the defaults. You can also write and read them just like any
* JSON Value.
* \sa setDefaults()
*/
Json::Value settings_;
StreamWriterBuilder();
~StreamWriterBuilder() override;
/**
* \throw std::exception if something goes wrong (e.g. invalid settings)
*/
StreamWriter* newStreamWriter() const override;
/** \return true if 'settings' are legal and consistent;
* otherwise, indicate bad settings via 'invalid'.
*/
bool validate(Json::Value* invalid) const;
/** A simple way to update a specific setting.
*/
Value& operator[](const String& key);
/** Called by ctor, but you can use this to reset settings_.
* \pre 'settings' != NULL (but Json::null is fine)
* \remark Defaults:
* \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults
*/
static void setDefaults(Json::Value* settings);
};
/** \brief Abstract class for writers.
* \deprecated Use StreamWriter. (And really, this is an implementation detail.)
*/
class JSON_API Writer {
public:
virtual ~Writer();
virtual String write(const Value& root) = 0;
};
/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
*without formatting (not human friendly).
*
* The JSON document is written in a single line. It is not intended for 'human'
*consumption,
* but may be useful to support feature such as RPC where bandwidth is limited.
* \sa Reader, Value
* \deprecated Use StreamWriterBuilder.
*/
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSON_API FastWriter
: public Writer {
public:
FastWriter();
~FastWriter() override = default;
void enableYAMLCompatibility();
/** \brief Drop the "null" string from the writer's output for nullValues.
* Strictly speaking, this is not valid JSON. But when the output is being
* fed to a browser's JavaScript, it makes for smaller output and the
* browser can handle the output just fine.
*/
void dropNullPlaceholders();
void omitEndingLineFeed();
public: // overridden from Writer
String write(const Value& root) override;
private:
void writeValue(const Value& value);
String document_;
bool yamlCompatibilityEnabled_{false};
bool dropNullPlaceholders_{false};
bool omitEndingLineFeed_{false};
};
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
*human friendly way.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per
*line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value
*types,
* and all the values fit on one lines, then print the array on a single
*line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their
*#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSON_API
StyledWriter : public Writer {
public:
StyledWriter();
~StyledWriter() override = default;
public: // overridden from Writer
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param root Value to serialize.
* \return String containing the JSON document that represents the root value.
*/
String write(const Value& root) override;
private:
void writeValue(const Value& value);
void writeArrayValue(const Value& value);
bool isMultilineArray(const Value& value);
void pushValue(const String& value);
void writeIndent();
void writeWithIndent(const String& value);
void indent();
void unindent();
void writeCommentBeforeValue(const Value& root);
void writeCommentAfterValueOnSameLine(const Value& root);
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
using ChildValues = std::vector<String>;
ChildValues childValues_;
String document_;
String indentString_;
unsigned int rightMargin_{74};
unsigned int indentSize_{3};
bool addChildValues_{false};
};
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
human friendly way,
to a stream rather than to a string.
*
* The rules for line break and indent are as follow:
* - Object value:
* - if empty then print {} without indent and line break
* - if not empty the print '{', line break & indent, print one value per
line
* and then unindent and line break and print '}'.
* - Array value:
* - if empty then print [] without indent and line break
* - if the array contains no object value, empty array or some other value
types,
* and all the values fit on one lines, then print the array on a single
line.
* - otherwise, it the values do not fit on one line, or the array contains
* object or non empty array, then print one value per line.
*
* If the Value have comments then they are outputed according to their
#CommentPlacement.
*
* \sa Reader, Value, Value::setComment()
* \deprecated Use StreamWriterBuilder.
*/
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996) // Deriving from deprecated class
#endif
class JSON_API
StyledStreamWriter {
public:
/**
* \param indentation Each level will be indented by this amount extra.
*/
StyledStreamWriter(String indentation = "\t");
~StyledStreamWriter() = default;
public:
/** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
* \param out Stream to write to. (Can be ostringstream, e.g.)
* \param root Value to serialize.
* \note There is no point in deriving from Writer, since write() should not
* return a value.
*/
void write(OStream& out, const Value& root);
private:
void writeValue(const Value& value);
void writeArrayValue(const Value& value);
bool isMultilineArray(const Value& value);
void pushValue(const String& value);
void writeIndent();
void writeWithIndent(const String& value);
void indent();
void unindent();
void writeCommentBeforeValue(const Value& root);
void writeCommentAfterValueOnSameLine(const Value& root);
static bool hasCommentForValue(const Value& value);
static String normalizeEOL(const String& text);
using ChildValues = std::vector<String>;
ChildValues childValues_;
OStream* document_;
String indentString_;
unsigned int rightMargin_{74};
String indentation_;
bool addChildValues_ : 1;
bool indented_ : 1;
};
#if defined(_MSC_VER)
#pragma warning(pop)
#endif
#if defined(JSON_HAS_INT64)
String JSON_API valueToString(Int value);
String JSON_API valueToString(UInt value);
#endif // if defined(JSON_HAS_INT64)
String JSON_API valueToString(LargestInt value);
String JSON_API valueToString(LargestUInt value);
String JSON_API valueToString(
double value, unsigned int precision = Value::defaultRealPrecision,
PrecisionType precisionType = PrecisionType::significantDigits);
String JSON_API valueToString(bool value);
String JSON_API valueToQuotedString(const char* value);
/// \brief Output using the StyledStreamWriter.
/// \see Json::operator>>()
JSON_API OStream& operator<<(OStream&, const Value& root);
} // namespace Json
#pragma pack(pop)
#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#pragma warning(pop)
#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
#endif // JSON_WRITER_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
#if !defined(JSON_IS_AMALGAMATION)
#include <json/config.h>
#endif
// Also support old flag NO_LOCALE_SUPPORT
#ifdef NO_LOCALE_SUPPORT
#define JSONCPP_NO_LOCALE_SUPPORT
#endif
#ifndef JSONCPP_NO_LOCALE_SUPPORT
#include <clocale>
#endif
/* This header provides common string manipulation support, such as UTF-8,
* portable conversion from/to string...
*
* It is an internal header that must not be exposed.
*/
namespace Json {
static inline char getDecimalPoint() {
#ifdef JSONCPP_NO_LOCALE_SUPPORT
return '\0';
#else
struct lconv* lc = localeconv();
return lc ? *(lc->decimal_point) : '\0';
#endif
}
/// Converts a unicode code-point to UTF-8.
static inline String codePointToUTF8(unsigned int cp) {
String result;
// based on description from http://en.wikipedia.org/wiki/UTF-8
if (cp <= 0x7f) {
result.resize(1);
result[0] = static_cast<char>(cp);
} else if (cp <= 0x7FF) {
result.resize(2);
result[1] = static_cast<char>(0x80 | (0x3f & cp));
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
} else if (cp <= 0xFFFF) {
result.resize(3);
result[2] = static_cast<char>(0x80 | (0x3f & cp));
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
result[0] = static_cast<char>(0xE0 | (0xf & (cp >> 12)));
} else if (cp <= 0x10FFFF) {
result.resize(4);
result[3] = static_cast<char>(0x80 | (0x3f & cp));
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
}
return result;
}
enum {
/// Constant that specify the size of the buffer that must be passed to
/// uintToString.
uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
};
// Defines a char buffer for use with uintToString().
using UIntToStringBuffer = char[uintToStringBufferSize];
/** Converts an unsigned integer to string.
* @param value Unsigned integer to convert to string
* @param current Input/Output string buffer.
* Must have at least uintToStringBufferSize chars free.
*/
static inline void uintToString(LargestUInt value, char*& current) {
*--current = 0;
do {
*--current = static_cast<char>(value % 10U + static_cast<unsigned>('0'));
value /= 10;
} while (value != 0);
}
/** Change ',' to '.' everywhere in buffer.
*
* We had a sophisticated way, but it did not work in WinCE.
* @see https://github.com/open-source-parsers/jsoncpp/pull/9
*/
template <typename Iter> Iter fixNumericLocale(Iter begin, Iter end) {
for (; begin != end; ++begin) {
if (*begin == ',') {
*begin = '.';
}
}
return begin;
}
template <typename Iter> void fixNumericLocaleInput(Iter begin, Iter end) {
char decimalPoint = getDecimalPoint();
if (decimalPoint == '\0' || decimalPoint == '.') {
return;
}
for (; begin != end; ++begin) {
if (*begin == '.') {
*begin = decimalPoint;
}
}
}
/**
* Return iterator that would be the new end of the range [begin,end), if we
* were to delete zeros in the end of string, but not the last zero before '.'.
*/
template <typename Iter>
Iter fixZerosInTheEnd(Iter begin, Iter end, unsigned int precision) {
for (; begin != end; --end) {
if (*(end - 1) != '0') {
return end;
}
// Don't delete the last zero before the decimal point.
if (begin != (end - 1) && begin != (end - 2) && *(end - 2) == '.') {
if (precision) {
return end;
}
return end - 2;
}
}
return end;
}
} // namespace Json
#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,156 @@
// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
// Distributed under MIT license, or public domain if desired and
// recognized in your jurisdiction.
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
// included by json_value.cpp
namespace Json {
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIteratorBase
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIteratorBase::ValueIteratorBase() : current_() {}
ValueIteratorBase::ValueIteratorBase(
const Value::ObjectValues::iterator& current)
: current_(current), isNull_(false) {}
Value& ValueIteratorBase::deref() { return current_->second; }
const Value& ValueIteratorBase::deref() const { return current_->second; }
void ValueIteratorBase::increment() { ++current_; }
void ValueIteratorBase::decrement() { --current_; }
ValueIteratorBase::difference_type
ValueIteratorBase::computeDistance(const SelfType& other) const {
// Iterator for null value are initialized using the default
// constructor, which initialize current_ to the default
// std::map::iterator. As begin() and end() are two instance
// of the default std::map::iterator, they can not be compared.
// To allow this, we handle this comparison specifically.
if (isNull_ && other.isNull_) {
return 0;
}
// Usage of std::distance is not portable (does not compile with Sun Studio 12
// RogueWave STL,
// which is the one used by default).
// Using a portable hand-made version for non random iterator instead:
// return difference_type( std::distance( current_, other.current_ ) );
difference_type myDistance = 0;
for (Value::ObjectValues::iterator it = current_; it != other.current_;
++it) {
++myDistance;
}
return myDistance;
}
bool ValueIteratorBase::isEqual(const SelfType& other) const {
if (isNull_) {
return other.isNull_;
}
return current_ == other.current_;
}
void ValueIteratorBase::copy(const SelfType& other) {
current_ = other.current_;
isNull_ = other.isNull_;
}
Value ValueIteratorBase::key() const {
const Value::CZString czstring = (*current_).first;
if (czstring.data()) {
if (czstring.isStaticString())
return Value(StaticString(czstring.data()));
return Value(czstring.data(), czstring.data() + czstring.length());
}
return Value(czstring.index());
}
UInt ValueIteratorBase::index() const {
const Value::CZString czstring = (*current_).first;
if (!czstring.data())
return czstring.index();
return Value::UInt(-1);
}
String ValueIteratorBase::name() const {
char const* keey;
char const* end;
keey = memberName(&end);
if (!keey)
return String();
return String(keey, end);
}
char const* ValueIteratorBase::memberName() const {
const char* cname = (*current_).first.data();
return cname ? cname : "";
}
char const* ValueIteratorBase::memberName(char const** end) const {
const char* cname = (*current_).first.data();
if (!cname) {
*end = nullptr;
return nullptr;
}
*end = cname + (*current_).first.length();
return cname;
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueConstIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueConstIterator::ValueConstIterator() = default;
ValueConstIterator::ValueConstIterator(
const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {}
ValueConstIterator::ValueConstIterator(ValueIterator const& other)
: ValueIteratorBase(other) {}
ValueConstIterator& ValueConstIterator::
operator=(const ValueIteratorBase& other) {
copy(other);
return *this;
}
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// class ValueIterator
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////
ValueIterator::ValueIterator() = default;
ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
: ValueIteratorBase(current) {}
ValueIterator::ValueIterator(const ValueConstIterator& other)
: ValueIteratorBase(other) {
throwRuntimeError("ConstIterator to Iterator should never be allowed.");
}
ValueIterator::ValueIterator(const ValueIterator& other) = default;
ValueIterator& ValueIterator::operator=(const SelfType& other) {
copy(other);
return *this;
}
} // namespace Json

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
# Copyright (c) 2020 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
!openxr_loader_for_android.pom

View File

@ -0,0 +1,319 @@
// Copyright (c) 2020-2022, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
#include "android_utilities.h"
#ifdef __ANDROID__
#include <wrap/android.net.h>
#include <wrap/android.content.h>
#include <wrap/android.database.h>
#include <json/value.h>
#include <openxr/openxr.h>
#include <sstream>
#include <vector>
#include <android/log.h>
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, "openxr_loader", __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, "openxr_loader", __VA_ARGS__)
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "openxr_loader", __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, "openxr_loader", __VA_ARGS__)
namespace openxr_android {
using wrap::android::content::ContentUris;
using wrap::android::content::Context;
using wrap::android::database::Cursor;
using wrap::android::net::Uri;
using wrap::android::net::Uri_Builder;
// Code in here corresponds roughly to the Java "BrokerContract" class and subclasses.
namespace {
constexpr auto AUTHORITY = "org.khronos.openxr.runtime_broker";
constexpr auto SYSTEM_AUTHORITY = "org.khronos.openxr.system_runtime_broker";
constexpr auto BASE_PATH = "openxr";
constexpr auto ABI_PATH = "abi";
constexpr auto RUNTIMES_PATH = "runtimes";
constexpr const char *getBrokerAuthority(bool systemBroker) { return systemBroker ? SYSTEM_AUTHORITY : AUTHORITY; }
struct BaseColumns {
/**
* The unique ID for a row.
*/
[[maybe_unused]] static constexpr auto ID = "_id";
};
/**
* Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/active URI.
* <p>
* This URI represents a "table" containing at most one item, the currently active runtime. The
* policy of which runtime is chosen to be active (if more than one is installed) is left to the
* content provider.
* <p>
* No sort order is required to be honored by the content provider.
*/
namespace active_runtime {
/**
* Final path component to this URI.
*/
static constexpr auto TABLE_PATH = "active";
/**
* Create a content URI for querying the data on the active runtime for a
* given major version of OpenXR.
*
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
* @param majorVer The major version of OpenXR.
* @param abi The Android ABI name in use.
* @return A content URI for a single item: the active runtime.
*/
static Uri makeContentUri(bool systemBroker, int majorVersion, const char *abi) {
auto builder = Uri_Builder::construct();
builder.scheme("content")
.authority(getBrokerAuthority(systemBroker))
.appendPath(BASE_PATH)
.appendPath(std::to_string(majorVersion))
.appendPath(ABI_PATH)
.appendPath(abi)
.appendPath(RUNTIMES_PATH)
.appendPath(TABLE_PATH);
ContentUris::appendId(builder, 0);
return builder.build();
}
struct Columns : BaseColumns {
/**
* Constant for the PACKAGE_NAME column name
*/
static constexpr auto PACKAGE_NAME = "package_name";
/**
* Constant for the NATIVE_LIB_DIR column name
*/
static constexpr auto NATIVE_LIB_DIR = "native_lib_dir";
/**
* Constant for the SO_FILENAME column name
*/
static constexpr auto SO_FILENAME = "so_filename";
/**
* Constant for the HAS_FUNCTIONS column name.
* <p>
* If this column contains true, you should check the /functions/ URI for that runtime.
*/
static constexpr auto HAS_FUNCTIONS = "has_functions";
};
} // namespace active_runtime
/**
* Contains details for the /openxr/[major_ver]/abi/[abi]/runtimes/[package]/functions URI.
* <p>
* This URI is for package-specific function name remapping. Since this is an optional field in
* the corresponding JSON manifests for OpenXR, it is optional here as well. If the active
* runtime contains "true" in its "has_functions" column, then this table must exist and be
* queryable.
* <p>
* No sort order is required to be honored by the content provider.
*/
namespace functions {
/**
* Final path component to this URI.
*/
static constexpr auto TABLE_PATH = "functions";
/**
* Create a content URI for querying all rows of the function remapping data for a given
* runtime package and major version of OpenXR.
*
* @param systemBroker If the system runtime broker (instead of the installable one) should be queried.
* @param majorVer The major version of OpenXR.
* @param packageName The package name of the runtime.
* @param abi The Android ABI name in use.
* @return A content URI for the entire table: the function remapping for that runtime.
*/
static Uri makeContentUri(bool systemBroker, int majorVersion, std::string const &packageName, const char *abi) {
auto builder = Uri_Builder::construct();
builder.scheme("content")
.authority(getBrokerAuthority(systemBroker))
.appendPath(BASE_PATH)
.appendPath(std::to_string(majorVersion))
.appendPath(ABI_PATH)
.appendPath(abi)
.appendPath(RUNTIMES_PATH)
.appendPath(packageName)
.appendPath(TABLE_PATH);
return builder.build();
}
struct Columns : BaseColumns {
/**
* Constant for the FUNCTION_NAME column name
*/
static constexpr auto FUNCTION_NAME = "function_name";
/**
* Constant for the SYMBOL_NAME column name
*/
static constexpr auto SYMBOL_NAME = "symbol_name";
};
} // namespace functions
} // namespace
static inline jni::Array<std::string> makeArray(std::initializer_list<const char *> &&list) {
auto ret = jni::Array<std::string>{(long)list.size()};
long i = 0;
for (auto &&elt : list) {
ret.setElement(i, elt);
++i;
}
return ret;
}
static constexpr auto TAG = "OpenXR-Loader";
#if defined(__arm__)
static constexpr auto ABI = "armeabi-v7l";
#elif defined(__aarch64__)
static constexpr auto ABI = "arm64-v8a";
#elif defined(__i386__)
static constexpr auto ABI = "x86";
#elif defined(__x86_64__)
static constexpr auto ABI = "x86_64";
#else
#error "Unknown ABI!"
#endif
/// Helper class to generate the jsoncpp object corresponding to a synthetic runtime manifest.
class JsonManifestBuilder {
public:
JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath);
JsonManifestBuilder &function(const std::string &functionName, const std::string &symbolName);
Json::Value build() const { return root_node; }
private:
Json::Value root_node;
};
inline JsonManifestBuilder::JsonManifestBuilder(const std::string &libraryPathParent, const std::string &libraryPath)
: root_node(Json::objectValue) {
root_node["file_format_version"] = "1.0.0";
root_node["instance_extensions"] = Json::Value(Json::arrayValue);
root_node["functions"] = Json::Value(Json::objectValue);
root_node[libraryPathParent] = Json::objectValue;
root_node[libraryPathParent]["library_path"] = libraryPath;
}
inline JsonManifestBuilder &JsonManifestBuilder::function(const std::string &functionName, const std::string &symbolName) {
root_node["functions"][functionName] = symbolName;
return *this;
}
static constexpr const char *getBrokerTypeName(bool systemBroker) { return systemBroker ? "system" : "installable"; }
static int populateFunctions(wrap::android::content::Context const &context, bool systemBroker, const std::string &packageName,
JsonManifestBuilder &builder) {
jni::Array<std::string> projection = makeArray({functions::Columns::FUNCTION_NAME, functions::Columns::SYMBOL_NAME});
auto uri = functions::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), packageName, ABI);
ALOGI("populateFunctions: Querying URI: %s", uri.toString().c_str());
Cursor cursor = context.getContentResolver().query(uri, projection);
if (cursor.isNull()) {
ALOGE("Null cursor when querying content resolver for functions.");
return -1;
}
if (cursor.getCount() < 1) {
ALOGE("Non-null but empty cursor when querying content resolver for functions.");
cursor.close();
return -1;
}
auto functionIndex = cursor.getColumnIndex(functions::Columns::FUNCTION_NAME);
auto symbolIndex = cursor.getColumnIndex(functions::Columns::SYMBOL_NAME);
while (cursor.moveToNext()) {
builder.function(cursor.getString(functionIndex), cursor.getString(symbolIndex));
}
cursor.close();
return 0;
}
/// Get cursor for active runtime, parameterized by whether or not we use the system broker
static bool getActiveRuntimeCursor(wrap::android::content::Context const &context, jni::Array<std::string> const &projection,
bool systemBroker, Cursor &cursor) {
auto uri = active_runtime::makeContentUri(systemBroker, XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), ABI);
ALOGI("getActiveRuntimeCursor: Querying URI: %s", uri.toString().c_str());
try {
cursor = context.getContentResolver().query(uri, projection);
} catch (const std::exception &e) {
ALOGW("Exception when querying %s content resolver: %s", getBrokerTypeName(systemBroker), e.what());
cursor = {};
return false;
}
if (cursor.isNull()) {
ALOGW("Null cursor when querying %s content resolver.", getBrokerTypeName(systemBroker));
cursor = {};
return false;
}
if (cursor.getCount() < 1) {
ALOGW("Non-null but empty cursor when querying %s content resolver.", getBrokerTypeName(systemBroker));
cursor.close();
cursor = {};
return false;
}
return true;
}
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest) {
jni::Array<std::string> projection = makeArray({active_runtime::Columns::PACKAGE_NAME, active_runtime::Columns::NATIVE_LIB_DIR,
active_runtime::Columns::SO_FILENAME, active_runtime::Columns::HAS_FUNCTIONS});
// First, try getting the installable broker's provider
bool systemBroker = false;
Cursor cursor;
if (!getActiveRuntimeCursor(context, projection, systemBroker, cursor)) {
// OK, try the system broker as a fallback.
systemBroker = true;
getActiveRuntimeCursor(context, projection, systemBroker, cursor);
}
if (cursor.isNull()) {
// Couldn't find either broker
ALOGE("Could access neither the installable nor system runtime broker.");
return -1;
}
cursor.moveToFirst();
auto filename = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::SO_FILENAME));
auto libDir = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::NATIVE_LIB_DIR));
auto packageName = cursor.getString(cursor.getColumnIndex(active_runtime::Columns::PACKAGE_NAME));
auto hasFunctions = cursor.getInt(cursor.getColumnIndex(active_runtime::Columns::HAS_FUNCTIONS)) == 1;
__android_log_print(ANDROID_LOG_INFO, TAG, "Got runtime: package: %s, so filename: %s, native lib dir: %s, has functions: %s",
packageName.c_str(), libDir.c_str(), filename.c_str(), (hasFunctions ? "yes" : "no"));
auto lib_path = libDir + "/" + filename;
cursor.close();
JsonManifestBuilder builder{"runtime", lib_path};
if (hasFunctions) {
int result = populateFunctions(context, systemBroker, packageName, builder);
if (result != 0) {
return result;
}
}
virtualManifest = builder.build();
return 0;
}
} // namespace openxr_android
#endif // __ANDROID__

View File

@ -0,0 +1,32 @@
// Copyright (c) 2020-2022, The Khronos Group Inc.
// Copyright (c) 2020-2021, Collabora, Ltd.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
#pragma once
#ifdef __ANDROID__
#include "wrap/android.content.h"
#include <string>
namespace Json {
class Value;
} // namespace Json
namespace openxr_android {
using wrap::android::content::Context;
/*!
* Find the single active OpenXR runtime on the system, and return a constructed JSON object representing it.
*
* @param context An Android context, preferably an Activity Context.
* @param[out] virtualManifest The Json::Value to fill with the virtual manifest.
*
* @return 0 on success, something else on failure.
*/
int getActiveRuntimeVirtualManifest(wrap::android::content::Context const &context, Json::Value &virtualManifest);
} // namespace openxr_android
#endif // __ANDROID__

View File

@ -0,0 +1,399 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#include "api_layer_interface.hpp"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "manifest_file.hpp"
#include "platform_utils.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#define OPENXR_ENABLE_LAYERS_ENV_VAR "XR_ENABLE_API_LAYERS"
// Add any layers defined in the loader layer environment variable.
static void AddEnvironmentApiLayers(std::vector<std::string>& enabled_layers) {
std::string layers = PlatformUtilsGetEnv(OPENXR_ENABLE_LAYERS_ENV_VAR);
std::size_t last_found = 0;
std::size_t found = layers.find_first_of(PATH_SEPARATOR);
std::string cur_search;
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
cur_search = layers.substr(last_found, found - last_found);
enabled_layers.push_back(cur_search);
last_found = found + 1;
found = layers.find_first_of(PATH_SEPARATOR, last_found);
}
// If there's something remaining in the string, copy it over
if (last_found < layers.size()) {
cur_search = layers.substr(last_found);
enabled_layers.push_back(cur_search);
}
}
XrResult ApiLayerInterface::GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count,
uint32_t* outgoing_count, XrApiLayerProperties* api_layer_properties) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
uint32_t manifest_count = 0;
// Validate props struct before proceeding
if (0 < incoming_count && nullptr != api_layer_properties) {
for (uint32_t i = 0; i < incoming_count; i++) {
if (XR_TYPE_API_LAYER_PROPERTIES != api_layer_properties[i].type) {
LoaderLogger::LogErrorMessage(openxr_command,
"VUID-XrApiLayerProperties-type-type: unknown type in api_layer_properties");
return XR_ERROR_VALIDATION_FAILURE;
}
}
}
// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
// and the function sets elementCountOutput." - 2.11
if (nullptr == outgoing_count) {
return XR_ERROR_VALIDATION_FAILURE;
}
// Find any implicit layers which we may need to report information for.
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCEEDED(result)) {
// Find any explicit layers which we may need to report information for.
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
}
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage(openxr_command,
"ApiLayerInterface::GetApiLayerProperties - failed searching for API layer manifest files");
return result;
}
manifest_count = static_cast<uint32_t>(manifest_files.size());
if (nullptr == outgoing_count) {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
"VUID-xrEnumerateApiLayerProperties-propertyCountOutput-parameter: null propertyCountOutput");
return XR_ERROR_VALIDATION_FAILURE;
}
*outgoing_count = manifest_count;
if (0 == incoming_count) {
// capacity check only
return XR_SUCCESS;
}
if (nullptr == api_layer_properties) {
// incoming_count is not 0 BUT the api_layer_properties is NULL
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
"VUID-xrEnumerateApiLayerProperties-properties-parameter: non-zero capacity but null array");
return XR_ERROR_VALIDATION_FAILURE;
}
if (incoming_count < manifest_count) {
LoaderLogger::LogErrorMessage(
"xrEnumerateInstanceExtensionProperties",
"VUID-xrEnumerateApiLayerProperties-propertyCapacityInput-parameter: insufficient space in array");
return XR_ERROR_SIZE_INSUFFICIENT;
}
for (uint32_t prop = 0; prop < incoming_count && prop < manifest_count; ++prop) {
manifest_files[prop]->PopulateApiLayerProperties(api_layer_properties[prop]);
}
return XR_SUCCESS;
}
XrResult ApiLayerInterface::GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
std::vector<XrExtensionProperties>& extension_properties) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> manifest_files;
// If a layer name is supplied, only use the information out of that one layer
if (nullptr != layer_name && 0 != strlen(layer_name)) {
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCEEDED(result)) {
// Find any explicit layers which we may need to report information for.
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, manifest_files);
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage(
openxr_command,
"ApiLayerInterface::GetInstanceExtensionProperties - failed searching for API layer manifest files");
return result;
}
bool found = false;
auto num_files = static_cast<uint32_t>(manifest_files.size());
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
// If a layer with the provided name exists, get it's instance extension information.
if (manifest_files[man_file]->LayerName() == layer_name) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
found = true;
break;
}
}
// If nothing found, report 0
if (!found) {
return XR_ERROR_API_LAYER_NOT_PRESENT;
}
}
// Otherwise, we want to add only implicit API layers and explicit API layers enabled using the environment variables
} else {
XrResult result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, manifest_files);
if (XR_SUCCEEDED(result)) {
// Find any environmentally enabled explicit layers. If they're present, treat them like implicit layers
// since we know that they're going to be enabled.
std::vector<std::string> env_enabled_layers;
AddEnvironmentApiLayers(env_enabled_layers);
if (!env_enabled_layers.empty()) {
std::vector<std::unique_ptr<ApiLayerManifestFile>> exp_layer_man_files = {};
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, exp_layer_man_files);
if (XR_SUCCEEDED(result)) {
for (auto& exp_layer_man_file : exp_layer_man_files) {
for (std::string& enabled_layer : env_enabled_layers) {
// If this is an enabled layer, transfer it over to the manifest list.
if (enabled_layer == exp_layer_man_file->LayerName()) {
manifest_files.push_back(std::move(exp_layer_man_file));
break;
}
}
}
}
}
}
// Grab the layer instance extensions information
auto num_files = static_cast<uint32_t>(manifest_files.size());
for (uint32_t man_file = 0; man_file < num_files; ++man_file) {
manifest_files[man_file]->GetInstanceExtensionProperties(extension_properties);
}
}
return XR_SUCCESS;
}
XrResult ApiLayerInterface::LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
const char* const* enabled_api_layer_names,
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces) {
XrResult last_error = XR_SUCCESS;
std::unordered_set<std::string> layers_already_found;
bool any_loaded = false;
std::vector<std::unique_ptr<ApiLayerManifestFile>> enabled_layer_manifest_files_in_init_order = {};
// Find any implicit layers.
XrResult result =
ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_IMPLICIT_API_LAYER, enabled_layer_manifest_files_in_init_order);
for (const auto& enabled_layer_manifest_file : enabled_layer_manifest_files_in_init_order) {
layers_already_found.insert(enabled_layer_manifest_file->LayerName());
}
// Find any explicit layers.
std::vector<std::unique_ptr<ApiLayerManifestFile>> explicit_layer_manifest_files = {};
if (XR_SUCCEEDED(result)) {
result = ApiLayerManifestFile::FindManifestFiles(MANIFEST_TYPE_EXPLICIT_API_LAYER, explicit_layer_manifest_files);
}
bool found_all_layers = true;
if (XR_SUCCEEDED(result)) {
// Put all explicit and then xrCreateInstance enabled layers into a string vector
std::vector<std::string> enabled_explicit_api_layer_names = {};
AddEnvironmentApiLayers(enabled_explicit_api_layer_names);
if (enabled_api_layer_count > 0) {
if (nullptr == enabled_api_layer_names) {
LoaderLogger::LogErrorMessage(
"xrCreateInstance",
"VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter: enabledApiLayerCount is non-0 but array is NULL");
LoaderLogger::LogErrorMessage(
"xrCreateInstance", "VUID-xrCreateInstance-info-parameter: something wrong with XrInstanceCreateInfo contents");
return XR_ERROR_VALIDATION_FAILURE;
}
std::copy(enabled_api_layer_names, enabled_api_layer_names + enabled_api_layer_count,
std::back_inserter(enabled_explicit_api_layer_names));
}
// add explicit layers to list of layers to enable
for (const auto& layer_name : enabled_explicit_api_layer_names) {
bool found_this_layer = false;
for (auto it = explicit_layer_manifest_files.begin(); it != explicit_layer_manifest_files.end();) {
bool erased_layer_manifest_file = false;
if (layers_already_found.count(layer_name) > 0) {
found_this_layer = true;
} else if (layer_name == (*it)->LayerName()) {
found_this_layer = true;
layers_already_found.insert(layer_name);
enabled_layer_manifest_files_in_init_order.push_back(std::move(*it));
it = explicit_layer_manifest_files.erase(it);
erased_layer_manifest_file = true;
}
if (!erased_layer_manifest_file) {
it++;
}
}
// If even one of the layers wasn't found, we want to return an error
if (!found_this_layer) {
found_all_layers = false;
std::string error_message = "ApiLayerInterface::LoadApiLayers - failed to find layer ";
error_message += layer_name;
LoaderLogger::LogErrorMessage(openxr_command, error_message);
}
}
}
for (std::unique_ptr<ApiLayerManifestFile>& manifest_file : enabled_layer_manifest_files_in_init_order) {
LoaderPlatformLibraryHandle layer_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
if (nullptr == layer_library) {
if (!any_loaded) {
last_error = XR_ERROR_FILE_ACCESS_ERROR;
}
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
warning_message += manifest_file->LayerName();
warning_message += ", failed to load with message \"";
warning_message += library_message;
warning_message += "\"";
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
continue;
}
// Get and settle on an layer interface version (using any provided name if required).
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderApiLayerInterface");
auto negotiate = reinterpret_cast<PFN_xrNegotiateLoaderApiLayerInterface>(
LoaderPlatformLibraryGetProcAddr(layer_library, function_name));
if (nullptr == negotiate) {
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
<< " because negotiation function " << function_name << " was not found";
LoaderLogger::LogErrorMessage(openxr_command, oss.str());
LoaderPlatformLibraryClose(layer_library);
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
continue;
}
// Loader info for negotiation
XrNegotiateLoaderInfo loader_info = {};
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
loader_info.minInterfaceVersion = 1;
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_API_LAYER_VERSION;
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
// Set up the layer return structure
XrNegotiateApiLayerRequest api_layer_info = {};
api_layer_info.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST;
api_layer_info.structVersion = XR_API_LAYER_INFO_STRUCT_VERSION;
api_layer_info.structSize = sizeof(XrNegotiateApiLayerRequest);
XrResult res = negotiate(&loader_info, manifest_file->LayerName().c_str(), &api_layer_info);
// If we supposedly succeeded, but got a nullptr for getInstanceProcAddr
// then something still went wrong, so return with an error.
if (XR_SUCCEEDED(res) && nullptr == api_layer_info.getInstanceProcAddr) {
std::string warning_message = "ApiLayerInterface::LoadApiLayers skipping layer ";
warning_message += manifest_file->LayerName();
warning_message += ", negotiation did not return a valid getInstanceProcAddr";
LoaderLogger::LogWarningMessage(openxr_command, warning_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
}
if (XR_FAILED(res)) {
if (!any_loaded) {
last_error = res;
}
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers skipping layer " << manifest_file->LayerName()
<< " due to failed negotiation with error " << res;
LoaderLogger::LogWarningMessage(openxr_command, oss.str());
LoaderPlatformLibraryClose(layer_library);
continue;
}
{
std::ostringstream oss;
oss << "ApiLayerInterface::LoadApiLayers succeeded loading layer " << manifest_file->LayerName()
<< " using interface version " << api_layer_info.layerInterfaceVersion << " and OpenXR API version "
<< XR_VERSION_MAJOR(api_layer_info.layerApiVersion) << "." << XR_VERSION_MINOR(api_layer_info.layerApiVersion);
LoaderLogger::LogInfoMessage(openxr_command, oss.str());
}
// Grab the list of extensions this layer supports for easy filtering after the
// xrCreateInstance call
std::vector<std::string> supported_extensions;
std::vector<XrExtensionProperties> extension_properties;
manifest_file->GetInstanceExtensionProperties(extension_properties);
supported_extensions.reserve(extension_properties.size());
for (XrExtensionProperties& ext_prop : extension_properties) {
supported_extensions.emplace_back(ext_prop.extensionName);
}
// Add this API layer to the vector
api_layer_interfaces.emplace_back(new ApiLayerInterface(manifest_file->LayerName(), layer_library, supported_extensions,
api_layer_info.getInstanceProcAddr,
api_layer_info.createApiLayerInstance));
// If we load one, clear all errors.
any_loaded = true;
last_error = XR_SUCCESS;
}
// Set error here to preserve prior error behavior
if (!found_all_layers) {
last_error = XR_ERROR_API_LAYER_NOT_PRESENT;
}
// If we failed catastrophically for some reason, clean up everything.
if (XR_FAILED(last_error)) {
api_layer_interfaces.clear();
}
return last_error;
}
ApiLayerInterface::ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
std::vector<std::string>& supported_extensions,
PFN_xrGetInstanceProcAddr get_instance_proc_addr,
PFN_xrCreateApiLayerInstance create_api_layer_instance)
: _layer_name(layer_name),
_layer_library(layer_library),
_get_instance_proc_addr(get_instance_proc_addr),
_create_api_layer_instance(create_api_layer_instance),
_supported_extensions(supported_extensions) {}
ApiLayerInterface::~ApiLayerInterface() {
std::string info_message = "ApiLayerInterface being destroyed for layer ";
info_message += _layer_name;
LoaderLogger::LogInfoMessage("", info_message);
LoaderPlatformLibraryClose(_layer_library);
}
bool ApiLayerInterface::SupportsExtension(const std::string& extension_name) const {
bool found_prop = false;
for (const std::string& supported_extension : _supported_extensions) {
if (supported_extension == extension_name) {
found_prop = true;
break;
}
}
return found_prop;
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <string>
#include <vector>
#include <memory>
#include <openxr/openxr.h>
#include "loader_platform.hpp"
#include "loader_interfaces.h"
struct XrGeneratedDispatchTable;
class ApiLayerInterface {
public:
// Factory method
static XrResult LoadApiLayers(const std::string& openxr_command, uint32_t enabled_api_layer_count,
const char* const* enabled_api_layer_names,
std::vector<std::unique_ptr<ApiLayerInterface>>& api_layer_interfaces);
// Static queries
static XrResult GetApiLayerProperties(const std::string& openxr_command, uint32_t incoming_count, uint32_t* outgoing_count,
XrApiLayerProperties* api_layer_properties);
static XrResult GetInstanceExtensionProperties(const std::string& openxr_command, const char* layer_name,
std::vector<XrExtensionProperties>& extension_properties);
ApiLayerInterface(const std::string& layer_name, LoaderPlatformLibraryHandle layer_library,
std::vector<std::string>& supported_extensions, PFN_xrGetInstanceProcAddr get_instance_proc_addr,
PFN_xrCreateApiLayerInstance create_api_layer_instance);
virtual ~ApiLayerInterface();
PFN_xrGetInstanceProcAddr GetInstanceProcAddrFuncPointer() { return _get_instance_proc_addr; }
PFN_xrCreateApiLayerInstance GetCreateApiLayerInstanceFuncPointer() { return _create_api_layer_instance; }
std::string LayerName() { return _layer_name; }
// Generated methods
bool SupportsExtension(const std::string& extension_name) const;
private:
std::string _layer_name;
LoaderPlatformLibraryHandle _layer_library;
PFN_xrGetInstanceProcAddr _get_instance_proc_addr;
PFN_xrCreateApiLayerInstance _create_api_layer_instance;
std::vector<std::string> _supported_extensions;
};

View File

@ -0,0 +1,40 @@
// Copyright (c) 2019-2022, The Khronos Group Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
// Provides protection for C ABI functions if standard library functions may throw.
#pragma once
#ifdef OPENXR_HAVE_COMMON_CONFIG
#include "common_config.h"
#endif // OPENXR_HAVE_COMMON_CONFIG
#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING
#define XRLOADER_ABI_TRY
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM
#define XRLOADER_ABI_CATCH_FALLBACK
#else
#include <stdexcept>
#define XRLOADER_ABI_TRY try
#define XRLOADER_ABI_CATCH_BAD_ALLOC_OOM \
catch (const std::bad_alloc&) { \
LoaderLogger::LogErrorMessage("", "failed allocating memory"); \
return XR_ERROR_OUT_OF_MEMORY; \
}
#define XRLOADER_ABI_CATCH_FALLBACK \
catch (const std::exception& e) { \
LoaderLogger::LogErrorMessage("", "Unknown failure: " + std::string(e.what())); \
return XR_ERROR_RUNTIME_FAILURE; \
} \
catch (...) { \
LoaderLogger::LogErrorMessage("", "Unknown failure"); \
return XR_ERROR_RUNTIME_FAILURE; \
}
#endif

View File

@ -0,0 +1,847 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
//
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#include "api_layer_interface.hpp"
#include "exception_handling.hpp"
#include "hex_and_handles.h"
#include "loader_instance.hpp"
#include "loader_logger_recorders.hpp"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_generated_loader.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
// Global loader lock to:
// 1. Ensure ActiveLoaderInstance get and set operations are done atomically.
// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use.
std::mutex &GetGlobalLoaderMutex() {
static std::mutex loader_mutex;
return loader_mutex;
}
// Prototypes for the debug utils calls used internally.
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineCreateDebugUtilsMessengerEXT(
XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo, XrDebugUtilsMessengerEXT *messenger);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
// Terminal functions needed by xrCreateInstance.
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance, const char *, PFN_xrVoidFunction *);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *, XrInstance *);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *,
const struct XrApiLayerCreateInfo *, XrInstance *);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance, const XrDebugUtilsObjectNameInfoEXT *);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance,
const XrDebugUtilsMessengerCreateInfoEXT *,
XrDebugUtilsMessengerEXT *);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT);
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT *callbackData);
// Utility template function meant to validate if a fixed size string contains
// a null-terminator.
template <size_t max_length>
inline bool IsMissingNullTerminator(const char (&str)[max_length]) {
for (size_t index = 0; index < max_length; ++index) {
if (str[index] == '\0') {
return false;
}
}
return true;
}
// ---- Core 1.0 manual loader trampoline functions
#ifdef XR_KHR_LOADER_INIT_SUPPORT // platforms that support XR_KHR_loader_init.
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrInitializeLoaderKHR", "Entering loader trampoline");
return InitializeLoader(loaderInitInfo);
}
XRLOADER_ABI_CATCH_FALLBACK
#endif
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
uint32_t *propertyCountOutput,
XrApiLayerProperties *properties) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");
// Make sure only one thread is attempting to read the JSON files at a time.
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,
propertyCountOutput, properties);
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage("xrEnumerateApiLayerProperties", "Failed ApiLayerInterface::GetApiLayerProperties");
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t propertyCapacityInput, uint32_t *propertyCountOutput,
XrExtensionProperties *properties) XRLOADER_ABI_TRY {
bool just_layer_properties = false;
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Entering loader trampoline");
// "Independent of elementCapacityInput or elements parameters, elementCountOutput must be a valid pointer,
// and the function sets elementCountOutput." - 2.11
if (nullptr == propertyCountOutput) {
return XR_ERROR_VALIDATION_FAILURE;
}
if (nullptr != layerName && 0 != strlen(layerName)) {
// Application is only interested in layer's properties, not all of them.
just_layer_properties = true;
}
std::vector<XrExtensionProperties> extension_properties = {};
XrResult result;
{
// Make sure the runtime isn't unloaded while this call is in progress.
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
// Get the layer extension properties
result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,
extension_properties);
if (XR_SUCCEEDED(result) && !just_layer_properties) {
// If not specific to a layer, get the runtime extension properties
result = RuntimeInterface::LoadRuntime("xrEnumerateInstanceExtensionProperties");
if (XR_SUCCEEDED(result)) {
RuntimeInterface::GetRuntime().GetInstanceExtensionProperties(extension_properties);
} else {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties",
"Failed to find default runtime with RuntimeInterface::LoadRuntime()");
}
}
}
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage("xrEnumerateInstanceExtensionProperties", "Failed querying extension properties");
return result;
}
// If this is not in reference to a specific layer, then add the loader-specific extension properties as well.
// These are extensions that the loader directly supports.
if (!just_layer_properties) {
for (const XrExtensionProperties &loader_prop : LoaderInstance::LoaderSpecificExtensions()) {
bool found_prop = false;
for (XrExtensionProperties &existing_prop : extension_properties) {
if (0 == strcmp(existing_prop.extensionName, loader_prop.extensionName)) {
found_prop = true;
// Use the loader version if it is newer
if (existing_prop.extensionVersion < loader_prop.extensionVersion) {
existing_prop.extensionVersion = loader_prop.extensionVersion;
}
break;
}
}
// Only add extensions not supported by the loader
if (!found_prop) {
extension_properties.push_back(loader_prop);
}
}
}
auto num_extension_properties = static_cast<uint32_t>(extension_properties.size());
if (propertyCapacityInput == 0) {
*propertyCountOutput = num_extension_properties;
} else if (nullptr != properties) {
if (propertyCapacityInput < num_extension_properties) {
*propertyCountOutput = num_extension_properties;
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-propertyCountOutput-parameter",
"xrEnumerateInstanceExtensionProperties", "insufficient space in array");
return XR_ERROR_SIZE_INSUFFICIENT;
}
uint32_t num_to_copy = num_extension_properties;
// Determine how many extension properties we can copy over
if (propertyCapacityInput < num_to_copy) {
num_to_copy = propertyCapacityInput;
}
bool properties_valid = true;
for (uint32_t prop = 0; prop < propertyCapacityInput && prop < extension_properties.size(); ++prop) {
if (XR_TYPE_EXTENSION_PROPERTIES != properties[prop].type) {
properties_valid = false;
LoaderLogger::LogValidationErrorMessage("VUID-XrExtensionProperties-type-type",
"xrEnumerateInstanceExtensionProperties", "unknown type in properties");
}
if (properties_valid) {
properties[prop] = extension_properties[prop];
}
}
if (!properties_valid) {
LoaderLogger::LogValidationErrorMessage("VUID-xrEnumerateInstanceExtensionProperties-properties-parameter",
"xrEnumerateInstanceExtensionProperties", "invalid properties");
return XR_ERROR_VALIDATION_FAILURE;
}
if (nullptr != propertyCountOutput) {
*propertyCountOutput = num_to_copy;
}
} else {
// incoming_count is not 0 BUT the properties is NULL
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderLogger::LogVerboseMessage("xrEnumerateInstanceExtensionProperties", "Completed loader trampoline");
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCreateInfo *info,
XrInstance *instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader trampoline");
if (nullptr == info) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance", "must be non-NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
// If application requested OpenXR API version is higher than the loader version, then we need to throw
// an error.
uint16_t app_major = XR_VERSION_MAJOR(info->applicationInfo.apiVersion); // NOLINT
uint16_t app_minor = XR_VERSION_MINOR(info->applicationInfo.apiVersion); // NOLINT
uint16_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION); // NOLINT
uint16_t loader_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION); // NOLINT
if (app_major > loader_major || (app_major == loader_major && app_minor > loader_minor)) {
std::ostringstream oss;
oss << "xrCreateInstance called with invalid API version " << app_major << "." << app_minor
<< ". Max supported version is " << loader_major << "." << loader_minor;
LoaderLogger::LogErrorMessage("xrCreateInstance", oss.str());
return XR_ERROR_API_VERSION_UNSUPPORTED;
}
if (nullptr == instance) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-instance-parameter", "xrCreateInstance", "must be non-NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
// Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.
std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());
// Check if there is already an XrInstance that is alive. If so, another instance cannot be created.
// The loader does not support multiple simultaneous instances because the loader is intended to be
// usable by apps using future OpenXR APIs (through xrGetInstanceProcAddr). Because the loader would
// not be aware of new handle types, it would not be able to look up the appropriate dispatch table
// in some cases.
if (ActiveLoaderInstance::IsAvailable()) { // If there is an XrInstance already alive.
LoaderLogger::LogErrorMessage("xrCreateInstance", "Loader does not support simultaneous XrInstances");
return XR_ERROR_LIMIT_REACHED;
}
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces;
XrResult result;
// Make sure only one thread is attempting to read the JSON files and use the instance.
{
// Load the available runtime
result = RuntimeInterface::LoadRuntime("xrCreateInstance");
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading runtime information");
} else {
// Load the appropriate layers
result = ApiLayerInterface::LoadApiLayers("xrCreateInstance", info->enabledApiLayerCount, info->enabledApiLayerNames,
api_layer_interfaces);
if (XR_FAILED(result)) {
LoaderLogger::LogErrorMessage("xrCreateInstance", "Failed loading layer information");
}
}
}
// Create the loader instance (only send down first runtime interface)
LoaderInstance *loader_instance = nullptr;
if (XR_SUCCEEDED(result)) {
std::unique_ptr<LoaderInstance> owned_loader_instance;
result = LoaderInstance::CreateInstance(LoaderXrTermGetInstanceProcAddr, LoaderXrTermCreateInstance,
LoaderXrTermCreateApiLayerInstance, std::move(api_layer_interfaces), info,
&owned_loader_instance);
if (XR_SUCCEEDED(result)) {
loader_instance = owned_loader_instance.get();
result = ActiveLoaderInstance::Set(std::move(owned_loader_instance), "xrCreateInstance");
}
}
if (XR_SUCCEEDED(result)) {
// Create a debug utils messenger if the create structure is in the "next" chain
const auto *next_header = reinterpret_cast<const XrBaseInStructure *>(info->next);
const XrDebugUtilsMessengerCreateInfoEXT *dbg_utils_create_info = nullptr;
while (next_header != nullptr) {
if (next_header->type == XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) {
LoaderLogger::LogInfoMessage("xrCreateInstance", "Found XrDebugUtilsMessengerCreateInfoEXT in \'next\' chain.");
dbg_utils_create_info = reinterpret_cast<const XrDebugUtilsMessengerCreateInfoEXT *>(next_header);
XrDebugUtilsMessengerEXT messenger;
result = LoaderTrampolineCreateDebugUtilsMessengerEXT(loader_instance->GetInstanceHandle(), dbg_utils_create_info,
&messenger);
if (XR_FAILED(result)) {
return XR_ERROR_VALIDATION_FAILURE;
}
loader_instance->SetDefaultDebugUtilsMessenger(messenger);
break;
}
next_header = reinterpret_cast<const XrBaseInStructure *>(next_header->next);
}
}
if (XR_FAILED(result)) {
// Ensure the global loader instance and runtime are destroyed if something went wrong.
ActiveLoaderInstance::Remove();
RuntimeInterface::UnloadRuntime("xrCreateInstance");
LoaderLogger::LogErrorMessage("xrCreateInstance", "xrCreateInstance failed");
} else {
*instance = loader_instance->GetInstanceHandle();
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader trampoline");
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader trampoline");
// Runtimes may detect XR_NULL_HANDLE provided as a required handle parameter and return XR_ERROR_HANDLE_INVALID. - 2.9
if (XR_NULL_HANDLE == instance) {
LoaderLogger::LogErrorMessage("xrDestroyInstance", "Instance handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
// Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance");
if (XR_FAILED(result)) {
return result;
}
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
// If we allocated a default debug utils messenger, free it
XrDebugUtilsMessengerEXT messenger = loader_instance->DefaultDebugUtilsMessenger();
if (messenger != XR_NULL_HANDLE) {
LoaderTrampolineDestroyDebugUtilsMessengerEXT(messenger);
}
// Now destroy the instance
if (XR_FAILED(dispatch_table->DestroyInstance(instance))) {
LoaderLogger::LogErrorMessage("xrDestroyInstance", "Unknown error occurred calling down chain");
}
// Get rid of the loader instance. This will make it possible to create another instance in the future.
ActiveLoaderInstance::Remove();
// Lock the instance create/destroy mutex
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader trampoline");
// Finally, unload the runtime if necessary
RuntimeInterface::UnloadRuntime("xrDestroyInstance");
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Core 1.0 manual loader terminator functions
// Validate that the applicationInfo structure in the XrInstanceCreateInfo is valid.
static XrResult ValidateApplicationInfo(const XrApplicationInfo &info) {
if (IsMissingNullTerminator<XR_MAX_APPLICATION_NAME_SIZE>(info.applicationName)) {
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-applicationName-parameter", "xrCreateInstance",
"application name missing NULL terminator.");
return XR_ERROR_NAME_INVALID;
}
if (IsMissingNullTerminator<XR_MAX_ENGINE_NAME_SIZE>(info.engineName)) {
LoaderLogger::LogValidationErrorMessage("VUID-XrApplicationInfo-engineName-parameter", "xrCreateInstance",
"engine name missing NULL terminator.");
return XR_ERROR_NAME_INVALID;
}
if (strlen(info.applicationName) == 0) {
LoaderLogger::LogErrorMessage("xrCreateInstance",
"VUID-XrApplicationInfo-engineName-parameter: application name can not be empty.");
return XR_ERROR_NAME_INVALID;
}
return XR_SUCCESS;
}
// Validate that the XrInstanceCreateInfo is valid
static XrResult ValidateInstanceCreateInfo(const XrInstanceCreateInfo *info) {
// Should have a valid 'type'
if (XR_TYPE_INSTANCE_CREATE_INFO != info->type) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-type-type", "xrCreateInstance",
"expected XR_TYPE_INSTANCE_CREATE_INFO.");
return XR_ERROR_VALIDATION_FAILURE;
}
// Flags must be 0
if (0 != info->createFlags) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-createFlags-zerobitmask", "xrCreateInstance",
"flags must be 0.");
return XR_ERROR_VALIDATION_FAILURE;
}
// ApplicationInfo struct must be valid
XrResult result = ValidateApplicationInfo(info->applicationInfo);
if (XR_FAILED(result)) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-applicationInfo-parameter", "xrCreateInstance",
"info->applicationInfo is not valid.");
return result;
}
// VUID-XrInstanceCreateInfo-enabledApiLayerNames-parameter already tested in LoadApiLayers()
if ((info->enabledExtensionCount != 0u) && nullptr == info->enabledExtensionNames) {
LoaderLogger::LogValidationErrorMessage("VUID-XrInstanceCreateInfo-enabledExtensionNames-parameter", "xrCreateInstance",
"enabledExtensionCount is non-0 but array is NULL");
return XR_ERROR_VALIDATION_FAILURE;
}
return XR_SUCCESS;
}
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateInstance(const XrInstanceCreateInfo *createInfo,
XrInstance *instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering loader terminator");
XrResult result = ValidateInstanceCreateInfo(createInfo);
if (XR_FAILED(result)) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateInstance-info-parameter", "xrCreateInstance",
"something wrong with XrInstanceCreateInfo contents");
return result;
}
result = RuntimeInterface::GetRuntime().CreateInstance(createInfo, instance);
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateApiLayerInstance(const XrInstanceCreateInfo *info,
const struct XrApiLayerCreateInfo * /*apiLayerInfo*/,
XrInstance *instance) {
return LoaderXrTermCreateInstance(info, instance);
}
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyInstance(XrInstance instance) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Entering loader terminator");
LoaderLogger::GetInstance().RemoveLogRecordersForXrInstance(instance);
XrResult result = RuntimeInterface::GetRuntime().DestroyInstance(instance);
LoaderLogger::LogVerboseMessage("xrDestroyInstance", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermGetInstanceProcAddr(XrInstance instance, const char *name,
PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
// A few instance commands need to go through a loader terminator.
// Otherwise, go directly to the runtime version of the command if it exists.
// But first set the function pointer to NULL so that the fall-through below actually works.
*function = nullptr;
// NOTE: ActiveLoaderInstance cannot be used in this function because it is called before an instance is made active.
if (0 == strcmp(name, "xrGetInstanceProcAddr")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermGetInstanceProcAddr);
} else if (0 == strcmp(name, "xrCreateInstance")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateInstance);
} else if (0 == strcmp(name, "xrDestroyInstance")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyInstance);
} else if (0 == strcmp(name, "xrSetDebugUtilsObjectNameEXT")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSetDebugUtilsObjectNameEXT);
} else if (0 == strcmp(name, "xrCreateDebugUtilsMessengerEXT")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateDebugUtilsMessengerEXT);
} else if (0 == strcmp(name, "xrDestroyDebugUtilsMessengerEXT")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermDestroyDebugUtilsMessengerEXT);
} else if (0 == strcmp(name, "xrSubmitDebugUtilsMessageEXT")) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermSubmitDebugUtilsMessageEXT);
} else if (0 == strcmp(name, "xrCreateApiLayerInstance")) {
// Special layer version of xrCreateInstance terminator. If we get called this by a layer,
// we simply re-direct the information back into the standard xrCreateInstance terminator.
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrTermCreateApiLayerInstance);
}
if (nullptr != *function) {
return XR_SUCCESS;
}
return RuntimeInterface::GetInstanceProcAddr(instance, name, function);
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Extension manual loader trampoline functions
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderTrampolineCreateDebugUtilsMessengerEXT(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader trampoline");
if (instance == XR_NULL_HANDLE) {
LoaderLogger::LogErrorMessage("xrCreateDebugUtilsMessengerEXT", "Instance handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateDebugUtilsMessengerEXT");
if (XR_FAILED(result)) {
return result;
}
result = loader_instance->DispatchTable()->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader trampoline");
return result;
}
XRLOADER_ABI_CATCH_BAD_ALLOC_OOM XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderTrampolineDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
// TODO: get instance from messenger in loader
// Also, is the loader really doing all this every call?
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader trampoline");
if (messenger == XR_NULL_HANDLE) {
LoaderLogger::LogErrorMessage("xrDestroyDebugUtilsMessengerEXT", "Messenger handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyDebugUtilsMessengerEXT");
if (XR_FAILED(result)) {
return result;
}
result = loader_instance->DispatchTable()->DestroyDebugUtilsMessengerEXT(messenger);
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader trampoline");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
if (session == XR_NULL_HANDLE) {
LoaderLogger::LogErrorMessage("xrSessionBeginDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
if (nullptr == labelInfo) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionBeginDebugUtilsLabelRegionEXT-labelInfo-parameter",
"xrSessionBeginDebugUtilsLabelRegionEXT", "labelInfo must be non-NULL",
{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionBeginDebugUtilsLabelRegionEXT");
if (XR_FAILED(result)) {
return result;
}
LoaderLogger::GetInstance().BeginLabelRegion(session, labelInfo);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionBeginDebugUtilsLabelRegionEXT) {
return dispatch_table->SessionBeginDebugUtilsLabelRegionEXT(session, labelInfo);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT(XrSession session) XRLOADER_ABI_TRY {
if (session == XR_NULL_HANDLE) {
LoaderLogger::LogErrorMessage("xrSessionEndDebugUtilsLabelRegionEXT", "Session handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionEndDebugUtilsLabelRegionEXT");
if (XR_FAILED(result)) {
return result;
}
LoaderLogger::GetInstance().EndLabelRegion(session);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionEndDebugUtilsLabelRegionEXT) {
return dispatch_table->SessionEndDebugUtilsLabelRegionEXT(session);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderTrampolineSessionInsertDebugUtilsLabelEXT(XrSession session, const XrDebugUtilsLabelEXT *labelInfo) XRLOADER_ABI_TRY {
if (session == XR_NULL_HANDLE) {
LoaderLogger::LogErrorMessage("xrSessionInsertDebugUtilsLabelEXT", "Session handle is XR_NULL_HANDLE.");
return XR_ERROR_HANDLE_INVALID;
}
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSessionInsertDebugUtilsLabelEXT");
if (XR_FAILED(result)) {
return result;
}
if (nullptr == labelInfo) {
LoaderLogger::LogValidationErrorMessage("VUID-xrSessionInsertDebugUtilsLabelEXT-labelInfo-parameter",
"xrSessionInsertDebugUtilsLabelEXT", "labelInfo must be non-NULL",
{XrSdkLogObjectInfo{session, XR_OBJECT_TYPE_SESSION}});
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderLogger::GetInstance().InsertLabel(session, labelInfo);
const std::unique_ptr<XrGeneratedDispatchTable> &dispatch_table = loader_instance->DispatchTable();
if (nullptr != dispatch_table->SessionInsertDebugUtilsLabelEXT) {
return dispatch_table->SessionInsertDebugUtilsLabelEXT(session, labelInfo);
}
return XR_SUCCESS;
}
XRLOADER_ABI_CATCH_FALLBACK
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
static XRAPI_ATTR XrResult XRAPI_CALL
LoaderTrampolineSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSetDebugUtilsObjectNameEXT");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->SetDebugUtilsObjectNameEXT(instance, nameInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
// No-op trampoline needed for xrGetInstanceProcAddr. Work done in terminator.
static XRAPI_ATTR XrResult XRAPI_CALL LoaderTrampolineSubmitDebugUtilsMessageEXT(
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
LoaderInstance *loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSubmitDebugUtilsMessageEXT");
if (XR_SUCCEEDED(result)) {
result =
loader_instance->DispatchTable()->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
// ---- Extension manual loader terminator functions
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermCreateDebugUtilsMessengerEXT(XrInstance instance,
const XrDebugUtilsMessengerCreateInfoEXT *createInfo,
XrDebugUtilsMessengerEXT *messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Entering loader terminator");
if (nullptr == messenger) {
LoaderLogger::LogValidationErrorMessage("VUID-xrCreateDebugUtilsMessengerEXT-messenger-parameter",
"xrCreateDebugUtilsMessengerEXT", "invalid messenger pointer");
return XR_ERROR_VALIDATION_FAILURE;
}
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
// This extension is supported entirely by the loader which means the runtime may or may not support it.
if (nullptr != dispatch_table->CreateDebugUtilsMessengerEXT) {
result = dispatch_table->CreateDebugUtilsMessengerEXT(instance, createInfo, messenger);
} else {
// Just allocate a character so we have a unique value
char *temp_mess_ptr = new char;
*messenger = reinterpret_cast<XrDebugUtilsMessengerEXT>(temp_mess_ptr);
}
if (XR_SUCCEEDED(result)) {
LoaderLogger::GetInstance().AddLogRecorderForXrInstance(instance, MakeDebugUtilsLoaderLogRecorder(createInfo, *messenger));
RuntimeInterface::GetRuntime().TrackDebugMessenger(instance, *messenger);
}
LoaderLogger::LogVerboseMessage("xrCreateDebugUtilsMessengerEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDebugUtilsMessengerDispatchTable(messenger);
XrResult result = XR_SUCCESS;
LoaderLogger::GetInstance().RemoveLogRecorder(MakeHandleGeneric(messenger));
RuntimeInterface::GetRuntime().ForgetDebugMessenger(messenger);
// This extension is supported entirely by the loader which means the runtime may or may not support it.
if (nullptr != dispatch_table->DestroyDebugUtilsMessengerEXT) {
result = dispatch_table->DestroyDebugUtilsMessengerEXT(messenger);
} else {
// Delete the character we would've created
delete (reinterpret_cast<char *>(MakeHandleGeneric(messenger)));
}
LoaderLogger::LogVerboseMessage("xrDestroyDebugUtilsMessengerEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrTermSubmitDebugUtilsMessageEXT(
XrInstance instance, XrDebugUtilsMessageSeverityFlagsEXT messageSeverity, XrDebugUtilsMessageTypeFlagsEXT messageTypes,
const XrDebugUtilsMessengerCallbackDataEXT *callbackData) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
if (nullptr != dispatch_table->SubmitDebugUtilsMessageEXT) {
result = dispatch_table->SubmitDebugUtilsMessageEXT(instance, messageSeverity, messageTypes, callbackData);
} else {
// Only log the message from the loader if the runtime doesn't support this extension. If we did,
// then the user would receive multiple instances of the same message.
LoaderLogger::GetInstance().LogDebugUtilsMessage(messageSeverity, messageTypes, callbackData);
}
LoaderLogger::LogVerboseMessage("xrSubmitDebugUtilsMessageEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL
LoaderXrTermSetDebugUtilsObjectNameEXT(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT *nameInfo) XRLOADER_ABI_TRY {
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Entering loader terminator");
const XrGeneratedDispatchTable *dispatch_table = RuntimeInterface::GetDispatchTable(instance);
XrResult result = XR_SUCCESS;
if (nullptr != dispatch_table->SetDebugUtilsObjectNameEXT) {
result = dispatch_table->SetDebugUtilsObjectNameEXT(instance, nameInfo);
}
LoaderLogger::GetInstance().AddObjectName(nameInfo->objectHandle, nameInfo->objectType, nameInfo->objectName);
LoaderLogger::LogVerboseMessage("xrSetDebugUtilsObjectNameEXT", "Completed loader terminator");
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
XRAPI_ATTR XrResult XRAPI_CALL LoaderXrGetInstanceProcAddr(XrInstance instance, const char *name,
PFN_xrVoidFunction *function) XRLOADER_ABI_TRY {
// Initialize the function to nullptr in case it does not get caught in a known case
*function = nullptr;
if (nullptr == function) {
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
"Invalid Function pointer");
return XR_ERROR_VALIDATION_FAILURE;
}
if (nullptr == name) {
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-function-parameter", "xrGetInstanceProcAddr",
"Invalid Name pointer");
return XR_ERROR_VALIDATION_FAILURE;
}
LoaderInstance *loader_instance = nullptr;
if (instance == XR_NULL_HANDLE) {
// Null instance is allowed for a few specific API entry points, otherwise return error
if (strcmp(name, "xrCreateInstance") != 0 && strcmp(name, "xrEnumerateApiLayerProperties") != 0 &&
strcmp(name, "xrEnumerateInstanceExtensionProperties") != 0 && strcmp(name, "xrInitializeLoaderKHR") != 0) {
// TODO why is xrGetInstanceProcAddr not listed in here?
std::string error_str = "XR_NULL_HANDLE for instance but query for ";
error_str += name;
error_str += " requires a valid instance";
LoaderLogger::LogValidationErrorMessage("VUID-xrGetInstanceProcAddr-instance-parameter", "xrGetInstanceProcAddr",
error_str);
return XR_ERROR_HANDLE_INVALID;
}
} else {
// non null instance passed in, it should be our current instance
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProcAddr");
if (XR_FAILED(result)) {
return result;
}
if (loader_instance->GetInstanceHandle() != instance) {
return XR_ERROR_HANDLE_INVALID;
}
}
// These functions must always go through the loader's implementation (trampoline).
if (strcmp(name, "xrGetInstanceProcAddr") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrGetInstanceProcAddr);
return XR_SUCCESS;
} else if (strcmp(name, "xrInitializeLoaderKHR") == 0) {
#ifdef XR_KHR_LOADER_INIT_SUPPORT
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrInitializeLoaderKHR);
return XR_SUCCESS;
#else
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
} else if (strcmp(name, "xrEnumerateApiLayerProperties") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateApiLayerProperties);
return XR_SUCCESS;
} else if (strcmp(name, "xrEnumerateInstanceExtensionProperties") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrEnumerateInstanceExtensionProperties);
return XR_SUCCESS;
} else if (strcmp(name, "xrCreateInstance") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrCreateInstance);
return XR_SUCCESS;
} else if (strcmp(name, "xrDestroyInstance") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderXrDestroyInstance);
return XR_SUCCESS;
}
// XR_EXT_debug_utils is built into the loader and handled partly through the xrGetInstanceProcAddress terminator,
// but the check to see if the extension is enabled must be done here where ActiveLoaderInstance is safe to use.
if (*function == nullptr) {
if (strcmp(name, "xrCreateDebugUtilsMessengerEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineCreateDebugUtilsMessengerEXT);
} else if (strcmp(name, "xrDestroyDebugUtilsMessengerEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineDestroyDebugUtilsMessengerEXT);
} else if (strcmp(name, "xrSessionBeginDebugUtilsLabelRegionEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionBeginDebugUtilsLabelRegionEXT);
} else if (strcmp(name, "xrSessionEndDebugUtilsLabelRegionEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionEndDebugUtilsLabelRegionEXT);
} else if (strcmp(name, "xrSessionInsertDebugUtilsLabelEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSessionInsertDebugUtilsLabelEXT);
} else if (strcmp(name, "xrSetDebugUtilsObjectNameEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSetDebugUtilsObjectNameEXT);
} else if (strcmp(name, "xrSubmitDebugUtilsMessageEXT") == 0) {
*function = reinterpret_cast<PFN_xrVoidFunction>(LoaderTrampolineSubmitDebugUtilsMessageEXT);
}
if (*function != nullptr && !loader_instance->ExtensionIsEnabled("XR_EXT_debug_utils")) {
// The function matches one of the XR_EXT_debug_utils functions but the extension is not enabled.
*function = nullptr;
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
}
if (*function != nullptr) {
// The loader has a trampoline or implementation of this function.
return XR_SUCCESS;
}
// If the function is not supported by the loader, call down to the next layer.
return loader_instance->GetInstanceProcAddr(name, function);
}
XRLOADER_ABI_CATCH_FALLBACK
// Exported loader functions
//
// The application might override these by exporting the same symbols and so we can't use these
// symbols anywhere in the loader code, and instead the internal non exported functions that these
// stubs call should be used internally.
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
uint32_t *propertyCountOutput,
XrApiLayerProperties *properties) {
return LoaderXrEnumerateApiLayerProperties(propertyCapacityInput, propertyCountOutput, properties);
}
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(const char *layerName,
uint32_t propertyCapacityInput,
uint32_t *propertyCountOutput,
XrExtensionProperties *properties) {
return LoaderXrEnumerateInstanceExtensionProperties(layerName, propertyCapacityInput, propertyCountOutput, properties);
}
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(const XrInstanceCreateInfo *info, XrInstance *instance) {
return LoaderXrCreateInstance(info, instance);
}
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(XrInstance instance) { return LoaderXrDestroyInstance(instance); }
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(XrInstance instance, const char *name,
PFN_xrVoidFunction *function) {
return LoaderXrGetInstanceProcAddr(instance, name, function);
}
#ifdef XR_KHR_LOADER_INIT_SUPPORT
LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(const XrLoaderInitInfoBaseHeaderKHR *loaderInitInfo) {
return LoaderXrInitializeLoaderKHR(loaderInitInfo);
}
#endif

View File

@ -0,0 +1,303 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#include "loader_instance.hpp"
#include "api_layer_interface.hpp"
#include "hex_and_handles.h"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_generated_loader.hpp"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
namespace {
std::unique_ptr<LoaderInstance>& GetSetCurrentLoaderInstance() {
static std::unique_ptr<LoaderInstance> current_loader_instance;
return current_loader_instance;
}
} // namespace
namespace ActiveLoaderInstance {
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name) {
if (GetSetCurrentLoaderInstance() != nullptr) {
LoaderLogger::LogErrorMessage(log_function_name, "Active XrInstance handle already exists");
return XR_ERROR_LIMIT_REACHED;
}
GetSetCurrentLoaderInstance() = std::move(loader_instance);
return XR_SUCCESS;
}
XrResult Get(LoaderInstance** loader_instance, const char* log_function_name) {
*loader_instance = GetSetCurrentLoaderInstance().get();
if (*loader_instance == nullptr) {
LoaderLogger::LogErrorMessage(log_function_name, "No active XrInstance handle.");
return XR_ERROR_HANDLE_INVALID;
}
return XR_SUCCESS;
}
bool IsAvailable() { return GetSetCurrentLoaderInstance() != nullptr; }
void Remove() { GetSetCurrentLoaderInstance().release(); }
} // namespace ActiveLoaderInstance
// Extensions that are supported by the loader, but may not be supported
// the the runtime.
const std::array<XrExtensionProperties, 1>& LoaderInstance::LoaderSpecificExtensions() {
static const std::array<XrExtensionProperties, 1> extensions = {XrExtensionProperties{
XR_TYPE_EXTENSION_PROPERTIES, nullptr, XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_EXT_debug_utils_SPEC_VERSION}};
return extensions;
}
namespace {
class InstanceCreateInfoManager {
public:
explicit InstanceCreateInfoManager(const XrInstanceCreateInfo* info) : original_create_info(info), modified_create_info(*info) {
Reset();
}
// Reset the "modified" state to match the original state.
void Reset() {
enabled_extensions_cstr.clear();
enabled_extensions_cstr.reserve(original_create_info->enabledExtensionCount);
for (uint32_t i = 0; i < original_create_info->enabledExtensionCount; ++i) {
enabled_extensions_cstr.push_back(original_create_info->enabledExtensionNames[i]);
}
Update();
}
// Remove extensions named in the parameter and return a pointer to the current state.
const XrInstanceCreateInfo* FilterOutExtensions(const std::vector<const char*>& extensions_to_skip) {
if (enabled_extensions_cstr.empty()) {
return Get();
}
if (extensions_to_skip.empty()) {
return Get();
}
for (auto& ext : extensions_to_skip) {
FilterOutExtension(ext);
}
return Update();
}
// Remove the extension named in the parameter and return a pointer to the current state.
const XrInstanceCreateInfo* FilterOutExtension(const char* extension_to_skip) {
if (enabled_extensions_cstr.empty()) {
return &modified_create_info;
}
auto b = enabled_extensions_cstr.begin();
auto e = enabled_extensions_cstr.end();
auto it = std::find_if(b, e, [&](const char* extension) { return strcmp(extension_to_skip, extension) == 0; });
if (it != e) {
// Just that one element goes away
enabled_extensions_cstr.erase(it);
}
return Update();
}
// Get the current modified XrInstanceCreateInfo
const XrInstanceCreateInfo* Get() const { return &modified_create_info; }
private:
const XrInstanceCreateInfo* Update() {
modified_create_info.enabledExtensionCount = static_cast<uint32_t>(enabled_extensions_cstr.size());
modified_create_info.enabledExtensionNames = enabled_extensions_cstr.empty() ? nullptr : enabled_extensions_cstr.data();
return &modified_create_info;
}
const XrInstanceCreateInfo* original_create_info;
XrInstanceCreateInfo modified_create_info;
std::vector<const char*> enabled_extensions_cstr;
};
} // namespace
// Factory method
XrResult LoaderInstance::CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term,
PFN_xrCreateInstance create_instance_term,
PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces,
const XrInstanceCreateInfo* info, std::unique_ptr<LoaderInstance>* loader_instance) {
LoaderLogger::LogVerboseMessage("xrCreateInstance", "Entering LoaderInstance::CreateInstance");
// Check the list of enabled extensions to make sure something supports them, and, if we do,
// add it to the list of enabled extensions
XrResult last_error = XR_SUCCESS;
for (uint32_t ext = 0; ext < info->enabledExtensionCount; ++ext) {
bool found = false;
// First check the runtime
if (RuntimeInterface::GetRuntime().SupportsExtension(info->enabledExtensionNames[ext])) {
found = true;
}
// Next check the loader
if (!found) {
for (auto& loader_extension : LoaderInstance::LoaderSpecificExtensions()) {
if (strcmp(loader_extension.extensionName, info->enabledExtensionNames[ext]) == 0) {
found = true;
break;
}
}
}
// Finally, check the enabled layers
if (!found) {
for (auto& layer_interface : api_layer_interfaces) {
if (layer_interface->SupportsExtension(info->enabledExtensionNames[ext])) {
found = true;
break;
}
}
}
if (!found) {
std::string msg = "LoaderInstance::CreateInstance, no support found for requested extension: ";
msg += info->enabledExtensionNames[ext];
LoaderLogger::LogErrorMessage("xrCreateInstance", msg);
last_error = XR_ERROR_EXTENSION_NOT_PRESENT;
break;
}
}
// Topmost means "closest to the application"
PFN_xrGetInstanceProcAddr topmost_gipa = get_instance_proc_addr_term;
XrInstance instance{XR_NULL_HANDLE};
if (XR_SUCCEEDED(last_error)) {
// Remove the loader-supported-extensions (debug utils), if it's in the list of enabled extensions but not supported by
// the runtime.
InstanceCreateInfoManager create_info_manager{info};
const XrInstanceCreateInfo* modified_create_info = info;
if (info->enabledExtensionCount > 0) {
std::vector<const char*> extensions_to_skip;
for (const auto& ext : LoaderInstance::LoaderSpecificExtensions()) {
if (!RuntimeInterface::GetRuntime().SupportsExtension(ext.extensionName)) {
extensions_to_skip.emplace_back(ext.extensionName);
}
}
modified_create_info = create_info_manager.FilterOutExtensions(extensions_to_skip);
}
// Only start the xrCreateApiLayerInstance stack if we have layers.
if (!api_layer_interfaces.empty()) {
// Initialize an array of ApiLayerNextInfo structs
std::unique_ptr<XrApiLayerNextInfo[]> next_info_list(new XrApiLayerNextInfo[api_layer_interfaces.size()]);
auto ni_index = static_cast<uint32_t>(api_layer_interfaces.size() - 1);
for (uint32_t i = 0; i <= ni_index; i++) {
next_info_list[i].structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO;
next_info_list[i].structVersion = XR_API_LAYER_NEXT_INFO_STRUCT_VERSION;
next_info_list[i].structSize = sizeof(XrApiLayerNextInfo);
}
// Go through all layers, and override the instance pointers with the layer version. However,
// go backwards through the layer list so we replace in reverse order so the layers can call their next function
// appropriately.
PFN_xrCreateApiLayerInstance topmost_cali_fp = create_api_layer_instance_term;
XrApiLayerNextInfo* topmost_nextinfo = nullptr;
for (auto layer_interface = api_layer_interfaces.rbegin(); layer_interface != api_layer_interfaces.rend();
++layer_interface) {
// Collect current layer's function pointers
PFN_xrGetInstanceProcAddr cur_gipa_fp = (*layer_interface)->GetInstanceProcAddrFuncPointer();
PFN_xrCreateApiLayerInstance cur_cali_fp = (*layer_interface)->GetCreateApiLayerInstanceFuncPointer();
// Fill in layer info and link previous (lower) layer fxn pointers
strncpy(next_info_list[ni_index].layerName, (*layer_interface)->LayerName().c_str(),
XR_MAX_API_LAYER_NAME_SIZE - 1);
next_info_list[ni_index].layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
next_info_list[ni_index].next = topmost_nextinfo;
next_info_list[ni_index].nextGetInstanceProcAddr = topmost_gipa;
next_info_list[ni_index].nextCreateApiLayerInstance = topmost_cali_fp;
// Update saved pointers for next iteration
topmost_nextinfo = &next_info_list[ni_index];
topmost_gipa = cur_gipa_fp;
topmost_cali_fp = cur_cali_fp;
ni_index--;
}
// Populate the ApiLayerCreateInfo struct and pass to topmost CreateApiLayerInstance()
XrApiLayerCreateInfo api_layer_ci = {};
api_layer_ci.structType = XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO;
api_layer_ci.structVersion = XR_API_LAYER_CREATE_INFO_STRUCT_VERSION;
api_layer_ci.structSize = sizeof(XrApiLayerCreateInfo);
api_layer_ci.loaderInstance = nullptr; // Not used.
api_layer_ci.settings_file_location[0] = '\0';
api_layer_ci.nextInfo = next_info_list.get();
//! @todo do we filter our create info extension list here?
//! Think that actually each layer might need to filter...
last_error = topmost_cali_fp(modified_create_info, &api_layer_ci, &instance);
} else {
// The loader's terminator is the topmost CreateInstance if there are no layers.
last_error = create_instance_term(modified_create_info, &instance);
}
if (XR_FAILED(last_error)) {
LoaderLogger::LogErrorMessage("xrCreateInstance", "LoaderInstance::CreateInstance chained CreateInstance call failed");
}
}
if (XR_SUCCEEDED(last_error)) {
loader_instance->reset(new LoaderInstance(instance, info, topmost_gipa, std::move(api_layer_interfaces)));
std::ostringstream oss;
oss << "LoaderInstance::CreateInstance succeeded with ";
oss << (*loader_instance)->LayerInterfaces().size();
oss << " layers enabled and runtime interface - created instance = ";
oss << HandleToHexString((*loader_instance)->GetInstanceHandle());
LoaderLogger::LogInfoMessage("xrCreateInstance", oss.str());
}
return last_error;
}
XrResult LoaderInstance::GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function) {
return _topmost_gipa(_runtime_instance, name, function);
}
LoaderInstance::LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* create_info, PFN_xrGetInstanceProcAddr topmost_gipa,
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces)
: _runtime_instance(instance),
_topmost_gipa(topmost_gipa),
_api_layer_interfaces(std::move(api_layer_interfaces)),
_dispatch_table(new XrGeneratedDispatchTable{}) {
for (uint32_t ext = 0; ext < create_info->enabledExtensionCount; ++ext) {
_enabled_extensions.push_back(create_info->enabledExtensionNames[ext]);
}
GeneratedXrPopulateDispatchTable(_dispatch_table.get(), instance, topmost_gipa);
}
LoaderInstance::~LoaderInstance() {
std::ostringstream oss;
oss << "Destroying LoaderInstance = ";
oss << PointerToHexString(this);
LoaderLogger::LogInfoMessage("xrDestroyInstance", oss.str());
}
bool LoaderInstance::ExtensionIsEnabled(const std::string& extension) {
for (std::string& cur_enabled : _enabled_extensions) {
if (cur_enabled == extension) {
return true;
}
}
return false;
}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "extra_algorithms.h"
#include "loader_interfaces.h"
#include <openxr/openxr.h>
#include <array>
#include <cmath>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
class ApiLayerInterface;
struct XrGeneratedDispatchTable;
class LoaderInstance;
// Manage the single loader instance that is available.
namespace ActiveLoaderInstance {
// Set the active loader instance. This will fail if there is already an active loader instance.
XrResult Set(std::unique_ptr<LoaderInstance> loader_instance, const char* log_function_name);
// Returns true if there is an active loader instance.
bool IsAvailable();
// Get the active LoaderInstance.
XrResult Get(LoaderInstance** loader_instance, const char* log_function_name);
// Destroy the currently active LoaderInstance if there is one. This will make the loader able to create a new XrInstance if needed.
void Remove();
}; // namespace ActiveLoaderInstance
// Manages information needed by the loader for an XrInstance, such as what extensions are available and the dispatch table.
class LoaderInstance {
public:
// Factory method
static XrResult CreateInstance(PFN_xrGetInstanceProcAddr get_instance_proc_addr_term, PFN_xrCreateInstance create_instance_term,
PFN_xrCreateApiLayerInstance create_api_layer_instance_term,
std::vector<std::unique_ptr<ApiLayerInterface>> layer_interfaces,
const XrInstanceCreateInfo* createInfo, std::unique_ptr<LoaderInstance>* loader_instance);
static const std::array<XrExtensionProperties, 1>& LoaderSpecificExtensions();
virtual ~LoaderInstance();
XrInstance GetInstanceHandle() { return _runtime_instance; }
const std::unique_ptr<XrGeneratedDispatchTable>& DispatchTable() { return _dispatch_table; }
std::vector<std::unique_ptr<ApiLayerInterface>>& LayerInterfaces() { return _api_layer_interfaces; }
bool ExtensionIsEnabled(const std::string& extension);
XrDebugUtilsMessengerEXT DefaultDebugUtilsMessenger() { return _messenger; }
void SetDefaultDebugUtilsMessenger(XrDebugUtilsMessengerEXT messenger) { _messenger = messenger; }
XrResult GetInstanceProcAddr(const char* name, PFN_xrVoidFunction* function);
private:
LoaderInstance(XrInstance instance, const XrInstanceCreateInfo* createInfo, PFN_xrGetInstanceProcAddr topmost_gipa,
std::vector<std::unique_ptr<ApiLayerInterface>> api_layer_interfaces);
private:
XrInstance _runtime_instance{XR_NULL_HANDLE};
PFN_xrGetInstanceProcAddr _topmost_gipa{nullptr};
std::vector<std::string> _enabled_extensions;
std::vector<std::unique_ptr<ApiLayerInterface>> _api_layer_interfaces;
std::unique_ptr<XrGeneratedDispatchTable> _dispatch_table;
// Internal debug messenger created during xrCreateInstance
XrDebugUtilsMessengerEXT _messenger{XR_NULL_HANDLE};
};

View File

@ -0,0 +1,239 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#include "loader_logger.hpp"
#include "extra_algorithms.h"
#include "hex_and_handles.h"
#include "loader_logger_recorders.hpp"
#include "platform_utils.hpp"
#include <openxr/openxr.h>
#include <algorithm>
#include <iterator>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
bool LoaderLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT /*message_severity*/,
XrDebugUtilsMessageTypeFlagsEXT /*message_type*/,
const XrDebugUtilsMessengerCallbackDataEXT* /*callback_data*/) {
return false;
}
// Utility functions for converting to/from XR_EXT_debug_utils values
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
XrDebugUtilsMessageSeverityFlagsEXT utils_severities) {
XrLoaderLogMessageSeverityFlags log_severities = 0UL;
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
}
if ((utils_severities & XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0u) {
log_severities |= XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
}
return log_severities;
}
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
XrLoaderLogMessageSeverityFlags log_severities) {
XrDebugUtilsMessageSeverityFlagsEXT utils_severities = 0UL;
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if ((log_severities & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT) != 0u) {
utils_severities |= XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
return utils_severities;
}
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types) {
XrLoaderLogMessageTypeFlagBits log_types = 0UL;
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT;
}
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT;
}
if ((utils_types & XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) != 0u) {
log_types |= XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT;
}
return log_types;
}
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types) {
XrDebugUtilsMessageTypeFlagsEXT utils_types = 0UL;
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
}
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
}
if ((log_types & XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT) != 0u) {
utils_types |= XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
}
return utils_types;
}
LoaderLogger::LoaderLogger() {
std::string debug_string = PlatformUtilsGetEnv("XR_LOADER_DEBUG");
// Add an error logger by default so that we at least get errors out to std::cerr.
// Normally we enable stderr output. But if the XR_LOADER_DEBUG environment variable is
// present as "none" then we don't.
if (debug_string != "none") {
AddLogRecorder(MakeStdErrLoaderLogRecorder(nullptr));
#ifdef __ANDROID__
// Add a logcat logger by default.
AddLogRecorder(MakeLogcatLoaderLogRecorder());
#endif // __ANDROID__
}
#ifdef _WIN32
// Add an debugger logger by default so that we at least get errors out to the debugger.
AddLogRecorder(MakeDebuggerLoaderLogRecorder(nullptr));
#endif
// If the environment variable to enable loader debugging is set, then enable the
// appropriate logging out to std::cout.
if (!debug_string.empty()) {
XrLoaderLogMessageSeverityFlags debug_flags = {};
if (debug_string == "error") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT;
} else if (debug_string == "warn") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT;
} else if (debug_string == "info") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT;
} else if (debug_string == "all" || debug_string == "verbose") {
debug_flags = XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT |
XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT;
}
AddLogRecorder(MakeStdOutLoaderLogRecorder(nullptr, debug_flags));
}
}
void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) {
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
_recorders.push_back(std::move(recorder));
}
void LoaderLogger::AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder) {
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
_recordersByInstance[instance].insert(recorder->UniqueId());
_recorders.emplace_back(std::move(recorder));
}
void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) {
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
vector_remove_if_and_erase(
_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; });
for (auto& recorders : _recordersByInstance) {
auto& messengersForInstance = recorders.second;
if (messengersForInstance.count(unique_id) > 0) {
messengersForInstance.erase(unique_id);
}
}
}
void LoaderLogger::RemoveLogRecordersForXrInstance(XrInstance instance) {
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
if (_recordersByInstance.find(instance) != _recordersByInstance.end()) {
auto recorders = _recordersByInstance[instance];
vector_remove_if_and_erase(_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) {
return recorders.find(recorder->UniqueId()) != recorders.end();
});
_recordersByInstance.erase(instance);
}
}
bool LoaderLogger::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const std::string& message_id, const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects) {
XrLoaderLogMessengerCallbackData callback_data = {};
callback_data.message_id = message_id.c_str();
callback_data.command_name = command_name.c_str();
callback_data.message = message.c_str();
auto names_and_labels = data_.PopulateNamesAndLabels(objects);
callback_data.objects = names_and_labels.sdk_objects.empty() ? nullptr : names_and_labels.sdk_objects.data();
callback_data.object_count = static_cast<uint8_t>(names_and_labels.objects.size());
callback_data.session_labels = names_and_labels.labels.empty() ? nullptr : names_and_labels.labels.data();
callback_data.session_labels_count = static_cast<uint8_t>(names_and_labels.labels.size());
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
bool exit_app = false;
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
if ((recorder->MessageSeverities() & message_severity) == message_severity &&
(recorder->MessageTypes() & message_type) == message_type) {
exit_app |= recorder->LogMessage(message_severity, message_type, &callback_data);
}
}
return exit_app;
}
// Extension-specific logging functions
bool LoaderLogger::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
bool exit_app = false;
XrLoaderLogMessageSeverityFlags log_message_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
XrLoaderLogMessageTypeFlags log_message_type = DebugUtilsMessageTypesToLoaderLogMessageTypes(message_type);
AugmentedCallbackData augmented_data;
data_.WrapCallbackData(&augmented_data, callback_data);
// Loop through the recorders
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
// Only send the message if it's a debug utils recorder and of the type the recorder cares about.
if (recorder->Type() != XR_LOADER_LOG_DEBUG_UTILS ||
(recorder->MessageSeverities() & log_message_severity) != log_message_severity ||
(recorder->MessageTypes() & log_message_type) != log_message_type) {
continue;
}
exit_app |= recorder->LogDebugUtilsMessage(message_severity, message_type, augmented_data.exported_data);
}
return exit_app;
}
void LoaderLogger::AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name) {
data_.AddObjectName(object_handle, object_type, object_name);
}
void LoaderLogger::BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
data_.BeginLabelRegion(session, *label_info);
}
void LoaderLogger::EndLabelRegion(XrSession session) { data_.EndLabelRegion(session); }
void LoaderLogger::InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info) {
data_.InsertLabel(session, *label_info);
}
void LoaderLogger::DeleteSessionLabels(XrSession session) { data_.DeleteSessionLabels(session); }

View File

@ -0,0 +1,194 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <set>
#include <map>
#include <shared_mutex>
#include <openxr/openxr.h>
#include "hex_and_handles.h"
#include "object_info.h"
// Use internal versions of flags similar to XR_EXT_debug_utils so that
// we're not tightly coupled to that extension. This way, if the extension
// changes or gets replaced, we can be flexible in the loader.
#define XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT 0x00000001
#define XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT 0x00000010
#define XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT 0x00000100
#define XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT 0x00001000
#define XR_LOADER_LOG_MESSAGE_SEVERITY_DEFAULT_BITS 0x00000000
typedef XrFlags64 XrLoaderLogMessageSeverityFlagBits;
typedef XrFlags64 XrLoaderLogMessageSeverityFlags;
#define XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT 0x00000001
#define XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT 0x00000002
#define XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT 0x00000004
#define XR_LOADER_LOG_MESSAGE_TYPE_DEFAULT_BITS 0xffffffff
typedef XrFlags64 XrLoaderLogMessageTypeFlagBits;
typedef XrFlags64 XrLoaderLogMessageTypeFlags;
struct XrLoaderLogMessengerCallbackData {
const char* message_id;
const char* command_name;
const char* message;
uint8_t object_count;
XrSdkLogObjectInfo* objects;
uint8_t session_labels_count;
XrDebugUtilsLabelEXT* session_labels;
};
enum XrLoaderLogType {
XR_LOADER_LOG_UNKNOWN = 0,
XR_LOADER_LOG_STDERR,
XR_LOADER_LOG_STDOUT,
XR_LOADER_LOG_DEBUG_UTILS,
XR_LOADER_LOG_DEBUGGER,
XR_LOADER_LOG_LOGCAT,
};
class LoaderLogRecorder {
public:
LoaderLogRecorder(XrLoaderLogType type, void* user_data, XrLoaderLogMessageSeverityFlags message_severities,
XrLoaderLogMessageTypeFlags message_types) {
_active = false;
_user_data = user_data;
_type = type;
_unique_id = 0;
_message_severities = message_severities;
_message_types = message_types;
}
virtual ~LoaderLogRecorder() = default;
XrLoaderLogType Type() { return _type; }
uint64_t UniqueId() { return _unique_id; }
XrLoaderLogMessageSeverityFlags MessageSeverities() { return _message_severities; }
XrLoaderLogMessageTypeFlags MessageTypes() { return _message_types; }
virtual void Start() { _active = true; }
bool IsPaused() { return _active; }
virtual void Pause() { _active = false; }
virtual void Resume() { _active = true; }
virtual void Stop() { _active = false; }
virtual bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) = 0;
// Extension-specific logging functions - defaults to do nothing.
virtual bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
protected:
bool _active;
XrLoaderLogType _type;
uint64_t _unique_id;
void* _user_data;
XrLoaderLogMessageSeverityFlags _message_severities;
XrLoaderLogMessageTypeFlags _message_types;
};
class LoaderLogger {
public:
static LoaderLogger& GetInstance() {
static LoaderLogger instance;
return instance;
}
void AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder);
void RemoveLogRecorder(uint64_t unique_id);
void AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder);
void RemoveLogRecordersForXrInstance(XrInstance instance);
//! Called from LoaderXrTermSetDebugUtilsObjectNameEXT - an empty name means remove
void AddObjectName(uint64_t object_handle, XrObjectType object_type, const std::string& object_name);
void BeginLabelRegion(XrSession session, const XrDebugUtilsLabelEXT* label_info);
void EndLabelRegion(XrSession session);
void InsertLabel(XrSession session, const XrDebugUtilsLabelEXT* label_info);
void DeleteSessionLabels(XrSession session);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const std::string& message_id, const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {});
static bool LogErrorMessage(const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogWarningMessage(const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogInfoMessage(const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogVerboseMessage(const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT, XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT,
"OpenXR-Loader", command_name, message, objects);
}
static bool LogValidationErrorMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
vuid, command_name, message, objects);
}
static bool LogValidationWarningMessage(const std::string& vuid, const std::string& command_name, const std::string& message,
const std::vector<XrSdkLogObjectInfo>& objects = {}) {
return GetInstance().LogMessage(XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT, XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT,
vuid, command_name, message, objects);
}
// Extension-specific logging functions
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data);
// Non-copyable
LoaderLogger(const LoaderLogger&) = delete;
LoaderLogger& operator=(const LoaderLogger&) = delete;
private:
LoaderLogger();
std::shared_timed_mutex _mutex;
// List of *all* available recorder objects (including created specifically for an Instance)
std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders;
// List of recorder objects only created specifically for an XrInstance
std::unordered_map<XrInstance, std::unordered_set<uint64_t>> _recordersByInstance;
DebugUtilsData data_;
};
// Utility functions for converting to/from XR_EXT_debug_utils values
XrLoaderLogMessageSeverityFlags DebugUtilsSeveritiesToLoaderLogMessageSeverities(
XrDebugUtilsMessageSeverityFlagsEXT utils_severities);
XrDebugUtilsMessageSeverityFlagsEXT LoaderLogMessageSeveritiesToDebugUtilsMessageSeverities(
XrLoaderLogMessageSeverityFlags log_severities);
XrLoaderLogMessageTypeFlagBits DebugUtilsMessageTypesToLoaderLogMessageTypes(XrDebugUtilsMessageTypeFlagsEXT utils_types);
XrDebugUtilsMessageTypeFlagsEXT LoaderLogMessageTypesToDebugUtilsMessageTypes(XrLoaderLogMessageTypeFlagBits log_types);

View File

@ -0,0 +1,291 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#include "loader_logger_recorders.hpp"
#include "hex_and_handles.h"
#include "loader_logger.hpp"
#include <openxr/openxr.h>
#include <memory>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#ifdef __ANDROID__
#include "android/log.h"
#endif
#ifdef _WIN32
#include <windows.h>
#endif
// Anonymous namespace to keep these types private
namespace {
void OutputMessageToStream(std::ostream& os, XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type, const XrLoaderLogMessengerCallbackData* callback_data) {
if (XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT > message_severity) {
os << "Verbose [";
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT > message_severity) {
os << "Info [";
} else if (XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT > message_severity) {
os << "Warning [";
} else {
os << "Error [";
}
switch (message_type) {
case XR_LOADER_LOG_MESSAGE_TYPE_GENERAL_BIT:
os << "GENERAL";
break;
case XR_LOADER_LOG_MESSAGE_TYPE_SPECIFICATION_BIT:
os << "SPEC";
break;
case XR_LOADER_LOG_MESSAGE_TYPE_PERFORMANCE_BIT:
os << "PERF";
break;
default:
os << "UNKNOWN";
break;
}
os << " | " << callback_data->command_name << " | " << callback_data->message_id << "] : " << callback_data->message
<< std::endl;
for (uint32_t obj = 0; obj < callback_data->object_count; ++obj) {
os << " Object[" << obj << "] = " << callback_data->objects[obj].ToString();
os << std::endl;
}
for (uint32_t label = 0; label < callback_data->session_labels_count; ++label) {
os << " SessionLabel[" << std::to_string(label) << "] = " << callback_data->session_labels[label].labelName;
os << std::endl;
}
}
// With std::cerr: Standard Error logger, always on for now
// With std::cout: Standard Output logger used with XR_LOADER_DEBUG
class OstreamLoaderLogRecorder : public LoaderLogRecorder {
public:
OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
private:
std::ostream& os_;
};
// Debug Utils logger used with XR_EXT_debug_utils
class DebugUtilsLogRecorder : public LoaderLogRecorder {
public:
DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info, XrDebugUtilsMessengerEXT debug_messenger);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
// Extension-specific logging functions
bool LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity, XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) override;
private:
PFN_xrDebugUtilsMessengerCallbackEXT _user_callback;
};
#ifdef __ANDROID__
class LogcatLoaderLogRecorder : public LoaderLogRecorder {
public:
LogcatLoaderLogRecorder();
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
};
#endif
#ifdef _WIN32
// Output to debugger
class DebuggerLoaderLogRecorder : public LoaderLogRecorder {
public:
DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags);
bool LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity, XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) override;
};
#endif
// Unified stdout/stderr logger
OstreamLoaderLogRecorder::OstreamLoaderLogRecorder(std::ostream& os, void* user_data, XrLoaderLogMessageSeverityFlags flags)
: LoaderLogRecorder(XR_LOADER_LOG_STDOUT, user_data, flags, 0xFFFFFFFFUL), os_(os) {
// Automatically start
Start();
}
bool OstreamLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
OutputMessageToStream(os_, message_severity, message_type, callback_data);
}
// Return of "true" means that we should exit the application after the logged message. We
// don't want to do that for our internal logging. Only let a user return true.
return false;
}
// A logger associated with the XR_EXT_debug_utils extension
DebugUtilsLogRecorder::DebugUtilsLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger)
: LoaderLogRecorder(XR_LOADER_LOG_DEBUG_UTILS, static_cast<void*>(create_info->userData),
DebugUtilsSeveritiesToLoaderLogMessageSeverities(create_info->messageSeverities),
DebugUtilsMessageTypesToLoaderLogMessageTypes(create_info->messageTypes)),
_user_callback(create_info->userCallback) {
// Use the debug messenger value to uniquely identify this logger with that messenger
_unique_id = MakeHandleGeneric(debug_messenger);
Start();
}
// Extension-specific logging functions
bool DebugUtilsLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
bool should_exit = false;
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
XrDebugUtilsMessageSeverityFlagsEXT utils_severity = DebugUtilsSeveritiesToLoaderLogMessageSeverities(message_severity);
XrDebugUtilsMessageTypeFlagsEXT utils_type = LoaderLogMessageTypesToDebugUtilsMessageTypes(message_type);
// Convert the loader log message into the debug utils log message information
XrDebugUtilsMessengerCallbackDataEXT utils_callback_data = {};
utils_callback_data.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT;
utils_callback_data.messageId = callback_data->message_id;
utils_callback_data.functionName = callback_data->command_name;
utils_callback_data.message = callback_data->message;
std::vector<XrDebugUtilsObjectNameInfoEXT> utils_objects;
utils_objects.resize(callback_data->object_count);
for (uint8_t object = 0; object < callback_data->object_count; ++object) {
utils_objects[object].type = XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT;
utils_objects[object].next = nullptr;
utils_objects[object].objectHandle = callback_data->objects[object].handle;
utils_objects[object].objectType = callback_data->objects[object].type;
utils_objects[object].objectName = callback_data->objects[object].name.c_str();
}
utils_callback_data.objectCount = callback_data->object_count;
utils_callback_data.objects = utils_objects.data();
utils_callback_data.sessionLabelCount = callback_data->session_labels_count;
utils_callback_data.sessionLabels = callback_data->session_labels;
// Call the user callback with the appropriate info
// Return of "true" means that we should exit the application after the logged message.
should_exit = (_user_callback(utils_severity, utils_type, &utils_callback_data, _user_data) == XR_TRUE);
}
return should_exit;
}
bool DebugUtilsLogRecorder::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT message_severity,
XrDebugUtilsMessageTypeFlagsEXT message_type,
const XrDebugUtilsMessengerCallbackDataEXT* callback_data) {
// Call the user callback with the appropriate info
// Return of "true" means that we should exit the application after the logged message.
return (_user_callback(message_severity, message_type, callback_data, _user_data) == XR_TRUE);
}
#ifdef __ANDROID__
static inline android_LogPriority LoaderToAndroidLogPriority(XrLoaderLogMessageSeverityFlags message_severity) {
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT)) {
return ANDROID_LOG_ERROR;
}
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT)) {
return ANDROID_LOG_WARN;
}
if (0 != (message_severity & XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT)) {
return ANDROID_LOG_INFO;
}
return ANDROID_LOG_VERBOSE;
}
LogcatLoaderLogRecorder::LogcatLoaderLogRecorder()
: LoaderLogRecorder(XR_LOADER_LOG_LOGCAT, nullptr,
XR_LOADER_LOG_MESSAGE_SEVERITY_VERBOSE_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_INFO_BIT |
XR_LOADER_LOG_MESSAGE_SEVERITY_WARNING_BIT | XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT,
0xFFFFFFFFUL) {
// Automatically start
Start();
}
bool LogcatLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
std::stringstream ss;
OutputMessageToStream(ss, message_severity, message_type, callback_data);
__android_log_write(LoaderToAndroidLogPriority(message_severity), "OpenXR-Loader", ss.str().c_str());
}
// Return of "true" means that we should exit the application after the logged message. We
// don't want to do that for our internal logging. Only let a user return true.
return false;
}
#endif // __ANDROID__
#ifdef _WIN32
// Unified stdout/stderr logger
DebuggerLoaderLogRecorder::DebuggerLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags)
: LoaderLogRecorder(XR_LOADER_LOG_DEBUGGER, user_data, flags, 0xFFFFFFFFUL) {
// Automatically start
Start();
}
bool DebuggerLoaderLogRecorder::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severity,
XrLoaderLogMessageTypeFlags message_type,
const XrLoaderLogMessengerCallbackData* callback_data) {
if (_active && 0 != (_message_severities & message_severity) && 0 != (_message_types & message_type)) {
std::stringstream ss;
OutputMessageToStream(ss, message_severity, message_type, callback_data);
OutputDebugStringA(ss.str().c_str());
}
// Return of "true" means that we should exit the application after the logged message. We
// don't want to do that for our internal logging. Only let a user return true.
return false;
}
#endif
} // namespace
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags) {
std::unique_ptr<LoaderLogRecorder> recorder(new OstreamLoaderLogRecorder(std::cout, user_data, flags));
return recorder;
}
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data) {
std::unique_ptr<LoaderLogRecorder> recorder(
new OstreamLoaderLogRecorder(std::cerr, user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT));
return recorder;
}
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger) {
std::unique_ptr<LoaderLogRecorder> recorder(new DebugUtilsLogRecorder(create_info, debug_messenger));
return recorder;
}
#ifdef __ANDROID__
std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder() {
std::unique_ptr<LoaderLogRecorder> recorder(new LogcatLoaderLogRecorder());
return recorder;
}
#endif
#ifdef _WIN32
std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data) {
std::unique_ptr<LoaderLogRecorder> recorder(new DebuggerLoaderLogRecorder(user_data, XR_LOADER_LOG_MESSAGE_SEVERITY_ERROR_BIT));
return recorder;
}
#endif

View File

@ -0,0 +1,40 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Ryan Pavlik <ryan.pavlik@collabora.com>
//
#pragma once
#include "loader_logger.hpp"
#include <openxr/openxr.h>
#include <memory>
//! Standard Error logger, on by default. Disabled with environment variable XR_LOADER_DEBUG = "none".
std::unique_ptr<LoaderLogRecorder> MakeStdErrLoaderLogRecorder(void* user_data);
//! Standard Output logger used with XR_LOADER_DEBUG environment variable.
std::unique_ptr<LoaderLogRecorder> MakeStdOutLoaderLogRecorder(void* user_data, XrLoaderLogMessageSeverityFlags flags);
#ifdef __ANDROID__
//! Android liblog ("logcat") logger
std::unique_ptr<LoaderLogRecorder> MakeLogcatLoaderLogRecorder();
#endif
// Debug Utils logger used with XR_EXT_debug_utils
std::unique_ptr<LoaderLogRecorder> MakeDebugUtilsLoaderLogRecorder(const XrDebugUtilsMessengerCreateInfoEXT* create_info,
XrDebugUtilsMessengerEXT debug_messenger);
#ifdef _WIN32
//! Win32 debugger output
std::unique_ptr<LoaderLogRecorder> MakeDebuggerLoaderLogRecorder(void* user_data);
#endif
// TODO: Add other Derived classes:
// - FileLoaderLogRecorder - During/after xrCreateInstance
// - PipeLoaderLogRecorder? - During/after xrCreateInstance

View File

@ -0,0 +1,204 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
//
#pragma once
#include <cassert>
#include <sstream>
#include <string>
#include "xr_dependencies.h"
#include "platform_utils.hpp"
#if defined(__GNUC__) && __GNUC__ >= 4
#define LOADER_EXPORT __attribute__((visibility("default")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
#define LOADER_EXPORT __attribute__((visibility("default")))
#else
#define LOADER_EXPORT
#endif
// Environment variables
#if defined(XR_OS_LINUX) || defined(XR_OS_APPLE) || defined(XR_OS_ANDROID)
#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#ifndef PATH_MAX
#define PATH_MAX 1024
#endif
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
// Dynamic Loading of libraries:
typedef void *LoaderPlatformLibraryHandle;
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// When loading the library, we use RTLD_LAZY so that not all symbols have to be
// resolved at this time (which improves performance). Note that if not all symbols
// can be resolved, this could cause crashes later.
// For experimenting/debugging: Define the LD_BIND_NOW environment variable to force all
// symbols to be resolved here.
return dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
(void)path;
return dlerror();
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { dlclose(library); }
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(!name.empty());
return dlsym(library, name.c_str());
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
(void)name;
return dlerror();
}
#elif defined(XR_OS_WINDOWS)
#define PATH_SEPARATOR ';'
#define DIRECTORY_SYMBOL '\\'
// Workaround for MS VS 2010/2013 missing snprintf and vsnprintf
#if defined(_MSC_VER) && _MSC_VER < 1900
#include <stdint.h>
static inline int32_t xr_vsnprintf(char *result_buffer, size_t buffer_size, const char *print_format, va_list varying_list) {
int32_t copy_count = -1;
if (buffer_size != 0) {
copy_count = _vsnprintf_s(result_buffer, buffer_size, _TRUNCATE, print_format, varying_list);
}
if (copy_count == -1) {
copy_count = _vscprintf(print_format, varying_list);
}
return copy_count;
}
static inline int32_t xr_snprintf(char *result_buffer, size_t buffer_size, const char *print_format, ...) {
va_list varying_list;
va_start(varying_list, print_format);
int32_t copy_count = xr_vsnprintf(result_buffer, buffer_size, print_format, varying_list);
va_end(varying_list);
return copy_count;
}
#define snprintf xr_snprintf
#define vsnprintf xr_vsnprintf
#endif
static inline std::string DescribeError(uint32_t code, bool prefixErrorCode = true) {
std::string str;
if (prefixErrorCode) {
char prefixBuffer[64];
snprintf(prefixBuffer, sizeof(prefixBuffer), "0x%llx (%lld): ", (uint64_t)code, (int64_t)code);
str = prefixBuffer;
}
// Could use FORMAT_MESSAGE_FROM_HMODULE to specify an error source.
WCHAR errorBufferW[1024]{};
const DWORD errorBufferWCapacity = sizeof(errorBufferW) / sizeof(errorBufferW[0]);
const DWORD length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, (DWORD)code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errorBufferW, errorBufferWCapacity, nullptr);
if (length) { // If errorBufferW contains what we are looking for...
str += wide_to_utf8(errorBufferW);
} else {
str = "(unknown)";
}
return str;
}
// Dynamic Loading:
typedef HMODULE LoaderPlatformLibraryHandle;
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
const std::wstring pathW = utf8_to_wide(path);
// Try loading the library the original way first.
LoaderPlatformLibraryHandle handle = LoadLibraryW(pathW.c_str());
if (handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
const DWORD dwAttrib = GetFileAttributesW(pathW.c_str());
const bool fileExists = (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
if (fileExists) {
// If that failed, then try loading it with broader search folders.
handle = LoadLibraryExW(pathW.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
}
}
return handle;
}
static inline std::string LoaderPlatformLibraryOpenError(const std::string &path) {
std::stringstream ss;
const DWORD dwLastError = GetLastError();
const std::string strError = DescribeError(dwLastError);
ss << "Failed to open dynamic library " << path << " with error " << dwLastError << ": " << strError;
return ss.str();
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) { FreeLibrary(library); }
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
assert(library);
assert(name.size() > 0);
return reinterpret_cast<void *>(GetProcAddress(library, name.c_str()));
}
static inline std::string LoaderPlatformLibraryGetProcAddrAddrError(const std::string &name) {
std::stringstream ss;
ss << "Failed to find function " << name << " in dynamic library";
return ss.str();
}
#else // Not Linux or Windows
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
static inline LoaderPlatformLibraryHandle LoaderPlatformLibraryOpen(const std::string &path) {
// Stub func
#error("Unknown platform, undefined dynamic library routines resulting");
(void)path;
}
static inline const char *LoaderPlatformLibraryOpenError(const std::string &path) {
// Stub func
(void)path;
}
static inline void LoaderPlatformLibraryClose(LoaderPlatformLibraryHandle library) {
// Stub func
(void)library;
}
static inline void *LoaderPlatformLibraryGetProcAddr(LoaderPlatformLibraryHandle library, const std::string &name) {
// Stub func
void(library);
void(name);
}
static inline const char *LoaderPlatformLibraryGetProcAddrError(const std::string &name) {
// Stub func
(void)name;
}
#endif

View File

@ -0,0 +1,845 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Authors: Mark Young <marky@lunarg.com>, Dave Houlton <daveh@lunarg.com>
//
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif // defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#include "manifest_file.hpp"
#ifdef OPENXR_HAVE_COMMON_CONFIG
#include "common_config.h"
#endif // OPENXR_HAVE_COMMON_CONFIG
#include "filesystem_utils.hpp"
#include "loader_platform.hpp"
#include "platform_utils.hpp"
#include "loader_logger.hpp"
#include <json/json.h>
#include <openxr/openxr.h>
#include <algorithm>
#include <cstring>
#include <fstream>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#ifndef FALLBACK_CONFIG_DIRS
#define FALLBACK_CONFIG_DIRS "/etc/xdg"
#endif // !FALLBACK_CONFIG_DIRS
#ifndef FALLBACK_DATA_DIRS
#define FALLBACK_DATA_DIRS "/usr/local/share:/usr/share"
#endif // !FALLBACK_DATA_DIRS
#ifndef SYSCONFDIR
#define SYSCONFDIR "/etc"
#endif // !SYSCONFDIR
#ifdef XRLOADER_DISABLE_EXCEPTION_HANDLING
#if JSON_USE_EXCEPTIONS
#error \
"Loader is configured to not catch exceptions, but jsoncpp was built with exception-throwing enabled, which could violate the C ABI. One of those two things needs to change."
#endif // JSON_USE_EXCEPTIONS
#endif // !XRLOADER_DISABLE_EXCEPTION_HANDLING
#include "runtime_interface.hpp"
// Utility functions for finding files in the appropriate paths
static inline bool StringEndsWith(const std::string &value, const std::string &ending) {
if (ending.size() > value.size()) {
return false;
}
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
// If the file found is a manifest file name, add it to the out_files manifest list.
static void AddIfJson(const std::string &full_file, std::vector<std::string> &manifest_files) {
if (full_file.empty() || !StringEndsWith(full_file, ".json")) {
return;
}
manifest_files.push_back(full_file);
}
// Check the current path for any manifest files. If the provided search_path is a directory, look for
// all included JSON files in that directory. Otherwise, just check the provided search_path which should
// be a single filename.
static void CheckAllFilesInThePath(const std::string &search_path, bool is_directory_list,
std::vector<std::string> &manifest_files) {
if (FileSysUtilsPathExists(search_path)) {
std::string absolute_path;
if (!is_directory_list) {
// If the file exists, try to add it
if (FileSysUtilsIsRegularFile(search_path)) {
FileSysUtilsGetAbsolutePath(search_path, absolute_path);
AddIfJson(absolute_path, manifest_files);
}
} else {
std::vector<std::string> files;
if (FileSysUtilsFindFilesInPath(search_path, files)) {
for (std::string &cur_file : files) {
std::string relative_path;
FileSysUtilsCombinePaths(search_path, cur_file, relative_path);
if (!FileSysUtilsGetAbsolutePath(relative_path, absolute_path)) {
continue;
}
AddIfJson(absolute_path, manifest_files);
}
}
}
}
}
// Add all manifest files in the provided paths to the manifest_files list. If search_path
// is made up of directory listings (versus direct manifest file names) search each path for
// any manifest files.
static void AddFilesInPath(const std::string &search_path, bool is_directory_list, std::vector<std::string> &manifest_files) {
std::size_t last_found = 0;
std::size_t found = search_path.find_first_of(PATH_SEPARATOR);
std::string cur_search;
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
// substr takes a start index and length.
std::size_t length = found - last_found;
cur_search = search_path.substr(last_found, length);
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
// This works around issue if multiple path separator follow each other directly.
last_found = found;
while (found == last_found) {
last_found = found + 1;
found = search_path.find_first_of(PATH_SEPARATOR, last_found);
}
}
// If there's something remaining in the string, copy it over
if (last_found < search_path.size()) {
cur_search = search_path.substr(last_found);
CheckAllFilesInThePath(cur_search, is_directory_list, manifest_files);
}
}
// Copy all paths listed in the cur_path string into output_path and append the appropriate relative_path onto the end of each.
static void CopyIncludedPaths(bool is_directory_list, const std::string &cur_path, const std::string &relative_path,
std::string &output_path) {
if (!cur_path.empty()) {
std::size_t last_found = 0;
std::size_t found = cur_path.find_first_of(PATH_SEPARATOR);
// Handle any path listings in the string (separated by the appropriate path separator)
while (found != std::string::npos) {
std::size_t length = found - last_found;
output_path += cur_path.substr(last_found, length);
if (is_directory_list && (cur_path[found - 1] != '\\' && cur_path[found - 1] != '/')) {
output_path += DIRECTORY_SYMBOL;
}
output_path += relative_path;
output_path += PATH_SEPARATOR;
last_found = found;
found = cur_path.find_first_of(PATH_SEPARATOR, found + 1);
}
// If there's something remaining in the string, copy it over
size_t last_char = cur_path.size() - 1;
if (last_found != last_char) {
output_path += cur_path.substr(last_found);
if (is_directory_list && (cur_path[last_char] != '\\' && cur_path[last_char] != '/')) {
output_path += DIRECTORY_SYMBOL;
}
output_path += relative_path;
output_path += PATH_SEPARATOR;
}
}
}
// Look for data files in the provided paths, but first check the environment override to determine if we should use that instead.
static void ReadDataFilesInSearchPaths(const std::string &override_env_var, const std::string &relative_path, bool &override_active,
std::vector<std::string> &manifest_files) {
std::string override_path;
std::string search_path;
if (!override_env_var.empty()) {
bool permit_override = true;
#ifndef XR_OS_WINDOWS
if (geteuid() != getuid() || getegid() != getgid()) {
// Don't allow setuid apps to use the env var
permit_override = false;
}
#endif
if (permit_override) {
override_path = PlatformUtilsGetSecureEnv(override_env_var.c_str());
}
}
if (!override_path.empty()) {
CopyIncludedPaths(true, override_path, "", search_path);
override_active = true;
} else {
override_active = false;
#if !defined(XR_OS_WINDOWS) && !defined(XR_OS_ANDROID)
const char home_additional[] = ".local/share/";
// Determine how much space is needed to generate the full search path
// for the current manifest files.
std::string xdg_conf_dirs = PlatformUtilsGetSecureEnv("XDG_CONFIG_DIRS");
std::string xdg_data_dirs = PlatformUtilsGetSecureEnv("XDG_DATA_DIRS");
std::string xdg_data_home = PlatformUtilsGetSecureEnv("XDG_DATA_HOME");
std::string home = PlatformUtilsGetSecureEnv("HOME");
if (xdg_conf_dirs.empty()) {
CopyIncludedPaths(true, FALLBACK_CONFIG_DIRS, relative_path, search_path);
} else {
CopyIncludedPaths(true, xdg_conf_dirs, relative_path, search_path);
}
CopyIncludedPaths(true, SYSCONFDIR, relative_path, search_path);
#if defined(EXTRASYSCONFDIR)
CopyIncludedPaths(true, EXTRASYSCONFDIR, relative_path, search_path);
#endif
if (xdg_data_dirs.empty()) {
CopyIncludedPaths(true, FALLBACK_DATA_DIRS, relative_path, search_path);
} else {
CopyIncludedPaths(true, xdg_data_dirs, relative_path, search_path);
}
if (!xdg_data_home.empty()) {
CopyIncludedPaths(true, xdg_data_home, relative_path, search_path);
} else if (!home.empty()) {
std::string relative_home_path = home_additional;
relative_home_path += relative_path;
CopyIncludedPaths(true, home, relative_home_path, search_path);
}
#else
(void)relative_path;
#endif
}
// Now, parse the paths and add any manifest files found in them.
AddFilesInPath(search_path, true, manifest_files);
}
#ifdef XR_OS_LINUX
// Get an XDG environment variable with a $HOME-relative default
static std::string GetXDGEnvHome(const char *name, const char *fallback_path) {
std::string result = PlatformUtilsGetSecureEnv(name);
if (!result.empty()) {
return result;
}
result = PlatformUtilsGetSecureEnv("HOME");
if (result.empty()) {
return result;
}
result += "/";
result += fallback_path;
return result;
}
// Get an XDG environment variable with absolute defaults
static std::string GetXDGEnvAbsolute(const char *name, const char *fallback_paths) {
std::string result = PlatformUtilsGetSecureEnv(name);
if (!result.empty()) {
return result;
}
return fallback_paths;
}
// Return the first instance of relative_path occurring in an XDG config dir according to standard
// precedence order.
static bool FindXDGConfigFile(const std::string &relative_path, std::string &out) {
out = GetXDGEnvHome("XDG_CONFIG_HOME", ".config");
if (!out.empty()) {
out += "/";
out += relative_path;
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in XDG_CONFIG_HOME: " + out);
if (FileSysUtilsPathExists(out)) {
return true;
}
}
std::istringstream iss(GetXDGEnvAbsolute("XDG_CONFIG_DIRS", FALLBACK_CONFIG_DIRS));
std::string path;
while (std::getline(iss, path, PATH_SEPARATOR)) {
if (path.empty()) {
continue;
}
out = path;
out += "/";
out += relative_path;
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in an entry of XDG_CONFIG_DIRS: " + out);
if (FileSysUtilsPathExists(out)) {
return true;
}
}
out = SYSCONFDIR;
out += "/";
out += relative_path;
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in SYSCONFDIR: " + out);
if (FileSysUtilsPathExists(out)) {
return true;
}
#if defined(EXTRASYSCONFDIR)
out = EXTRASYSCONFDIR;
out += "/";
out += relative_path;
LoaderLogger::LogInfoMessage("", "Looking for " + relative_path + " in compiled-in EXTRASYSCONFDIR: " + out);
if (FileSysUtilsPathExists(out)) {
return true;
}
#endif
out.clear();
return false;
}
#endif
#ifdef XR_OS_WINDOWS
// Look for runtime data files in the provided paths, but first check the environment override to determine
// if we should use that instead.
static void ReadRuntimeDataFilesInRegistry(const std::string &runtime_registry_location,
const std::string &default_runtime_value_name,
std::vector<std::string> &manifest_files) {
HKEY hkey;
DWORD access_flags;
wchar_t value_w[1024];
DWORD value_size_w = sizeof(value_w); // byte size of the buffer.
// Generate the full registry location for the registry information
std::string full_registry_location = OPENXR_REGISTRY_LOCATION;
full_registry_location += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
full_registry_location += runtime_registry_location;
const std::wstring full_registry_location_w = utf8_to_wide(full_registry_location);
const std::wstring default_runtime_value_name_w = utf8_to_wide(default_runtime_value_name);
// Use 64 bit regkey for 64bit application, and use 32 bit regkey in WOW for 32bit application.
access_flags = KEY_QUERY_VALUE;
LONG open_value = RegOpenKeyExW(HKEY_LOCAL_MACHINE, full_registry_location_w.c_str(), 0, access_flags, &hkey);
if (ERROR_SUCCESS != open_value) {
LoaderLogger::LogWarningMessage("",
"ReadRuntimeDataFilesInRegistry - failed to open registry key " + full_registry_location);
} else if (ERROR_SUCCESS != RegGetValueW(hkey, nullptr, default_runtime_value_name_w.c_str(),
RRF_RT_REG_SZ | REG_EXPAND_SZ | RRF_ZEROONFAILURE, NULL,
reinterpret_cast<LPBYTE>(&value_w), &value_size_w)) {
LoaderLogger::LogWarningMessage(
"", "ReadRuntimeDataFilesInRegistry - failed to read registry value " + default_runtime_value_name);
} else {
AddFilesInPath(wide_to_utf8(value_w), false, manifest_files);
}
}
// Look for layer data files in the provided paths, but first check the environment override to determine
// if we should use that instead.
static void ReadLayerDataFilesInRegistry(const std::string &registry_location, std::vector<std::string> &manifest_files) {
const std::wstring full_registry_location_w =
utf8_to_wide(OPENXR_REGISTRY_LOCATION + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + registry_location);
auto ReadLayerDataFilesInHive = [&](HKEY hive) {
HKEY hkey;
LONG open_value = RegOpenKeyExW(hive, full_registry_location_w.c_str(), 0, KEY_QUERY_VALUE, &hkey);
if (ERROR_SUCCESS != open_value) {
return false;
}
wchar_t name_w[1024]{};
LONG rtn_value;
DWORD name_size = 1023;
DWORD value;
DWORD value_size = sizeof(value);
DWORD key_index = 0;
while (ERROR_SUCCESS ==
(rtn_value = RegEnumValueW(hkey, key_index++, name_w, &name_size, NULL, NULL, (LPBYTE)&value, &value_size))) {
if (value_size == sizeof(value) && value == 0) {
const std::string filename = wide_to_utf8(name_w);
AddFilesInPath(filename, false, manifest_files);
}
// Reset some items for the next loop
name_size = 1023;
}
RegCloseKey(hkey);
return true;
};
// Do not allow high integrity processes to act on data that can be controlled by medium integrity processes.
const bool readFromCurrentUser = !IsHighIntegrityLevel();
bool found = ReadLayerDataFilesInHive(HKEY_LOCAL_MACHINE);
if (readFromCurrentUser) {
found |= ReadLayerDataFilesInHive(HKEY_CURRENT_USER);
}
if (!found) {
std::string warning_message = "ReadLayerDataFilesInRegistry - failed to read registry location ";
warning_message += registry_location;
warning_message += (readFromCurrentUser ? " in either HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER" : " in HKEY_LOCAL_MACHINE");
LoaderLogger::LogWarningMessage("", warning_message);
}
}
#endif // XR_OS_WINDOWS
ManifestFile::ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path)
: _filename(filename), _type(type), _library_path(library_path) {}
bool ManifestFile::IsValidJson(const Json::Value &root_node, JsonVersion &version) {
if (root_node["file_format_version"].isNull() || !root_node["file_format_version"].isString()) {
LoaderLogger::LogErrorMessage("", "ManifestFile::IsValidJson - JSON file missing \"file_format_version\"");
return false;
}
std::string file_format = root_node["file_format_version"].asString();
const int num_fields = sscanf(file_format.c_str(), "%u.%u.%u", &version.major, &version.minor, &version.patch);
// Only version 1.0.0 is defined currently. Eventually we may have more version, but
// some of the versions may only be valid for layers or runtimes specifically.
if (num_fields != 3 || version.major != 1 || version.minor != 0 || version.patch != 0) {
std::ostringstream error_ss;
error_ss << "ManifestFile::IsValidJson - JSON \"file_format_version\" " << version.major << "." << version.minor << "."
<< version.patch << " is not supported";
LoaderLogger::LogErrorMessage("", error_ss.str());
return false;
}
return true;
}
static void GetExtensionProperties(const std::vector<ExtensionListing> &extensions, std::vector<XrExtensionProperties> &props) {
for (const auto &ext : extensions) {
auto it =
std::find_if(props.begin(), props.end(), [&](XrExtensionProperties &prop) { return prop.extensionName == ext.name; });
if (it != props.end()) {
it->extensionVersion = std::max(it->extensionVersion, ext.extension_version);
} else {
XrExtensionProperties prop = {};
prop.type = XR_TYPE_EXTENSION_PROPERTIES;
prop.next = nullptr;
strncpy(prop.extensionName, ext.name.c_str(), XR_MAX_EXTENSION_NAME_SIZE - 1);
prop.extensionName[XR_MAX_EXTENSION_NAME_SIZE - 1] = '\0';
prop.extensionVersion = ext.extension_version;
props.push_back(prop);
}
}
}
// Return any instance extensions found in the manifest files in the proper form for
// OpenXR (XrExtensionProperties).
void ManifestFile::GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props) {
GetExtensionProperties(_instance_extensions, props);
}
const std::string &ManifestFile::GetFunctionName(const std::string &func_name) const {
if (!_functions_renamed.empty()) {
auto found = _functions_renamed.find(func_name);
if (found != _functions_renamed.end()) {
return found->second;
}
}
return func_name;
}
RuntimeManifestFile::RuntimeManifestFile(const std::string &filename, const std::string &library_path)
: ManifestFile(MANIFEST_TYPE_RUNTIME, filename, library_path) {}
static void ParseExtension(Json::Value const &ext, std::vector<ExtensionListing> &extensions) {
Json::Value ext_name = ext["name"];
Json::Value ext_version = ext["extension_version"];
// Allow "extension_version" as a String or a UInt to maintain backwards compatibility, even though it should be a String.
// Internal Issue 1411: https://gitlab.khronos.org/openxr/openxr/-/issues/1411
// Internal MR !1867: https://gitlab.khronos.org/openxr/openxr/-/merge_requests/1867
if (ext_name.isString() && (ext_version.isString() || ext_version.isUInt())) {
ExtensionListing ext_listing = {};
ext_listing.name = ext_name.asString();
if (ext_version.isUInt()) {
ext_listing.extension_version = ext_version.asUInt();
} else {
ext_listing.extension_version = atoi(ext_version.asString().c_str());
}
extensions.push_back(ext_listing);
}
}
void ManifestFile::ParseCommon(Json::Value const &root_node) {
const Json::Value &inst_exts = root_node["instance_extensions"];
if (!inst_exts.isNull() && inst_exts.isArray()) {
for (const auto &ext : inst_exts) {
ParseExtension(ext, _instance_extensions);
}
}
const Json::Value &funcs_renamed = root_node["functions"];
if (!funcs_renamed.isNull() && !funcs_renamed.empty()) {
for (Json::ValueConstIterator func_it = funcs_renamed.begin(); func_it != funcs_renamed.end(); ++func_it) {
if (!(*func_it).isString()) {
LoaderLogger::LogWarningMessage(
"", "ManifestFile::ParseCommon " + _filename + " \"functions\" section contains non-string values.");
continue;
}
std::string original_name = func_it.key().asString();
std::string new_name = (*func_it).asString();
_functions_renamed.emplace(original_name, new_name);
}
}
}
void RuntimeManifestFile::CreateIfValid(std::string const &filename,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
std::ifstream json_stream(filename, std::ifstream::in);
LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::CreateIfValid - attempting to load " + filename);
std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid ");
if (!json_stream.is_open()) {
error_ss << "failed to open " << filename << ". Does it exist?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
Json::CharReaderBuilder builder;
std::string errors;
Json::Value root_node = Json::nullValue;
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
error_ss << "failed to parse " << filename << ".";
if (!errors.empty()) {
error_ss << " (Error message: " << errors << ")";
}
error_ss << " Is it a valid runtime manifest file?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
CreateIfValid(root_node, filename, manifest_files);
}
void RuntimeManifestFile::CreateIfValid(const Json::Value &root_node, const std::string &filename,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
std::ostringstream error_ss("RuntimeManifestFile::CreateIfValid ");
JsonVersion file_version = {};
if (!ManifestFile::IsValidJson(root_node, file_version)) {
error_ss << "isValidJson indicates " << filename << " is not a valid manifest file.";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
const Json::Value &runtime_root_node = root_node["runtime"];
// The Runtime manifest file needs the "runtime" root as well as a sub-node for "library_path". If any of those aren't there,
// fail.
if (runtime_root_node.isNull() || runtime_root_node["library_path"].isNull() || !runtime_root_node["library_path"].isString()) {
error_ss << filename << " is missing required fields. Verify all proper fields exist.";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
std::string lib_path = runtime_root_node["library_path"].asString();
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
// global library path.
if (lib_path.find('\\') != std::string::npos || lib_path.find('/') != std::string::npos) {
// If the library_path is an absolute path, just use that if it exists
if (FileSysUtilsIsAbsolutePath(lib_path)) {
if (!FileSysUtilsPathExists(lib_path)) {
error_ss << filename << " library " << lib_path << " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
} else {
// Otherwise, treat the library path as a relative path based on the JSON file.
std::string canonical_path;
std::string combined_path;
std::string file_parent;
// Search relative to the real manifest file, not relative to the symlink
if (!FileSysUtilsGetCanonicalPath(filename, canonical_path)) {
// Give relative to the non-canonical path a chance
canonical_path = filename;
}
if (!FileSysUtilsGetParentPath(canonical_path, file_parent) ||
!FileSysUtilsCombinePaths(file_parent, lib_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
error_ss << filename << " library " << combined_path << " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
lib_path = combined_path;
}
}
// Add this runtime manifest file
manifest_files.emplace_back(new RuntimeManifestFile(filename, lib_path));
// Add any extensions to it after the fact.
// Handle any renamed functions
manifest_files.back()->ParseCommon(runtime_root_node);
}
// Find all manifest files in the appropriate search paths/registries for the given type.
XrResult RuntimeManifestFile::FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files) {
XrResult result = XR_SUCCESS;
std::string filename = PlatformUtilsGetSecureEnv(OPENXR_RUNTIME_JSON_ENV_VAR);
if (!filename.empty()) {
LoaderLogger::LogInfoMessage(
"", "RuntimeManifestFile::FindManifestFiles - using environment variable override runtime file " + filename);
} else {
#ifdef XR_OS_WINDOWS
std::vector<std::string> filenames;
ReadRuntimeDataFilesInRegistry("", "ActiveRuntime", filenames);
if (filenames.size() == 0) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to find active runtime file in registry");
return XR_ERROR_RUNTIME_UNAVAILABLE;
}
if (filenames.size() > 1) {
LoaderLogger::LogWarningMessage(
"", "RuntimeManifestFile::FindManifestFiles - found too many default runtime files in registry");
}
filename = filenames[0];
LoaderLogger::LogInfoMessage("",
"RuntimeManifestFile::FindManifestFiles - using registry-specified runtime file " + filename);
#elif defined(XR_OS_LINUX)
const std::string relative_path =
"openxr/" + std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) + "/active_runtime.json";
if (!FindXDGConfigFile(relative_path, filename)) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
return XR_ERROR_RUNTIME_UNAVAILABLE;
}
#else
#if defined(XR_KHR_LOADER_INIT_SUPPORT)
Json::Value virtualManifest;
result = GetPlatformRuntimeVirtualManifest(virtualManifest);
if (XR_SUCCESS == result) {
RuntimeManifestFile::CreateIfValid(virtualManifest, "", manifest_files);
return result;
}
#endif // defined(XR_KHR_LOADER_INIT_SUPPORT)
if (!PlatformGetGlobalRuntimeFileName(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION), filename)) {
LoaderLogger::LogErrorMessage(
"", "RuntimeManifestFile::FindManifestFiles - failed to determine active runtime file path for this environment");
return XR_ERROR_RUNTIME_UNAVAILABLE;
}
result = XR_SUCCESS;
LoaderLogger::LogInfoMessage("", "RuntimeManifestFile::FindManifestFiles - using global runtime file " + filename);
#endif
}
RuntimeManifestFile::CreateIfValid(filename, manifest_files);
return result;
}
ApiLayerManifestFile::ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
const std::string &description, const JsonVersion &api_version,
const uint32_t &implementation_version, const std::string &library_path)
: ManifestFile(type, filename, library_path),
_api_version(api_version),
_layer_name(layer_name),
_description(description),
_implementation_version(implementation_version) {}
void ApiLayerManifestFile::CreateIfValid(ManifestFileType type, const std::string &filename,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::ifstream json_stream(filename, std::ifstream::in);
std::ostringstream error_ss("ApiLayerManifestFile::CreateIfValid ");
if (!json_stream.is_open()) {
error_ss << "failed to open " << filename << ". Does it exist?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
Json::CharReaderBuilder builder;
std::string errors;
Json::Value root_node = Json::nullValue;
if (!Json::parseFromStream(builder, json_stream, &root_node, &errors) || !root_node.isObject()) {
error_ss << "failed to parse " << filename << ".";
if (!errors.empty()) {
error_ss << " (Error message: " << errors << ")";
}
error_ss << " Is it a valid layer manifest file?";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
JsonVersion file_version = {};
if (!ManifestFile::IsValidJson(root_node, file_version)) {
error_ss << "isValidJson indicates " << filename << " is not a valid manifest file.";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
Json::Value layer_root_node = root_node["api_layer"];
// The API Layer manifest file needs the "api_layer" root as well as other sub-nodes.
// If any of those aren't there, fail.
if (layer_root_node.isNull() || layer_root_node["name"].isNull() || !layer_root_node["name"].isString() ||
layer_root_node["api_version"].isNull() || !layer_root_node["api_version"].isString() ||
layer_root_node["library_path"].isNull() || !layer_root_node["library_path"].isString() ||
layer_root_node["implementation_version"].isNull() || !layer_root_node["implementation_version"].isString()) {
error_ss << filename << " is missing required fields. Verify all proper fields exist.";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
if (MANIFEST_TYPE_IMPLICIT_API_LAYER == type) {
bool enabled = true;
// Implicit layers require the disable environment variable.
if (layer_root_node["disable_environment"].isNull() || !layer_root_node["disable_environment"].isString()) {
error_ss << "Implicit layer " << filename << " is missing \"disable_environment\"";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
// Check if there's an enable environment variable provided
if (!layer_root_node["enable_environment"].isNull() && layer_root_node["enable_environment"].isString()) {
std::string env_var = layer_root_node["enable_environment"].asString();
// If it's not set in the environment, disable the layer
if (!PlatformUtilsGetEnvSet(env_var.c_str())) {
enabled = false;
}
}
// Check for the disable environment variable, which must be provided in the JSON
std::string env_var = layer_root_node["disable_environment"].asString();
// If the env var is set, disable the layer. Disable env var overrides enable above
if (PlatformUtilsGetEnvSet(env_var.c_str())) {
enabled = false;
}
// Not enabled, so pretend like it isn't even there.
if (!enabled) {
error_ss << "Implicit layer " << filename << " is disabled";
LoaderLogger::LogInfoMessage("", error_ss.str());
return;
}
}
std::string layer_name = layer_root_node["name"].asString();
std::string api_version_string = layer_root_node["api_version"].asString();
JsonVersion api_version = {};
const int num_fields = sscanf(api_version_string.c_str(), "%u.%u", &api_version.major, &api_version.minor);
api_version.patch = 0;
if ((num_fields != 2) || (api_version.major == 0 && api_version.minor == 0) ||
api_version.major > XR_VERSION_MAJOR(XR_CURRENT_API_VERSION)) {
error_ss << "layer " << filename << " has invalid API Version. Skipping layer.";
LoaderLogger::LogWarningMessage("", error_ss.str());
return;
}
uint32_t implementation_version = atoi(layer_root_node["implementation_version"].asString().c_str());
std::string library_path = layer_root_node["library_path"].asString();
// If the library_path variable has no directory symbol, it's just a file name and should be accessible on the
// global library path.
if (library_path.find('\\') != std::string::npos || library_path.find('/') != std::string::npos) {
// If the library_path is an absolute path, just use that if it exists
if (FileSysUtilsIsAbsolutePath(library_path)) {
if (!FileSysUtilsPathExists(library_path)) {
error_ss << filename << " library " << library_path << " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
} else {
// Otherwise, treat the library path as a relative path based on the JSON file.
std::string combined_path;
std::string file_parent;
if (!FileSysUtilsGetParentPath(filename, file_parent) ||
!FileSysUtilsCombinePaths(file_parent, library_path, combined_path) || !FileSysUtilsPathExists(combined_path)) {
error_ss << filename << " library " << combined_path << " does not appear to exist";
LoaderLogger::LogErrorMessage("", error_ss.str());
return;
}
library_path = combined_path;
}
}
std::string description;
if (!layer_root_node["description"].isNull() && layer_root_node["description"].isString()) {
description = layer_root_node["description"].asString();
}
// Add this layer manifest file
manifest_files.emplace_back(
new ApiLayerManifestFile(type, filename, layer_name, description, api_version, implementation_version, library_path));
// Add any extensions to it after the fact.
manifest_files.back()->ParseCommon(layer_root_node);
}
void ApiLayerManifestFile::PopulateApiLayerProperties(XrApiLayerProperties &props) const {
props.layerVersion = _implementation_version;
props.specVersion = XR_MAKE_VERSION(_api_version.major, _api_version.minor, _api_version.patch);
strncpy(props.layerName, _layer_name.c_str(), XR_MAX_API_LAYER_NAME_SIZE - 1);
if (_layer_name.size() >= XR_MAX_API_LAYER_NAME_SIZE - 1) {
props.layerName[XR_MAX_API_LAYER_NAME_SIZE - 1] = '\0';
}
strncpy(props.description, _description.c_str(), XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1);
if (_description.size() >= XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1) {
props.description[XR_MAX_API_LAYER_DESCRIPTION_SIZE - 1] = '\0';
}
}
// Find all layer manifest files in the appropriate search paths/registries for the given type.
XrResult ApiLayerManifestFile::FindManifestFiles(ManifestFileType type,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files) {
std::string relative_path;
std::string override_env_var;
std::string registry_location;
// Add the appropriate top-level folders for the relative path. These should be
// the string "openxr/" followed by the API major version as a string.
relative_path = OPENXR_RELATIVE_PATH;
relative_path += std::to_string(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION));
switch (type) {
case MANIFEST_TYPE_IMPLICIT_API_LAYER:
relative_path += OPENXR_IMPLICIT_API_LAYER_RELATIVE_PATH;
override_env_var = "";
#ifdef XR_OS_WINDOWS
registry_location = OPENXR_IMPLICIT_API_LAYER_REGISTRY_LOCATION;
#endif
break;
case MANIFEST_TYPE_EXPLICIT_API_LAYER:
relative_path += OPENXR_EXPLICIT_API_LAYER_RELATIVE_PATH;
override_env_var = OPENXR_API_LAYER_PATH_ENV_VAR;
#ifdef XR_OS_WINDOWS
registry_location = OPENXR_EXPLICIT_API_LAYER_REGISTRY_LOCATION;
#endif
break;
default:
LoaderLogger::LogErrorMessage("", "ApiLayerManifestFile::FindManifestFiles - unknown manifest file requested");
return XR_ERROR_FILE_ACCESS_ERROR;
}
bool override_active = false;
std::vector<std::string> filenames;
ReadDataFilesInSearchPaths(override_env_var, relative_path, override_active, filenames);
#ifdef XR_OS_WINDOWS
// Read the registry if the override wasn't active.
if (!override_active) {
ReadLayerDataFilesInRegistry(registry_location, filenames);
}
#endif
for (std::string &cur_file : filenames) {
ApiLayerManifestFile::CreateIfValid(type, cur_file, manifest_files);
}
return XR_SUCCESS;
}

View File

@ -0,0 +1,103 @@
// Copyright (c) 2017 The Khronos Group Inc.
// Copyright (c) 2017 Valve Corporation
// Copyright (c) 2017 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <openxr/openxr.h>
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
namespace Json {
class Value;
}
enum ManifestFileType {
MANIFEST_TYPE_UNDEFINED = 0,
MANIFEST_TYPE_RUNTIME,
MANIFEST_TYPE_IMPLICIT_API_LAYER,
MANIFEST_TYPE_EXPLICIT_API_LAYER,
};
struct JsonVersion {
uint32_t major;
uint32_t minor;
uint32_t patch;
};
struct ExtensionListing {
std::string name;
uint32_t extension_version;
};
// ManifestFile class -
// Base class responsible for finding and parsing manifest files.
class ManifestFile {
public:
// Non-copyable
ManifestFile(const ManifestFile &) = delete;
ManifestFile &operator=(const ManifestFile &) = delete;
ManifestFileType Type() const { return _type; }
const std::string &Filename() const { return _filename; }
const std::string &LibraryPath() const { return _library_path; }
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties> &props);
const std::string &GetFunctionName(const std::string &func_name) const;
protected:
ManifestFile(ManifestFileType type, const std::string &filename, const std::string &library_path);
void ParseCommon(Json::Value const &root_node);
static bool IsValidJson(const Json::Value &root, JsonVersion &version);
private:
std::string _filename;
ManifestFileType _type;
std::string _library_path;
std::vector<ExtensionListing> _instance_extensions;
std::unordered_map<std::string, std::string> _functions_renamed;
};
// RuntimeManifestFile class -
// Responsible for finding and parsing Runtime-specific manifest files.
class RuntimeManifestFile : public ManifestFile {
public:
// Factory method
static XrResult FindManifestFiles(std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
private:
RuntimeManifestFile(const std::string &filename, const std::string &library_path);
static void CreateIfValid(const std::string &filename, std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
static void CreateIfValid(const Json::Value &root_node, const std::string &filename,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
};
// ApiLayerManifestFile class -
// Responsible for finding and parsing API Layer-specific manifest files.
class ApiLayerManifestFile : public ManifestFile {
public:
// Factory method
static XrResult FindManifestFiles(ManifestFileType type, std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
const std::string &LayerName() const { return _layer_name; }
void PopulateApiLayerProperties(XrApiLayerProperties &props) const;
private:
ApiLayerManifestFile(ManifestFileType type, const std::string &filename, const std::string &layer_name,
const std::string &description, const JsonVersion &api_version, const uint32_t &implementation_version,
const std::string &library_path);
static void CreateIfValid(ManifestFileType type, const std::string &filename,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
JsonVersion _api_version;
std::string _layer_name;
std::string _description;
uint32_t _implementation_version;
};

View File

@ -0,0 +1,493 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#include "runtime_interface.hpp"
#include "manifest_file.hpp"
#include "loader_interfaces.h"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "xr_generated_dispatch_table.h"
#include <openxr/openxr.h>
#include <cstring>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#ifdef XR_USE_PLATFORM_ANDROID
#include "android_utilities.h"
#include <json/value.h>
#endif // XR_USE_PLATFORM_ANDROID
#ifdef XR_KHR_LOADER_INIT_SUPPORT
namespace {
/*!
* Stores a copy of the data passed to the xrInitializeLoaderKHR function in a singleton.
*/
class LoaderInitData {
public:
/*!
* Singleton accessor.
*/
static LoaderInitData& instance() {
static LoaderInitData obj;
return obj;
}
#ifdef XR_USE_PLATFORM_ANDROID
/*!
* Type alias for the platform-specific structure type.
*/
using StructType = XrLoaderInitInfoAndroidKHR;
#endif
/*!
* Get our copy of the data, casted to pass to the runtime's matching method.
*/
const XrLoaderInitInfoBaseHeaderKHR* getParam() const { return reinterpret_cast<const XrLoaderInitInfoBaseHeaderKHR*>(&_data); }
/*!
* Get the data via its real structure type.
*/
const StructType& getData() const { return _data; }
/*!
* Has this been correctly initialized?
*/
bool initialized() const noexcept { return _initialized; }
/*!
* Initialize loader data - called by InitializeLoader() and thus ultimately by the loader's xrInitializeLoaderKHR
* implementation. Each platform that needs this extension will provide an implementation of this.
*/
XrResult initialize(const XrLoaderInitInfoBaseHeaderKHR* info);
private:
//! Private constructor, forces use of singleton accessor.
LoaderInitData() = default;
//! Platform-specific init data
StructType _data = {};
//! Flag for indicating whether _data is valid.
bool _initialized = false;
};
#ifdef XR_USE_PLATFORM_ANDROID
// Check and copy the Android-specific init data.
XrResult LoaderInitData::initialize(const XrLoaderInitInfoBaseHeaderKHR* info) {
if (info->type != XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) {
return XR_ERROR_VALIDATION_FAILURE;
}
auto cast_info = reinterpret_cast<XrLoaderInitInfoAndroidKHR const*>(info);
if (cast_info->applicationVM == nullptr) {
return XR_ERROR_VALIDATION_FAILURE;
}
if (cast_info->applicationContext == nullptr) {
return XR_ERROR_VALIDATION_FAILURE;
}
_data = *cast_info;
jni::init((jni::JavaVM*)_data.applicationVM);
_data.next = nullptr;
_initialized = true;
return XR_SUCCESS;
}
#endif // XR_USE_PLATFORM_ANDROID
} // namespace
XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo) {
return LoaderInitData::instance().initialize(loaderInitInfo);
}
#endif // XR_KHR_LOADER_INIT_SUPPORT
#ifdef XR_USE_PLATFORM_ANDROID
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest) {
using wrap::android::content::Context;
auto& initData = LoaderInitData::instance();
if (!initData.initialized()) {
return XR_ERROR_INITIALIZATION_FAILED;
}
auto context = Context(reinterpret_cast<jobject>(initData.getData().applicationContext));
if (context.isNull()) {
return XR_ERROR_INITIALIZATION_FAILED;
}
Json::Value virtualManifest;
if (0 != openxr_android::getActiveRuntimeVirtualManifest(context, virtualManifest)) {
return XR_ERROR_INITIALIZATION_FAILED;
}
out_manifest = virtualManifest;
return XR_SUCCESS;
}
#endif // XR_USE_PLATFORM_ANDROID
XrResult RuntimeInterface::TryLoadingSingleRuntime(const std::string& openxr_command,
std::unique_ptr<RuntimeManifestFile>& manifest_file) {
LoaderPlatformLibraryHandle runtime_library = LoaderPlatformLibraryOpen(manifest_file->LibraryPath());
if (nullptr == runtime_library) {
std::string library_message = LoaderPlatformLibraryOpenError(manifest_file->LibraryPath());
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
warning_message += manifest_file->Filename();
warning_message += ", failed to load with message \"";
warning_message += library_message;
warning_message += "\"";
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
return XR_ERROR_FILE_ACCESS_ERROR;
}
#ifdef XR_KHR_LOADER_INIT_SUPPORT
if (!LoaderInitData::instance().initialized()) {
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntime skipping manifest file " +
manifest_file->Filename() +
" because xrInitializeLoaderKHR was not yet called.");
LoaderPlatformLibraryClose(runtime_library);
return XR_ERROR_VALIDATION_FAILURE;
}
bool forwardedInitLoader = false;
{
// If we have xrInitializeLoaderKHR exposed as an export, forward call to it.
const auto function_name = manifest_file->GetFunctionName("xrInitializeLoaderKHR");
auto initLoader =
reinterpret_cast<PFN_xrInitializeLoaderKHR>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));
if (initLoader != nullptr) {
// we found the entry point one way or another.
LoaderLogger::LogInfoMessage(openxr_command,
"RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime before "
"calling xrNegotiateLoaderRuntimeInterface.");
XrResult res = initLoader(LoaderInitData::instance().getParam());
if (!XR_SUCCEEDED(res)) {
LoaderLogger::LogErrorMessage(openxr_command,
"RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed.");
LoaderPlatformLibraryClose(runtime_library);
return res;
}
forwardedInitLoader = true;
}
}
#endif
// Get and settle on an runtime interface version (using any provided name if required).
std::string function_name = manifest_file->GetFunctionName("xrNegotiateLoaderRuntimeInterface");
auto negotiate =
reinterpret_cast<PFN_xrNegotiateLoaderRuntimeInterface>(LoaderPlatformLibraryGetProcAddr(runtime_library, function_name));
// Loader info for negotiation
XrNegotiateLoaderInfo loader_info = {};
loader_info.structType = XR_LOADER_INTERFACE_STRUCT_LOADER_INFO;
loader_info.structVersion = XR_LOADER_INFO_STRUCT_VERSION;
loader_info.structSize = sizeof(XrNegotiateLoaderInfo);
loader_info.minInterfaceVersion = 1;
loader_info.maxInterfaceVersion = XR_CURRENT_LOADER_RUNTIME_VERSION;
loader_info.minApiVersion = XR_MAKE_VERSION(1, 0, 0);
loader_info.maxApiVersion = XR_MAKE_VERSION(1, 0x3ff, 0xfff); // Maximum allowed version for this major version.
// Set up the runtime return structure
XrNegotiateRuntimeRequest runtime_info = {};
runtime_info.structType = XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST;
runtime_info.structVersion = XR_RUNTIME_INFO_STRUCT_VERSION;
runtime_info.structSize = sizeof(XrNegotiateRuntimeRequest);
// Skip calling the negotiate function and fail if the function pointer
// could not get loaded
XrResult res = XR_ERROR_RUNTIME_FAILURE;
if (nullptr != negotiate) {
res = negotiate(&loader_info, &runtime_info);
}
// If we supposedly succeeded, but got a nullptr for GetInstanceProcAddr
// then something still went wrong, so return with an error.
if (XR_SUCCEEDED(res)) {
uint32_t runtime_major = XR_VERSION_MAJOR(runtime_info.runtimeApiVersion);
uint32_t runtime_minor = XR_VERSION_MINOR(runtime_info.runtimeApiVersion);
uint32_t loader_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
if (nullptr == runtime_info.getInstanceProcAddr) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", negotiation succeeded but returned NULL getInstanceProcAddr";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
} else if (0 >= runtime_info.runtimeInterfaceVersion ||
XR_CURRENT_LOADER_RUNTIME_VERSION < runtime_info.runtimeInterfaceVersion) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", negotiation succeeded but returned invalid interface version";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
} else if (runtime_major != loader_major || (runtime_major == 0 && runtime_minor == 0)) {
std::string error_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
error_message += manifest_file->Filename();
error_message += ", OpenXR version returned not compatible with this loader";
LoaderLogger::LogErrorMessage(openxr_command, error_message);
res = XR_ERROR_FILE_CONTENTS_INVALID;
}
}
#ifdef XR_KHR_LOADER_INIT_SUPPORT
if (XR_SUCCEEDED(res) && !forwardedInitLoader) {
// Forward initialize loader call, where possible and if we did not do so before.
PFN_xrVoidFunction initializeVoid = nullptr;
PFN_xrInitializeLoaderKHR initialize = nullptr;
// Now we may try asking xrGetInstanceProcAddr
if (XR_SUCCEEDED(runtime_info.getInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", &initializeVoid))) {
if (initializeVoid == nullptr) {
LoaderLogger::LogErrorMessage(openxr_command,
"RuntimeInterface::LoadRuntime got success from xrGetInstanceProcAddr "
"for xrInitializeLoaderKHR, but output a null pointer.");
res = XR_ERROR_RUNTIME_FAILURE;
} else {
initialize = reinterpret_cast<PFN_xrInitializeLoaderKHR>(initializeVoid);
}
}
if (initialize != nullptr) {
// we found the entry point one way or another.
LoaderLogger::LogInfoMessage(openxr_command,
"RuntimeInterface::LoadRuntime forwarding xrInitializeLoaderKHR call to runtime after "
"calling xrNegotiateLoaderRuntimeInterface.");
res = initialize(LoaderInitData::instance().getParam());
if (!XR_SUCCEEDED(res)) {
LoaderLogger::LogErrorMessage(openxr_command,
"RuntimeInterface::LoadRuntime forwarded call to xrInitializeLoaderKHR failed.");
}
}
}
#endif
if (XR_FAILED(res)) {
std::string warning_message = "RuntimeInterface::LoadRuntime skipping manifest file ";
warning_message += manifest_file->Filename();
warning_message += ", negotiation failed with error ";
warning_message += std::to_string(res);
LoaderLogger::LogErrorMessage(openxr_command, warning_message);
LoaderPlatformLibraryClose(runtime_library);
return res;
}
std::string info_message = "RuntimeInterface::LoadRuntime succeeded loading runtime defined in manifest file ";
info_message += manifest_file->Filename();
info_message += " using interface version ";
info_message += std::to_string(runtime_info.runtimeInterfaceVersion);
info_message += " and OpenXR API version ";
info_message += std::to_string(XR_VERSION_MAJOR(runtime_info.runtimeApiVersion));
info_message += ".";
info_message += std::to_string(XR_VERSION_MINOR(runtime_info.runtimeApiVersion));
LoaderLogger::LogInfoMessage(openxr_command, info_message);
// Use this runtime
GetInstance().reset(new RuntimeInterface(runtime_library, runtime_info.getInstanceProcAddr));
// Grab the list of extensions this runtime supports for easy filtering after the
// xrCreateInstance call
std::vector<std::string> supported_extensions;
std::vector<XrExtensionProperties> extension_properties;
GetInstance()->GetInstanceExtensionProperties(extension_properties);
supported_extensions.reserve(extension_properties.size());
for (XrExtensionProperties ext_prop : extension_properties) {
supported_extensions.emplace_back(ext_prop.extensionName);
}
GetInstance()->SetSupportedExtensions(supported_extensions);
return XR_SUCCESS;
}
XrResult RuntimeInterface::LoadRuntime(const std::string& openxr_command) {
// If something's already loaded, we're done here.
if (GetInstance() != nullptr) {
return XR_SUCCESS;
}
#ifdef XR_KHR_LOADER_INIT_SUPPORT
if (!LoaderInitData::instance().initialized()) {
LoaderLogger::LogErrorMessage(
openxr_command, "RuntimeInterface::LoadRuntime cannot run because xrInitializeLoaderKHR was not successfully called.");
return XR_ERROR_INITIALIZATION_FAILED;
}
#endif // XR_KHR_LOADER_INIT_SUPPORT
std::vector<std::unique_ptr<RuntimeManifestFile>> runtime_manifest_files = {};
// Find the available runtimes which we may need to report information for.
XrResult last_error = RuntimeManifestFile::FindManifestFiles(runtime_manifest_files);
if (XR_FAILED(last_error)) {
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - unknown error");
} else {
last_error = XR_ERROR_RUNTIME_UNAVAILABLE;
for (std::unique_ptr<RuntimeManifestFile>& manifest_file : runtime_manifest_files) {
last_error = RuntimeInterface::TryLoadingSingleRuntime(openxr_command, manifest_file);
if (XR_SUCCEEDED(last_error)) {
break;
}
}
}
// Unsuccessful in loading any runtime, throw the runtime unavailable message.
if (XR_FAILED(last_error)) {
LoaderLogger::LogErrorMessage(openxr_command, "RuntimeInterface::LoadRuntimes - failed to load a runtime");
last_error = XR_ERROR_RUNTIME_UNAVAILABLE;
}
return last_error;
}
void RuntimeInterface::UnloadRuntime(const std::string& openxr_command) {
if (GetInstance()) {
LoaderLogger::LogInfoMessage(openxr_command, "RuntimeInterface::UnloadRuntime - Unloading RuntimeInterface");
GetInstance().reset();
}
}
XrResult RuntimeInterface::GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function) {
return GetInstance()->_get_instance_proc_addr(instance, name, function);
}
const XrGeneratedDispatchTable* RuntimeInterface::GetDispatchTable(XrInstance instance) {
XrGeneratedDispatchTable* table = nullptr;
std::lock_guard<std::mutex> mlock(GetInstance()->_dispatch_table_mutex);
auto it = GetInstance()->_dispatch_table_map.find(instance);
if (it != GetInstance()->_dispatch_table_map.end()) {
table = it->second.get();
}
return table;
}
const XrGeneratedDispatchTable* RuntimeInterface::GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger) {
XrInstance runtime_instance = XR_NULL_HANDLE;
{
std::lock_guard<std::mutex> mlock(GetInstance()->_messenger_to_instance_mutex);
auto it = GetInstance()->_messenger_to_instance_map.find(messenger);
if (it != GetInstance()->_messenger_to_instance_map.end()) {
runtime_instance = it->second;
}
}
return GetDispatchTable(runtime_instance);
}
RuntimeInterface::RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr)
: _runtime_library(runtime_library), _get_instance_proc_addr(get_instance_proc_addr) {}
RuntimeInterface::~RuntimeInterface() {
std::string info_message = "RuntimeInterface being destroyed.";
LoaderLogger::LogInfoMessage("", info_message);
{
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
_dispatch_table_map.clear();
}
LoaderPlatformLibraryClose(_runtime_library);
}
void RuntimeInterface::GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties) {
std::vector<XrExtensionProperties> runtime_extension_properties;
PFN_xrEnumerateInstanceExtensionProperties rt_xrEnumerateInstanceExtensionProperties;
_get_instance_proc_addr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties",
reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrEnumerateInstanceExtensionProperties));
uint32_t count = 0;
uint32_t count_output = 0;
// Get the count from the runtime
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, nullptr);
if (count_output > 0) {
runtime_extension_properties.resize(count_output);
count = count_output;
for (XrExtensionProperties& ext_prop : runtime_extension_properties) {
ext_prop.type = XR_TYPE_EXTENSION_PROPERTIES;
ext_prop.next = nullptr;
}
rt_xrEnumerateInstanceExtensionProperties(nullptr, count, &count_output, runtime_extension_properties.data());
}
size_t ext_count = runtime_extension_properties.size();
size_t props_count = extension_properties.size();
for (size_t ext = 0; ext < ext_count; ++ext) {
bool found = false;
for (size_t prop = 0; prop < props_count; ++prop) {
// If we find it, then make sure the spec version matches that of the runtime instead of the
// layer.
if (strcmp(extension_properties[prop].extensionName, runtime_extension_properties[ext].extensionName) == 0) {
// Make sure the spec version used is the runtime's
extension_properties[prop].extensionVersion = runtime_extension_properties[ext].extensionVersion;
found = true;
break;
}
}
if (!found) {
extension_properties.push_back(runtime_extension_properties[ext]);
}
}
}
XrResult RuntimeInterface::CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance) {
XrResult res = XR_SUCCESS;
bool create_succeeded = false;
PFN_xrCreateInstance rt_xrCreateInstance;
_get_instance_proc_addr(XR_NULL_HANDLE, "xrCreateInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrCreateInstance));
res = rt_xrCreateInstance(info, instance);
if (XR_SUCCEEDED(res)) {
create_succeeded = true;
std::unique_ptr<XrGeneratedDispatchTable> dispatch_table(new XrGeneratedDispatchTable());
GeneratedXrPopulateDispatchTable(dispatch_table.get(), *instance, _get_instance_proc_addr);
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
_dispatch_table_map[*instance] = std::move(dispatch_table);
}
// If the failure occurred during the populate, clean up the instance we had picked up from the runtime
if (XR_FAILED(res) && create_succeeded) {
PFN_xrDestroyInstance rt_xrDestroyInstance;
_get_instance_proc_addr(*instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
rt_xrDestroyInstance(*instance);
*instance = XR_NULL_HANDLE;
}
return res;
}
XrResult RuntimeInterface::DestroyInstance(XrInstance instance) {
if (XR_NULL_HANDLE != instance) {
// Destroy the dispatch table for this instance first
{
std::lock_guard<std::mutex> mlock(_dispatch_table_mutex);
auto map_iter = _dispatch_table_map.find(instance);
if (map_iter != _dispatch_table_map.end()) {
_dispatch_table_map.erase(map_iter);
}
}
// Now delete the instance
PFN_xrDestroyInstance rt_xrDestroyInstance;
_get_instance_proc_addr(instance, "xrDestroyInstance", reinterpret_cast<PFN_xrVoidFunction*>(&rt_xrDestroyInstance));
rt_xrDestroyInstance(instance);
}
return XR_SUCCESS;
}
bool RuntimeInterface::TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger) {
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
_messenger_to_instance_map[messenger] = instance;
return true;
}
void RuntimeInterface::ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger) {
if (XR_NULL_HANDLE != messenger) {
std::lock_guard<std::mutex> mlock(_messenger_to_instance_mutex);
_messenger_to_instance_map.erase(messenger);
}
}
void RuntimeInterface::SetSupportedExtensions(std::vector<std::string>& supported_extensions) {
_supported_extensions = supported_extensions;
}
bool RuntimeInterface::SupportsExtension(const std::string& extension_name) {
bool found_prop = false;
for (const std::string& supported_extension : _supported_extensions) {
if (supported_extension == extension_name) {
found_prop = true;
break;
}
}
return found_prop;
}

View File

@ -0,0 +1,84 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Initial Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "loader_platform.hpp"
#include <openxr/openxr.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <memory>
#ifdef XR_USE_PLATFORM_ANDROID
#define XR_KHR_LOADER_INIT_SUPPORT
#endif
namespace Json {
class Value;
}
#ifdef XR_KHR_LOADER_INIT_SUPPORT
//! Initialize loader, where required.
XrResult InitializeLoader(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);
XrResult GetPlatformRuntimeVirtualManifest(Json::Value& out_manifest);
#endif
class RuntimeManifestFile;
struct XrGeneratedDispatchTable;
class RuntimeInterface {
public:
virtual ~RuntimeInterface();
// Helper functions for loading and unloading the runtime (but only when necessary)
static XrResult LoadRuntime(const std::string& openxr_command);
static void UnloadRuntime(const std::string& openxr_command);
static RuntimeInterface& GetRuntime() { return *(GetInstance().get()); }
static XrResult GetInstanceProcAddr(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
// Get the direct dispatch table to this runtime, without API layers or loader terminators.
static const XrGeneratedDispatchTable* GetDispatchTable(XrInstance instance);
static const XrGeneratedDispatchTable* GetDebugUtilsMessengerDispatchTable(XrDebugUtilsMessengerEXT messenger);
void GetInstanceExtensionProperties(std::vector<XrExtensionProperties>& extension_properties);
bool SupportsExtension(const std::string& extension_name);
XrResult CreateInstance(const XrInstanceCreateInfo* info, XrInstance* instance);
XrResult DestroyInstance(XrInstance instance);
bool TrackDebugMessenger(XrInstance instance, XrDebugUtilsMessengerEXT messenger);
void ForgetDebugMessenger(XrDebugUtilsMessengerEXT messenger);
// No default construction
RuntimeInterface() = delete;
// Non-copyable
RuntimeInterface(const RuntimeInterface&) = delete;
RuntimeInterface& operator=(const RuntimeInterface&) = delete;
private:
RuntimeInterface(LoaderPlatformLibraryHandle runtime_library, PFN_xrGetInstanceProcAddr get_instance_proc_addr);
void SetSupportedExtensions(std::vector<std::string>& supported_extensions);
static XrResult TryLoadingSingleRuntime(const std::string& openxr_command, std::unique_ptr<RuntimeManifestFile>& manifest_file);
static std::unique_ptr<RuntimeInterface>& GetInstance() {
static std::unique_ptr<RuntimeInterface> instance;
return instance;
}
LoaderPlatformLibraryHandle _runtime_library;
PFN_xrGetInstanceProcAddr _get_instance_proc_addr;
std::unordered_map<XrInstance, std::unique_ptr<XrGeneratedDispatchTable>> _dispatch_table_map;
std::mutex _dispatch_table_mutex;
std::unordered_map<XrDebugUtilsMessengerEXT, XrInstance> _messenger_to_instance_map;
std::mutex _messenger_to_instance_mutex;
std::vector<std::string> _supported_extensions;
};

View File

@ -0,0 +1,700 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See loader_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "xr_generated_loader.hpp"
#include "api_layer_interface.hpp"
#include "exception_handling.hpp"
#include "hex_and_handles.h"
#include "loader_instance.hpp"
#include "loader_logger.hpp"
#include "loader_platform.hpp"
#include "runtime_interface.hpp"
#include "xr_generated_dispatch_table.h"
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#include <cstring>
#include <memory>
#include <new>
#include <string>
#include <unordered_map>
// Automatically generated instance trampolines and terminators
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
XrInstance instance,
XrInstanceProperties* instanceProperties) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInstanceProperties");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetInstanceProperties(instance, instanceProperties);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
XrInstance instance,
XrEventDataBuffer* eventData) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPollEvent");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->PollEvent(instance, eventData);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
XrInstance instance,
XrResult value,
char buffer[XR_MAX_RESULT_STRING_SIZE]) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrResultToString");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->ResultToString(instance, value, buffer);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
XrInstance instance,
XrStructureType value,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStructureTypeToString");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->StructureTypeToString(instance, value, buffer);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
XrInstance instance,
const XrSystemGetInfo* getInfo,
XrSystemId* systemId) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystem");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetSystem(instance, getInfo, systemId);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
XrInstance instance,
XrSystemId systemId,
XrSystemProperties* properties) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetSystemProperties");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetSystemProperties(instance, systemId, properties);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t environmentBlendModeCapacityInput,
uint32_t* environmentBlendModeCountOutput,
XrEnvironmentBlendMode* environmentBlendModes) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateEnvironmentBlendModes");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateEnvironmentBlendModes(instance, systemId, viewConfigurationType, environmentBlendModeCapacityInput, environmentBlendModeCountOutput, environmentBlendModes);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
XrInstance instance,
const XrSessionCreateInfo* createInfo,
XrSession* session) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSession");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateSession(instance, createInfo, session);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession(
XrSession session) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySession");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->DestroySession(session);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces(
XrSession session,
uint32_t spaceCapacityInput,
uint32_t* spaceCountOutput,
XrReferenceSpaceType* spaces) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateReferenceSpaces");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateReferenceSpaces(session, spaceCapacityInput, spaceCountOutput, spaces);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace(
XrSession session,
const XrReferenceSpaceCreateInfo* createInfo,
XrSpace* space) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateReferenceSpace");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateReferenceSpace(session, createInfo, space);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect(
XrSession session,
XrReferenceSpaceType referenceSpaceType,
XrExtent2Df* bounds) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetReferenceSpaceBoundsRect");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetReferenceSpaceBoundsRect(session, referenceSpaceType, bounds);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace(
XrSession session,
const XrActionSpaceCreateInfo* createInfo,
XrSpace* space) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSpace");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateActionSpace(session, createInfo, space);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
XrSpace space,
XrSpace baseSpace,
XrTime time,
XrSpaceLocation* location) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateSpace");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->LocateSpace(space, baseSpace, time, location);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace(
XrSpace space) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySpace");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->DestroySpace(space);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
XrInstance instance,
XrSystemId systemId,
uint32_t viewConfigurationTypeCapacityInput,
uint32_t* viewConfigurationTypeCountOutput,
XrViewConfigurationType* viewConfigurationTypes) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurations");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateViewConfigurations(instance, systemId, viewConfigurationTypeCapacityInput, viewConfigurationTypeCountOutput, viewConfigurationTypes);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
XrViewConfigurationProperties* configurationProperties) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetViewConfigurationProperties");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetViewConfigurationProperties(instance, systemId, viewConfigurationType, configurationProperties);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrViewConfigurationView* views) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateViewConfigurationViews");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateViewConfigurationViews(instance, systemId, viewConfigurationType, viewCapacityInput, viewCountOutput, views);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats(
XrSession session,
uint32_t formatCapacityInput,
uint32_t* formatCountOutput,
int64_t* formats) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainFormats");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateSwapchainFormats(session, formatCapacityInput, formatCountOutput, formats);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
XrSession session,
const XrSwapchainCreateInfo* createInfo,
XrSwapchain* swapchain) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateSwapchain");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateSwapchain(session, createInfo, swapchain);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain(
XrSwapchain swapchain) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroySwapchain");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->DestroySwapchain(swapchain);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages(
XrSwapchain swapchain,
uint32_t imageCapacityInput,
uint32_t* imageCountOutput,
XrSwapchainImageBaseHeader* images) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateSwapchainImages");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateSwapchainImages(swapchain, imageCapacityInput, imageCountOutput, images);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageAcquireInfo* acquireInfo,
uint32_t* index) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAcquireSwapchainImage");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->AcquireSwapchainImage(swapchain, acquireInfo, index);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageWaitInfo* waitInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitSwapchainImage");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->WaitSwapchainImage(swapchain, waitInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageReleaseInfo* releaseInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrReleaseSwapchainImage");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->ReleaseSwapchainImage(swapchain, releaseInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession(
XrSession session,
const XrSessionBeginInfo* beginInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginSession");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->BeginSession(session, beginInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession(
XrSession session) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndSession");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EndSession(session);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession(
XrSession session) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrRequestExitSession");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->RequestExitSession(session);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame(
XrSession session,
const XrFrameWaitInfo* frameWaitInfo,
XrFrameState* frameState) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrWaitFrame");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->WaitFrame(session, frameWaitInfo, frameState);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame(
XrSession session,
const XrFrameBeginInfo* frameBeginInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrBeginFrame");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->BeginFrame(session, frameBeginInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame(
XrSession session,
const XrFrameEndInfo* frameEndInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEndFrame");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EndFrame(session, frameEndInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
XrSession session,
const XrViewLocateInfo* viewLocateInfo,
XrViewState* viewState,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrView* views) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrLocateViews");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->LocateViews(session, viewLocateInfo, viewState, viewCapacityInput, viewCountOutput, views);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
XrInstance instance,
const char* pathString,
XrPath* path) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStringToPath");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->StringToPath(instance, pathString, path);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
XrInstance instance,
XrPath path,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrPathToString");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->PathToString(instance, path, bufferCapacityInput, bufferCountOutput, buffer);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
XrInstance instance,
const XrActionSetCreateInfo* createInfo,
XrActionSet* actionSet) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateActionSet");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateActionSet(instance, createInfo, actionSet);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet(
XrActionSet actionSet) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyActionSet");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->DestroyActionSet(actionSet);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction(
XrActionSet actionSet,
const XrActionCreateInfo* createInfo,
XrAction* action) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrCreateAction");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->CreateAction(actionSet, createInfo, action);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction(
XrAction action) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyAction");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->DestroyAction(action);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
XrInstance instance,
const XrInteractionProfileSuggestedBinding* suggestedBindings) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSuggestInteractionProfileBindings");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->SuggestInteractionProfileBindings(instance, suggestedBindings);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets(
XrSession session,
const XrSessionActionSetsAttachInfo* attachInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrAttachSessionActionSets");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->AttachSessionActionSets(session, attachInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
XrSession session,
XrPath topLevelUserPath,
XrInteractionProfileState* interactionProfile) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetCurrentInteractionProfile");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetCurrentInteractionProfile(session, topLevelUserPath, interactionProfile);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateBoolean* state) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateBoolean");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetActionStateBoolean(session, getInfo, state);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateFloat* state) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateFloat");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetActionStateFloat(session, getInfo, state);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateVector2f* state) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStateVector2f");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetActionStateVector2f(session, getInfo, state);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStatePose* state) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetActionStatePose");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetActionStatePose(session, getInfo, state);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions(
XrSession session,
const XrActionsSyncInfo* syncInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrSyncActions");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->SyncActions(session, syncInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction(
XrSession session,
const XrBoundSourcesForActionEnumerateInfo* enumerateInfo,
uint32_t sourceCapacityInput,
uint32_t* sourceCountOutput,
XrPath* sources) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrEnumerateBoundSourcesForAction");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->EnumerateBoundSourcesForAction(session, enumerateInfo, sourceCapacityInput, sourceCountOutput, sources);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
XrSession session,
const XrInputSourceLocalizedNameGetInfo* getInfo,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrGetInputSourceLocalizedName");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->GetInputSourceLocalizedName(session, getInfo, bufferCapacityInput, bufferCountOutput, buffer);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
XrSession session,
const XrHapticActionInfo* hapticActionInfo,
const XrHapticBaseHeader* hapticFeedback) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrApplyHapticFeedback");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->ApplyHapticFeedback(session, hapticActionInfo, hapticFeedback);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
XrSession session,
const XrHapticActionInfo* hapticActionInfo) XRLOADER_ABI_TRY {
LoaderInstance* loader_instance;
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrStopHapticFeedback");
if (XR_SUCCEEDED(result)) {
result = loader_instance->DispatchTable()->StopHapticFeedback(session, hapticActionInfo);
}
return result;
}
XRLOADER_ABI_CATCH_FALLBACK

View File

@ -0,0 +1,252 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See loader_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include <unordered_map>
#include <thread>
#include <mutex>
#include "xr_dependencies.h"
#include "openxr/openxr.h"
#include "openxr/openxr_platform.h"
#include "loader_interfaces.h"
#include "loader_instance.hpp"
#include "loader_platform.hpp"
#ifdef __cplusplus
extern "C" {
#endif
// Loader manually generated function prototypes
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
XrInstance instance,
XrInstanceProperties* instanceProperties);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
XrInstance instance,
XrEventDataBuffer* eventData);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
XrInstance instance,
XrResult value,
char buffer[XR_MAX_RESULT_STRING_SIZE]);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
XrInstance instance,
XrStructureType value,
char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
XrInstance instance,
const XrSystemGetInfo* getInfo,
XrSystemId* systemId);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
XrInstance instance,
XrSystemId systemId,
XrSystemProperties* properties);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t environmentBlendModeCapacityInput,
uint32_t* environmentBlendModeCountOutput,
XrEnvironmentBlendMode* environmentBlendModes);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
XrInstance instance,
const XrSessionCreateInfo* createInfo,
XrSession* session);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession(
XrSession session);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces(
XrSession session,
uint32_t spaceCapacityInput,
uint32_t* spaceCountOutput,
XrReferenceSpaceType* spaces);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace(
XrSession session,
const XrReferenceSpaceCreateInfo* createInfo,
XrSpace* space);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect(
XrSession session,
XrReferenceSpaceType referenceSpaceType,
XrExtent2Df* bounds);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace(
XrSession session,
const XrActionSpaceCreateInfo* createInfo,
XrSpace* space);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
XrSpace space,
XrSpace baseSpace,
XrTime time,
XrSpaceLocation* location);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace(
XrSpace space);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
XrInstance instance,
XrSystemId systemId,
uint32_t viewConfigurationTypeCapacityInput,
uint32_t* viewConfigurationTypeCountOutput,
XrViewConfigurationType* viewConfigurationTypes);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
XrViewConfigurationProperties* configurationProperties);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
XrInstance instance,
XrSystemId systemId,
XrViewConfigurationType viewConfigurationType,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrViewConfigurationView* views);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats(
XrSession session,
uint32_t formatCapacityInput,
uint32_t* formatCountOutput,
int64_t* formats);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
XrSession session,
const XrSwapchainCreateInfo* createInfo,
XrSwapchain* swapchain);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain(
XrSwapchain swapchain);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages(
XrSwapchain swapchain,
uint32_t imageCapacityInput,
uint32_t* imageCountOutput,
XrSwapchainImageBaseHeader* images);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageAcquireInfo* acquireInfo,
uint32_t* index);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageWaitInfo* waitInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage(
XrSwapchain swapchain,
const XrSwapchainImageReleaseInfo* releaseInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession(
XrSession session,
const XrSessionBeginInfo* beginInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndSession(
XrSession session);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession(
XrSession session);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame(
XrSession session,
const XrFrameWaitInfo* frameWaitInfo,
XrFrameState* frameState);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame(
XrSession session,
const XrFrameBeginInfo* frameBeginInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame(
XrSession session,
const XrFrameEndInfo* frameEndInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
XrSession session,
const XrViewLocateInfo* viewLocateInfo,
XrViewState* viewState,
uint32_t viewCapacityInput,
uint32_t* viewCountOutput,
XrView* views);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
XrInstance instance,
const char* pathString,
XrPath* path);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
XrInstance instance,
XrPath path,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
XrInstance instance,
const XrActionSetCreateInfo* createInfo,
XrActionSet* actionSet);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet(
XrActionSet actionSet);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction(
XrActionSet actionSet,
const XrActionCreateInfo* createInfo,
XrAction* action);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction(
XrAction action);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
XrInstance instance,
const XrInteractionProfileSuggestedBinding* suggestedBindings);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets(
XrSession session,
const XrSessionActionSetsAttachInfo* attachInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
XrSession session,
XrPath topLevelUserPath,
XrInteractionProfileState* interactionProfile);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateBoolean* state);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateFloat* state);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStateVector2f* state);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
XrSession session,
const XrActionStateGetInfo* getInfo,
XrActionStatePose* state);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions(
XrSession session,
const XrActionsSyncInfo* syncInfo);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction(
XrSession session,
const XrBoundSourcesForActionEnumerateInfo* enumerateInfo,
uint32_t sourceCapacityInput,
uint32_t* sourceCountOutput,
XrPath* sources);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
XrSession session,
const XrInputSourceLocalizedNameGetInfo* getInfo,
uint32_t bufferCapacityInput,
uint32_t* bufferCountOutput,
char* buffer);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
XrSession session,
const XrHapticActionInfo* hapticActionInfo,
const XrHapticBaseHeader* hapticFeedback);
extern "C" LOADER_EXPORT XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
XrSession session,
const XrHapticActionInfo* hapticActionInfo);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -0,0 +1,347 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
//
#include "xr_generated_dispatch_table.h"
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
// Helper function to populate an instance dispatch table
void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
XrInstance instance,
PFN_xrGetInstanceProcAddr get_inst_proc_addr) {
// ---- Core 1.0 commands
table->GetInstanceProcAddr = get_inst_proc_addr;
(get_inst_proc_addr(instance, "xrCreateInstance", (PFN_xrVoidFunction*)&table->CreateInstance));
(get_inst_proc_addr(instance, "xrDestroyInstance", (PFN_xrVoidFunction*)&table->DestroyInstance));
(get_inst_proc_addr(instance, "xrGetInstanceProperties", (PFN_xrVoidFunction*)&table->GetInstanceProperties));
(get_inst_proc_addr(instance, "xrPollEvent", (PFN_xrVoidFunction*)&table->PollEvent));
(get_inst_proc_addr(instance, "xrResultToString", (PFN_xrVoidFunction*)&table->ResultToString));
(get_inst_proc_addr(instance, "xrStructureTypeToString", (PFN_xrVoidFunction*)&table->StructureTypeToString));
(get_inst_proc_addr(instance, "xrGetSystem", (PFN_xrVoidFunction*)&table->GetSystem));
(get_inst_proc_addr(instance, "xrGetSystemProperties", (PFN_xrVoidFunction*)&table->GetSystemProperties));
(get_inst_proc_addr(instance, "xrEnumerateEnvironmentBlendModes", (PFN_xrVoidFunction*)&table->EnumerateEnvironmentBlendModes));
(get_inst_proc_addr(instance, "xrCreateSession", (PFN_xrVoidFunction*)&table->CreateSession));
(get_inst_proc_addr(instance, "xrDestroySession", (PFN_xrVoidFunction*)&table->DestroySession));
(get_inst_proc_addr(instance, "xrEnumerateReferenceSpaces", (PFN_xrVoidFunction*)&table->EnumerateReferenceSpaces));
(get_inst_proc_addr(instance, "xrCreateReferenceSpace", (PFN_xrVoidFunction*)&table->CreateReferenceSpace));
(get_inst_proc_addr(instance, "xrGetReferenceSpaceBoundsRect", (PFN_xrVoidFunction*)&table->GetReferenceSpaceBoundsRect));
(get_inst_proc_addr(instance, "xrCreateActionSpace", (PFN_xrVoidFunction*)&table->CreateActionSpace));
(get_inst_proc_addr(instance, "xrLocateSpace", (PFN_xrVoidFunction*)&table->LocateSpace));
(get_inst_proc_addr(instance, "xrDestroySpace", (PFN_xrVoidFunction*)&table->DestroySpace));
(get_inst_proc_addr(instance, "xrEnumerateViewConfigurations", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurations));
(get_inst_proc_addr(instance, "xrGetViewConfigurationProperties", (PFN_xrVoidFunction*)&table->GetViewConfigurationProperties));
(get_inst_proc_addr(instance, "xrEnumerateViewConfigurationViews", (PFN_xrVoidFunction*)&table->EnumerateViewConfigurationViews));
(get_inst_proc_addr(instance, "xrEnumerateSwapchainFormats", (PFN_xrVoidFunction*)&table->EnumerateSwapchainFormats));
(get_inst_proc_addr(instance, "xrCreateSwapchain", (PFN_xrVoidFunction*)&table->CreateSwapchain));
(get_inst_proc_addr(instance, "xrDestroySwapchain", (PFN_xrVoidFunction*)&table->DestroySwapchain));
(get_inst_proc_addr(instance, "xrEnumerateSwapchainImages", (PFN_xrVoidFunction*)&table->EnumerateSwapchainImages));
(get_inst_proc_addr(instance, "xrAcquireSwapchainImage", (PFN_xrVoidFunction*)&table->AcquireSwapchainImage));
(get_inst_proc_addr(instance, "xrWaitSwapchainImage", (PFN_xrVoidFunction*)&table->WaitSwapchainImage));
(get_inst_proc_addr(instance, "xrReleaseSwapchainImage", (PFN_xrVoidFunction*)&table->ReleaseSwapchainImage));
(get_inst_proc_addr(instance, "xrBeginSession", (PFN_xrVoidFunction*)&table->BeginSession));
(get_inst_proc_addr(instance, "xrEndSession", (PFN_xrVoidFunction*)&table->EndSession));
(get_inst_proc_addr(instance, "xrRequestExitSession", (PFN_xrVoidFunction*)&table->RequestExitSession));
(get_inst_proc_addr(instance, "xrWaitFrame", (PFN_xrVoidFunction*)&table->WaitFrame));
(get_inst_proc_addr(instance, "xrBeginFrame", (PFN_xrVoidFunction*)&table->BeginFrame));
(get_inst_proc_addr(instance, "xrEndFrame", (PFN_xrVoidFunction*)&table->EndFrame));
(get_inst_proc_addr(instance, "xrLocateViews", (PFN_xrVoidFunction*)&table->LocateViews));
(get_inst_proc_addr(instance, "xrStringToPath", (PFN_xrVoidFunction*)&table->StringToPath));
(get_inst_proc_addr(instance, "xrPathToString", (PFN_xrVoidFunction*)&table->PathToString));
(get_inst_proc_addr(instance, "xrCreateActionSet", (PFN_xrVoidFunction*)&table->CreateActionSet));
(get_inst_proc_addr(instance, "xrDestroyActionSet", (PFN_xrVoidFunction*)&table->DestroyActionSet));
(get_inst_proc_addr(instance, "xrCreateAction", (PFN_xrVoidFunction*)&table->CreateAction));
(get_inst_proc_addr(instance, "xrDestroyAction", (PFN_xrVoidFunction*)&table->DestroyAction));
(get_inst_proc_addr(instance, "xrSuggestInteractionProfileBindings", (PFN_xrVoidFunction*)&table->SuggestInteractionProfileBindings));
(get_inst_proc_addr(instance, "xrAttachSessionActionSets", (PFN_xrVoidFunction*)&table->AttachSessionActionSets));
(get_inst_proc_addr(instance, "xrGetCurrentInteractionProfile", (PFN_xrVoidFunction*)&table->GetCurrentInteractionProfile));
(get_inst_proc_addr(instance, "xrGetActionStateBoolean", (PFN_xrVoidFunction*)&table->GetActionStateBoolean));
(get_inst_proc_addr(instance, "xrGetActionStateFloat", (PFN_xrVoidFunction*)&table->GetActionStateFloat));
(get_inst_proc_addr(instance, "xrGetActionStateVector2f", (PFN_xrVoidFunction*)&table->GetActionStateVector2f));
(get_inst_proc_addr(instance, "xrGetActionStatePose", (PFN_xrVoidFunction*)&table->GetActionStatePose));
(get_inst_proc_addr(instance, "xrSyncActions", (PFN_xrVoidFunction*)&table->SyncActions));
(get_inst_proc_addr(instance, "xrEnumerateBoundSourcesForAction", (PFN_xrVoidFunction*)&table->EnumerateBoundSourcesForAction));
(get_inst_proc_addr(instance, "xrGetInputSourceLocalizedName", (PFN_xrVoidFunction*)&table->GetInputSourceLocalizedName));
(get_inst_proc_addr(instance, "xrApplyHapticFeedback", (PFN_xrVoidFunction*)&table->ApplyHapticFeedback));
(get_inst_proc_addr(instance, "xrStopHapticFeedback", (PFN_xrVoidFunction*)&table->StopHapticFeedback));
// ---- XR_KHR_android_thread_settings extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
(get_inst_proc_addr(instance, "xrSetAndroidApplicationThreadKHR", (PFN_xrVoidFunction*)&table->SetAndroidApplicationThreadKHR));
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_android_surface_swapchain extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
(get_inst_proc_addr(instance, "xrCreateSwapchainAndroidSurfaceKHR", (PFN_xrVoidFunction*)&table->CreateSwapchainAndroidSurfaceKHR));
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_opengl_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL)
(get_inst_proc_addr(instance, "xrGetOpenGLGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_OPENGL)
// ---- XR_KHR_opengl_es_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
(get_inst_proc_addr(instance, "xrGetOpenGLESGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetOpenGLESGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES)
// ---- XR_KHR_vulkan_enable extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanInstanceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanInstanceExtensionsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanDeviceExtensionsKHR", (PFN_xrVoidFunction*)&table->GetVulkanDeviceExtensionsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsDeviceKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsDeviceKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_KHR_D3D11_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D11)
(get_inst_proc_addr(instance, "xrGetD3D11GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D11GraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_D3D11)
// ---- XR_KHR_D3D12_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D12)
(get_inst_proc_addr(instance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction*)&table->GetD3D12GraphicsRequirementsKHR));
#endif // defined(XR_USE_GRAPHICS_API_D3D12)
// ---- XR_KHR_visibility_mask extension commands
(get_inst_proc_addr(instance, "xrGetVisibilityMaskKHR", (PFN_xrVoidFunction*)&table->GetVisibilityMaskKHR));
// ---- XR_KHR_win32_convert_performance_counter_time extension commands
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrConvertWin32PerformanceCounterToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertWin32PerformanceCounterToTimeKHR));
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrConvertTimeToWin32PerformanceCounterKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToWin32PerformanceCounterKHR));
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_KHR_convert_timespec_time extension commands
#if defined(XR_USE_TIMESPEC)
(get_inst_proc_addr(instance, "xrConvertTimespecTimeToTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimespecTimeToTimeKHR));
#endif // defined(XR_USE_TIMESPEC)
#if defined(XR_USE_TIMESPEC)
(get_inst_proc_addr(instance, "xrConvertTimeToTimespecTimeKHR", (PFN_xrVoidFunction*)&table->ConvertTimeToTimespecTimeKHR));
#endif // defined(XR_USE_TIMESPEC)
// ---- XR_KHR_vulkan_enable2 extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction*)&table->CreateVulkanInstanceKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction*)&table->CreateVulkanDeviceKHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsDevice2KHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
(get_inst_proc_addr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction*)&table->GetVulkanGraphicsRequirements2KHR));
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_EXT_performance_settings extension commands
(get_inst_proc_addr(instance, "xrPerfSettingsSetPerformanceLevelEXT", (PFN_xrVoidFunction*)&table->PerfSettingsSetPerformanceLevelEXT));
// ---- XR_EXT_thermal_query extension commands
(get_inst_proc_addr(instance, "xrThermalGetTemperatureTrendEXT", (PFN_xrVoidFunction*)&table->ThermalGetTemperatureTrendEXT));
// ---- XR_EXT_debug_utils extension commands
(get_inst_proc_addr(instance, "xrSetDebugUtilsObjectNameEXT", (PFN_xrVoidFunction*)&table->SetDebugUtilsObjectNameEXT));
(get_inst_proc_addr(instance, "xrCreateDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->CreateDebugUtilsMessengerEXT));
(get_inst_proc_addr(instance, "xrDestroyDebugUtilsMessengerEXT", (PFN_xrVoidFunction*)&table->DestroyDebugUtilsMessengerEXT));
(get_inst_proc_addr(instance, "xrSubmitDebugUtilsMessageEXT", (PFN_xrVoidFunction*)&table->SubmitDebugUtilsMessageEXT));
(get_inst_proc_addr(instance, "xrSessionBeginDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionBeginDebugUtilsLabelRegionEXT));
(get_inst_proc_addr(instance, "xrSessionEndDebugUtilsLabelRegionEXT", (PFN_xrVoidFunction*)&table->SessionEndDebugUtilsLabelRegionEXT));
(get_inst_proc_addr(instance, "xrSessionInsertDebugUtilsLabelEXT", (PFN_xrVoidFunction*)&table->SessionInsertDebugUtilsLabelEXT));
// ---- XR_MSFT_spatial_anchor extension commands
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorMSFT));
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorSpaceMSFT));
(get_inst_proc_addr(instance, "xrDestroySpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->DestroySpatialAnchorMSFT));
// ---- XR_EXT_conformance_automation extension commands
(get_inst_proc_addr(instance, "xrSetInputDeviceActiveEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceActiveEXT));
(get_inst_proc_addr(instance, "xrSetInputDeviceStateBoolEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateBoolEXT));
(get_inst_proc_addr(instance, "xrSetInputDeviceStateFloatEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateFloatEXT));
(get_inst_proc_addr(instance, "xrSetInputDeviceStateVector2fEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceStateVector2fEXT));
(get_inst_proc_addr(instance, "xrSetInputDeviceLocationEXT", (PFN_xrVoidFunction*)&table->SetInputDeviceLocationEXT));
// ---- XR_MSFT_spatial_graph_bridge extension commands
(get_inst_proc_addr(instance, "xrCreateSpatialGraphNodeSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialGraphNodeSpaceMSFT));
// ---- XR_EXT_hand_tracking extension commands
(get_inst_proc_addr(instance, "xrCreateHandTrackerEXT", (PFN_xrVoidFunction*)&table->CreateHandTrackerEXT));
(get_inst_proc_addr(instance, "xrDestroyHandTrackerEXT", (PFN_xrVoidFunction*)&table->DestroyHandTrackerEXT));
(get_inst_proc_addr(instance, "xrLocateHandJointsEXT", (PFN_xrVoidFunction*)&table->LocateHandJointsEXT));
// ---- XR_MSFT_hand_tracking_mesh extension commands
(get_inst_proc_addr(instance, "xrCreateHandMeshSpaceMSFT", (PFN_xrVoidFunction*)&table->CreateHandMeshSpaceMSFT));
(get_inst_proc_addr(instance, "xrUpdateHandMeshMSFT", (PFN_xrVoidFunction*)&table->UpdateHandMeshMSFT));
// ---- XR_MSFT_controller_model extension commands
(get_inst_proc_addr(instance, "xrGetControllerModelKeyMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelKeyMSFT));
(get_inst_proc_addr(instance, "xrLoadControllerModelMSFT", (PFN_xrVoidFunction*)&table->LoadControllerModelMSFT));
(get_inst_proc_addr(instance, "xrGetControllerModelPropertiesMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelPropertiesMSFT));
(get_inst_proc_addr(instance, "xrGetControllerModelStateMSFT", (PFN_xrVoidFunction*)&table->GetControllerModelStateMSFT));
// ---- XR_MSFT_perception_anchor_interop extension commands
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorFromPerceptionAnchorMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorFromPerceptionAnchorMSFT));
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrTryGetPerceptionAnchorFromSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->TryGetPerceptionAnchorFromSpatialAnchorMSFT));
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_MSFT_composition_layer_reprojection extension commands
(get_inst_proc_addr(instance, "xrEnumerateReprojectionModesMSFT", (PFN_xrVoidFunction*)&table->EnumerateReprojectionModesMSFT));
// ---- XR_FB_swapchain_update_state extension commands
(get_inst_proc_addr(instance, "xrUpdateSwapchainFB", (PFN_xrVoidFunction*)&table->UpdateSwapchainFB));
(get_inst_proc_addr(instance, "xrGetSwapchainStateFB", (PFN_xrVoidFunction*)&table->GetSwapchainStateFB));
// ---- XR_MSFT_scene_understanding extension commands
(get_inst_proc_addr(instance, "xrEnumerateSceneComputeFeaturesMSFT", (PFN_xrVoidFunction*)&table->EnumerateSceneComputeFeaturesMSFT));
(get_inst_proc_addr(instance, "xrCreateSceneObserverMSFT", (PFN_xrVoidFunction*)&table->CreateSceneObserverMSFT));
(get_inst_proc_addr(instance, "xrDestroySceneObserverMSFT", (PFN_xrVoidFunction*)&table->DestroySceneObserverMSFT));
(get_inst_proc_addr(instance, "xrCreateSceneMSFT", (PFN_xrVoidFunction*)&table->CreateSceneMSFT));
(get_inst_proc_addr(instance, "xrDestroySceneMSFT", (PFN_xrVoidFunction*)&table->DestroySceneMSFT));
(get_inst_proc_addr(instance, "xrComputeNewSceneMSFT", (PFN_xrVoidFunction*)&table->ComputeNewSceneMSFT));
(get_inst_proc_addr(instance, "xrGetSceneComputeStateMSFT", (PFN_xrVoidFunction*)&table->GetSceneComputeStateMSFT));
(get_inst_proc_addr(instance, "xrGetSceneComponentsMSFT", (PFN_xrVoidFunction*)&table->GetSceneComponentsMSFT));
(get_inst_proc_addr(instance, "xrLocateSceneComponentsMSFT", (PFN_xrVoidFunction*)&table->LocateSceneComponentsMSFT));
(get_inst_proc_addr(instance, "xrGetSceneMeshBuffersMSFT", (PFN_xrVoidFunction*)&table->GetSceneMeshBuffersMSFT));
// ---- XR_MSFT_scene_understanding_serialization extension commands
(get_inst_proc_addr(instance, "xrDeserializeSceneMSFT", (PFN_xrVoidFunction*)&table->DeserializeSceneMSFT));
(get_inst_proc_addr(instance, "xrGetSerializedSceneFragmentDataMSFT", (PFN_xrVoidFunction*)&table->GetSerializedSceneFragmentDataMSFT));
// ---- XR_FB_display_refresh_rate extension commands
(get_inst_proc_addr(instance, "xrEnumerateDisplayRefreshRatesFB", (PFN_xrVoidFunction*)&table->EnumerateDisplayRefreshRatesFB));
(get_inst_proc_addr(instance, "xrGetDisplayRefreshRateFB", (PFN_xrVoidFunction*)&table->GetDisplayRefreshRateFB));
(get_inst_proc_addr(instance, "xrRequestDisplayRefreshRateFB", (PFN_xrVoidFunction*)&table->RequestDisplayRefreshRateFB));
// ---- XR_HTCX_vive_tracker_interaction extension commands
(get_inst_proc_addr(instance, "xrEnumerateViveTrackerPathsHTCX", (PFN_xrVoidFunction*)&table->EnumerateViveTrackerPathsHTCX));
// ---- XR_HTC_facial_tracking extension commands
(get_inst_proc_addr(instance, "xrCreateFacialTrackerHTC", (PFN_xrVoidFunction*)&table->CreateFacialTrackerHTC));
(get_inst_proc_addr(instance, "xrDestroyFacialTrackerHTC", (PFN_xrVoidFunction*)&table->DestroyFacialTrackerHTC));
(get_inst_proc_addr(instance, "xrGetFacialExpressionsHTC", (PFN_xrVoidFunction*)&table->GetFacialExpressionsHTC));
// ---- XR_FB_color_space extension commands
(get_inst_proc_addr(instance, "xrEnumerateColorSpacesFB", (PFN_xrVoidFunction*)&table->EnumerateColorSpacesFB));
(get_inst_proc_addr(instance, "xrSetColorSpaceFB", (PFN_xrVoidFunction*)&table->SetColorSpaceFB));
// ---- XR_FB_hand_tracking_mesh extension commands
(get_inst_proc_addr(instance, "xrGetHandMeshFB", (PFN_xrVoidFunction*)&table->GetHandMeshFB));
// ---- XR_FB_foveation extension commands
(get_inst_proc_addr(instance, "xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)&table->CreateFoveationProfileFB));
(get_inst_proc_addr(instance, "xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)&table->DestroyFoveationProfileFB));
// ---- XR_FB_keyboard_tracking extension commands
(get_inst_proc_addr(instance, "xrQuerySystemTrackedKeyboardFB", (PFN_xrVoidFunction*)&table->QuerySystemTrackedKeyboardFB));
(get_inst_proc_addr(instance, "xrCreateKeyboardSpaceFB", (PFN_xrVoidFunction*)&table->CreateKeyboardSpaceFB));
// ---- XR_FB_triangle_mesh extension commands
(get_inst_proc_addr(instance, "xrCreateTriangleMeshFB", (PFN_xrVoidFunction*)&table->CreateTriangleMeshFB));
(get_inst_proc_addr(instance, "xrDestroyTriangleMeshFB", (PFN_xrVoidFunction*)&table->DestroyTriangleMeshFB));
(get_inst_proc_addr(instance, "xrTriangleMeshGetVertexBufferFB", (PFN_xrVoidFunction*)&table->TriangleMeshGetVertexBufferFB));
(get_inst_proc_addr(instance, "xrTriangleMeshGetIndexBufferFB", (PFN_xrVoidFunction*)&table->TriangleMeshGetIndexBufferFB));
(get_inst_proc_addr(instance, "xrTriangleMeshBeginUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshBeginUpdateFB));
(get_inst_proc_addr(instance, "xrTriangleMeshEndUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshEndUpdateFB));
(get_inst_proc_addr(instance, "xrTriangleMeshBeginVertexBufferUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshBeginVertexBufferUpdateFB));
(get_inst_proc_addr(instance, "xrTriangleMeshEndVertexBufferUpdateFB", (PFN_xrVoidFunction*)&table->TriangleMeshEndVertexBufferUpdateFB));
// ---- XR_FB_passthrough extension commands
(get_inst_proc_addr(instance, "xrCreatePassthroughFB", (PFN_xrVoidFunction*)&table->CreatePassthroughFB));
(get_inst_proc_addr(instance, "xrDestroyPassthroughFB", (PFN_xrVoidFunction*)&table->DestroyPassthroughFB));
(get_inst_proc_addr(instance, "xrPassthroughStartFB", (PFN_xrVoidFunction*)&table->PassthroughStartFB));
(get_inst_proc_addr(instance, "xrPassthroughPauseFB", (PFN_xrVoidFunction*)&table->PassthroughPauseFB));
(get_inst_proc_addr(instance, "xrCreatePassthroughLayerFB", (PFN_xrVoidFunction*)&table->CreatePassthroughLayerFB));
(get_inst_proc_addr(instance, "xrDestroyPassthroughLayerFB", (PFN_xrVoidFunction*)&table->DestroyPassthroughLayerFB));
(get_inst_proc_addr(instance, "xrPassthroughLayerPauseFB", (PFN_xrVoidFunction*)&table->PassthroughLayerPauseFB));
(get_inst_proc_addr(instance, "xrPassthroughLayerResumeFB", (PFN_xrVoidFunction*)&table->PassthroughLayerResumeFB));
(get_inst_proc_addr(instance, "xrPassthroughLayerSetStyleFB", (PFN_xrVoidFunction*)&table->PassthroughLayerSetStyleFB));
(get_inst_proc_addr(instance, "xrCreateGeometryInstanceFB", (PFN_xrVoidFunction*)&table->CreateGeometryInstanceFB));
(get_inst_proc_addr(instance, "xrDestroyGeometryInstanceFB", (PFN_xrVoidFunction*)&table->DestroyGeometryInstanceFB));
(get_inst_proc_addr(instance, "xrGeometryInstanceSetTransformFB", (PFN_xrVoidFunction*)&table->GeometryInstanceSetTransformFB));
// ---- XR_FB_render_model extension commands
(get_inst_proc_addr(instance, "xrEnumerateRenderModelPathsFB", (PFN_xrVoidFunction*)&table->EnumerateRenderModelPathsFB));
(get_inst_proc_addr(instance, "xrGetRenderModelPropertiesFB", (PFN_xrVoidFunction*)&table->GetRenderModelPropertiesFB));
(get_inst_proc_addr(instance, "xrLoadRenderModelFB", (PFN_xrVoidFunction*)&table->LoadRenderModelFB));
// ---- XR_VARJO_environment_depth_estimation extension commands
(get_inst_proc_addr(instance, "xrSetEnvironmentDepthEstimationVARJO", (PFN_xrVoidFunction*)&table->SetEnvironmentDepthEstimationVARJO));
// ---- XR_VARJO_marker_tracking extension commands
(get_inst_proc_addr(instance, "xrSetMarkerTrackingVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingVARJO));
(get_inst_proc_addr(instance, "xrSetMarkerTrackingTimeoutVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingTimeoutVARJO));
(get_inst_proc_addr(instance, "xrSetMarkerTrackingPredictionVARJO", (PFN_xrVoidFunction*)&table->SetMarkerTrackingPredictionVARJO));
(get_inst_proc_addr(instance, "xrGetMarkerSizeVARJO", (PFN_xrVoidFunction*)&table->GetMarkerSizeVARJO));
(get_inst_proc_addr(instance, "xrCreateMarkerSpaceVARJO", (PFN_xrVoidFunction*)&table->CreateMarkerSpaceVARJO));
// ---- XR_MSFT_spatial_anchor_persistence extension commands
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorStoreConnectionMSFT));
(get_inst_proc_addr(instance, "xrDestroySpatialAnchorStoreConnectionMSFT", (PFN_xrVoidFunction*)&table->DestroySpatialAnchorStoreConnectionMSFT));
(get_inst_proc_addr(instance, "xrPersistSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->PersistSpatialAnchorMSFT));
(get_inst_proc_addr(instance, "xrEnumeratePersistedSpatialAnchorNamesMSFT", (PFN_xrVoidFunction*)&table->EnumeratePersistedSpatialAnchorNamesMSFT));
(get_inst_proc_addr(instance, "xrCreateSpatialAnchorFromPersistedNameMSFT", (PFN_xrVoidFunction*)&table->CreateSpatialAnchorFromPersistedNameMSFT));
(get_inst_proc_addr(instance, "xrUnpersistSpatialAnchorMSFT", (PFN_xrVoidFunction*)&table->UnpersistSpatialAnchorMSFT));
(get_inst_proc_addr(instance, "xrClearSpatialAnchorStoreMSFT", (PFN_xrVoidFunction*)&table->ClearSpatialAnchorStoreMSFT));
// ---- XR_OCULUS_audio_device_guid extension commands
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrGetAudioOutputDeviceGuidOculus", (PFN_xrVoidFunction*)&table->GetAudioOutputDeviceGuidOculus));
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
(get_inst_proc_addr(instance, "xrGetAudioInputDeviceGuidOculus", (PFN_xrVoidFunction*)&table->GetAudioInputDeviceGuidOculus));
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_ALMALENCE_digital_lens_control extension commands
(get_inst_proc_addr(instance, "xrSetDigitalLensControlALMALENCE", (PFN_xrVoidFunction*)&table->SetDigitalLensControlALMALENCE));
// ---- XR_FB_passthrough_keyboard_hands extension commands
(get_inst_proc_addr(instance, "xrPassthroughLayerSetKeyboardHandsIntensityFB", (PFN_xrVoidFunction*)&table->PassthroughLayerSetKeyboardHandsIntensityFB));
}
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -0,0 +1,355 @@
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// *********** THIS FILE IS GENERATED - DO NOT EDIT ***********
// See utility_source_generator.py for modifications
// ************************************************************
// Copyright (c) 2017-2022, The Khronos Group Inc.
// Copyright (c) 2017-2019 Valve Corporation
// Copyright (c) 2017-2019 LunarG, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Mark Young <marky@lunarg.com>
//
#pragma once
#include "xr_dependencies.h"
#include <openxr/openxr.h>
#include <openxr/openxr_platform.h>
#ifdef __cplusplus
extern "C" {
#endif
// Generated dispatch table
struct XrGeneratedDispatchTable {
// ---- Core 1.0 commands
PFN_xrGetInstanceProcAddr GetInstanceProcAddr;
PFN_xrEnumerateApiLayerProperties EnumerateApiLayerProperties;
PFN_xrEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_xrCreateInstance CreateInstance;
PFN_xrDestroyInstance DestroyInstance;
PFN_xrGetInstanceProperties GetInstanceProperties;
PFN_xrPollEvent PollEvent;
PFN_xrResultToString ResultToString;
PFN_xrStructureTypeToString StructureTypeToString;
PFN_xrGetSystem GetSystem;
PFN_xrGetSystemProperties GetSystemProperties;
PFN_xrEnumerateEnvironmentBlendModes EnumerateEnvironmentBlendModes;
PFN_xrCreateSession CreateSession;
PFN_xrDestroySession DestroySession;
PFN_xrEnumerateReferenceSpaces EnumerateReferenceSpaces;
PFN_xrCreateReferenceSpace CreateReferenceSpace;
PFN_xrGetReferenceSpaceBoundsRect GetReferenceSpaceBoundsRect;
PFN_xrCreateActionSpace CreateActionSpace;
PFN_xrLocateSpace LocateSpace;
PFN_xrDestroySpace DestroySpace;
PFN_xrEnumerateViewConfigurations EnumerateViewConfigurations;
PFN_xrGetViewConfigurationProperties GetViewConfigurationProperties;
PFN_xrEnumerateViewConfigurationViews EnumerateViewConfigurationViews;
PFN_xrEnumerateSwapchainFormats EnumerateSwapchainFormats;
PFN_xrCreateSwapchain CreateSwapchain;
PFN_xrDestroySwapchain DestroySwapchain;
PFN_xrEnumerateSwapchainImages EnumerateSwapchainImages;
PFN_xrAcquireSwapchainImage AcquireSwapchainImage;
PFN_xrWaitSwapchainImage WaitSwapchainImage;
PFN_xrReleaseSwapchainImage ReleaseSwapchainImage;
PFN_xrBeginSession BeginSession;
PFN_xrEndSession EndSession;
PFN_xrRequestExitSession RequestExitSession;
PFN_xrWaitFrame WaitFrame;
PFN_xrBeginFrame BeginFrame;
PFN_xrEndFrame EndFrame;
PFN_xrLocateViews LocateViews;
PFN_xrStringToPath StringToPath;
PFN_xrPathToString PathToString;
PFN_xrCreateActionSet CreateActionSet;
PFN_xrDestroyActionSet DestroyActionSet;
PFN_xrCreateAction CreateAction;
PFN_xrDestroyAction DestroyAction;
PFN_xrSuggestInteractionProfileBindings SuggestInteractionProfileBindings;
PFN_xrAttachSessionActionSets AttachSessionActionSets;
PFN_xrGetCurrentInteractionProfile GetCurrentInteractionProfile;
PFN_xrGetActionStateBoolean GetActionStateBoolean;
PFN_xrGetActionStateFloat GetActionStateFloat;
PFN_xrGetActionStateVector2f GetActionStateVector2f;
PFN_xrGetActionStatePose GetActionStatePose;
PFN_xrSyncActions SyncActions;
PFN_xrEnumerateBoundSourcesForAction EnumerateBoundSourcesForAction;
PFN_xrGetInputSourceLocalizedName GetInputSourceLocalizedName;
PFN_xrApplyHapticFeedback ApplyHapticFeedback;
PFN_xrStopHapticFeedback StopHapticFeedback;
// ---- XR_KHR_android_thread_settings extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
PFN_xrSetAndroidApplicationThreadKHR SetAndroidApplicationThreadKHR;
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_android_surface_swapchain extension commands
#if defined(XR_USE_PLATFORM_ANDROID)
PFN_xrCreateSwapchainAndroidSurfaceKHR CreateSwapchainAndroidSurfaceKHR;
#endif // defined(XR_USE_PLATFORM_ANDROID)
// ---- XR_KHR_opengl_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL)
PFN_xrGetOpenGLGraphicsRequirementsKHR GetOpenGLGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_OPENGL)
// ---- XR_KHR_opengl_es_enable extension commands
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
PFN_xrGetOpenGLESGraphicsRequirementsKHR GetOpenGLESGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_OPENGL_ES)
// ---- XR_KHR_vulkan_enable extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanInstanceExtensionsKHR GetVulkanInstanceExtensionsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanDeviceExtensionsKHR GetVulkanDeviceExtensionsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsDeviceKHR GetVulkanGraphicsDeviceKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsRequirementsKHR GetVulkanGraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_KHR_D3D11_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D11)
PFN_xrGetD3D11GraphicsRequirementsKHR GetD3D11GraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_D3D11)
// ---- XR_KHR_D3D12_enable extension commands
#if defined(XR_USE_GRAPHICS_API_D3D12)
PFN_xrGetD3D12GraphicsRequirementsKHR GetD3D12GraphicsRequirementsKHR;
#endif // defined(XR_USE_GRAPHICS_API_D3D12)
// ---- XR_KHR_visibility_mask extension commands
PFN_xrGetVisibilityMaskKHR GetVisibilityMaskKHR;
// ---- XR_KHR_win32_convert_performance_counter_time extension commands
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrConvertWin32PerformanceCounterToTimeKHR ConvertWin32PerformanceCounterToTimeKHR;
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrConvertTimeToWin32PerformanceCounterKHR ConvertTimeToWin32PerformanceCounterKHR;
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_KHR_convert_timespec_time extension commands
#if defined(XR_USE_TIMESPEC)
PFN_xrConvertTimespecTimeToTimeKHR ConvertTimespecTimeToTimeKHR;
#endif // defined(XR_USE_TIMESPEC)
#if defined(XR_USE_TIMESPEC)
PFN_xrConvertTimeToTimespecTimeKHR ConvertTimeToTimespecTimeKHR;
#endif // defined(XR_USE_TIMESPEC)
// ---- XR_KHR_loader_init extension commands
PFN_xrInitializeLoaderKHR InitializeLoaderKHR;
// ---- XR_KHR_vulkan_enable2 extension commands
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrCreateVulkanInstanceKHR CreateVulkanInstanceKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrCreateVulkanDeviceKHR CreateVulkanDeviceKHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsDevice2KHR GetVulkanGraphicsDevice2KHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
#if defined(XR_USE_GRAPHICS_API_VULKAN)
PFN_xrGetVulkanGraphicsRequirements2KHR GetVulkanGraphicsRequirements2KHR;
#endif // defined(XR_USE_GRAPHICS_API_VULKAN)
// ---- XR_EXT_performance_settings extension commands
PFN_xrPerfSettingsSetPerformanceLevelEXT PerfSettingsSetPerformanceLevelEXT;
// ---- XR_EXT_thermal_query extension commands
PFN_xrThermalGetTemperatureTrendEXT ThermalGetTemperatureTrendEXT;
// ---- XR_EXT_debug_utils extension commands
PFN_xrSetDebugUtilsObjectNameEXT SetDebugUtilsObjectNameEXT;
PFN_xrCreateDebugUtilsMessengerEXT CreateDebugUtilsMessengerEXT;
PFN_xrDestroyDebugUtilsMessengerEXT DestroyDebugUtilsMessengerEXT;
PFN_xrSubmitDebugUtilsMessageEXT SubmitDebugUtilsMessageEXT;
PFN_xrSessionBeginDebugUtilsLabelRegionEXT SessionBeginDebugUtilsLabelRegionEXT;
PFN_xrSessionEndDebugUtilsLabelRegionEXT SessionEndDebugUtilsLabelRegionEXT;
PFN_xrSessionInsertDebugUtilsLabelEXT SessionInsertDebugUtilsLabelEXT;
// ---- XR_MSFT_spatial_anchor extension commands
PFN_xrCreateSpatialAnchorMSFT CreateSpatialAnchorMSFT;
PFN_xrCreateSpatialAnchorSpaceMSFT CreateSpatialAnchorSpaceMSFT;
PFN_xrDestroySpatialAnchorMSFT DestroySpatialAnchorMSFT;
// ---- XR_EXT_conformance_automation extension commands
PFN_xrSetInputDeviceActiveEXT SetInputDeviceActiveEXT;
PFN_xrSetInputDeviceStateBoolEXT SetInputDeviceStateBoolEXT;
PFN_xrSetInputDeviceStateFloatEXT SetInputDeviceStateFloatEXT;
PFN_xrSetInputDeviceStateVector2fEXT SetInputDeviceStateVector2fEXT;
PFN_xrSetInputDeviceLocationEXT SetInputDeviceLocationEXT;
// ---- XR_MSFT_spatial_graph_bridge extension commands
PFN_xrCreateSpatialGraphNodeSpaceMSFT CreateSpatialGraphNodeSpaceMSFT;
// ---- XR_EXT_hand_tracking extension commands
PFN_xrCreateHandTrackerEXT CreateHandTrackerEXT;
PFN_xrDestroyHandTrackerEXT DestroyHandTrackerEXT;
PFN_xrLocateHandJointsEXT LocateHandJointsEXT;
// ---- XR_MSFT_hand_tracking_mesh extension commands
PFN_xrCreateHandMeshSpaceMSFT CreateHandMeshSpaceMSFT;
PFN_xrUpdateHandMeshMSFT UpdateHandMeshMSFT;
// ---- XR_MSFT_controller_model extension commands
PFN_xrGetControllerModelKeyMSFT GetControllerModelKeyMSFT;
PFN_xrLoadControllerModelMSFT LoadControllerModelMSFT;
PFN_xrGetControllerModelPropertiesMSFT GetControllerModelPropertiesMSFT;
PFN_xrGetControllerModelStateMSFT GetControllerModelStateMSFT;
// ---- XR_MSFT_perception_anchor_interop extension commands
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrCreateSpatialAnchorFromPerceptionAnchorMSFT CreateSpatialAnchorFromPerceptionAnchorMSFT;
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrTryGetPerceptionAnchorFromSpatialAnchorMSFT TryGetPerceptionAnchorFromSpatialAnchorMSFT;
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_MSFT_composition_layer_reprojection extension commands
PFN_xrEnumerateReprojectionModesMSFT EnumerateReprojectionModesMSFT;
// ---- XR_FB_swapchain_update_state extension commands
PFN_xrUpdateSwapchainFB UpdateSwapchainFB;
PFN_xrGetSwapchainStateFB GetSwapchainStateFB;
// ---- XR_MSFT_scene_understanding extension commands
PFN_xrEnumerateSceneComputeFeaturesMSFT EnumerateSceneComputeFeaturesMSFT;
PFN_xrCreateSceneObserverMSFT CreateSceneObserverMSFT;
PFN_xrDestroySceneObserverMSFT DestroySceneObserverMSFT;
PFN_xrCreateSceneMSFT CreateSceneMSFT;
PFN_xrDestroySceneMSFT DestroySceneMSFT;
PFN_xrComputeNewSceneMSFT ComputeNewSceneMSFT;
PFN_xrGetSceneComputeStateMSFT GetSceneComputeStateMSFT;
PFN_xrGetSceneComponentsMSFT GetSceneComponentsMSFT;
PFN_xrLocateSceneComponentsMSFT LocateSceneComponentsMSFT;
PFN_xrGetSceneMeshBuffersMSFT GetSceneMeshBuffersMSFT;
// ---- XR_MSFT_scene_understanding_serialization extension commands
PFN_xrDeserializeSceneMSFT DeserializeSceneMSFT;
PFN_xrGetSerializedSceneFragmentDataMSFT GetSerializedSceneFragmentDataMSFT;
// ---- XR_FB_display_refresh_rate extension commands
PFN_xrEnumerateDisplayRefreshRatesFB EnumerateDisplayRefreshRatesFB;
PFN_xrGetDisplayRefreshRateFB GetDisplayRefreshRateFB;
PFN_xrRequestDisplayRefreshRateFB RequestDisplayRefreshRateFB;
// ---- XR_HTCX_vive_tracker_interaction extension commands
PFN_xrEnumerateViveTrackerPathsHTCX EnumerateViveTrackerPathsHTCX;
// ---- XR_HTC_facial_tracking extension commands
PFN_xrCreateFacialTrackerHTC CreateFacialTrackerHTC;
PFN_xrDestroyFacialTrackerHTC DestroyFacialTrackerHTC;
PFN_xrGetFacialExpressionsHTC GetFacialExpressionsHTC;
// ---- XR_FB_color_space extension commands
PFN_xrEnumerateColorSpacesFB EnumerateColorSpacesFB;
PFN_xrSetColorSpaceFB SetColorSpaceFB;
// ---- XR_FB_hand_tracking_mesh extension commands
PFN_xrGetHandMeshFB GetHandMeshFB;
// ---- XR_FB_foveation extension commands
PFN_xrCreateFoveationProfileFB CreateFoveationProfileFB;
PFN_xrDestroyFoveationProfileFB DestroyFoveationProfileFB;
// ---- XR_FB_keyboard_tracking extension commands
PFN_xrQuerySystemTrackedKeyboardFB QuerySystemTrackedKeyboardFB;
PFN_xrCreateKeyboardSpaceFB CreateKeyboardSpaceFB;
// ---- XR_FB_triangle_mesh extension commands
PFN_xrCreateTriangleMeshFB CreateTriangleMeshFB;
PFN_xrDestroyTriangleMeshFB DestroyTriangleMeshFB;
PFN_xrTriangleMeshGetVertexBufferFB TriangleMeshGetVertexBufferFB;
PFN_xrTriangleMeshGetIndexBufferFB TriangleMeshGetIndexBufferFB;
PFN_xrTriangleMeshBeginUpdateFB TriangleMeshBeginUpdateFB;
PFN_xrTriangleMeshEndUpdateFB TriangleMeshEndUpdateFB;
PFN_xrTriangleMeshBeginVertexBufferUpdateFB TriangleMeshBeginVertexBufferUpdateFB;
PFN_xrTriangleMeshEndVertexBufferUpdateFB TriangleMeshEndVertexBufferUpdateFB;
// ---- XR_FB_passthrough extension commands
PFN_xrCreatePassthroughFB CreatePassthroughFB;
PFN_xrDestroyPassthroughFB DestroyPassthroughFB;
PFN_xrPassthroughStartFB PassthroughStartFB;
PFN_xrPassthroughPauseFB PassthroughPauseFB;
PFN_xrCreatePassthroughLayerFB CreatePassthroughLayerFB;
PFN_xrDestroyPassthroughLayerFB DestroyPassthroughLayerFB;
PFN_xrPassthroughLayerPauseFB PassthroughLayerPauseFB;
PFN_xrPassthroughLayerResumeFB PassthroughLayerResumeFB;
PFN_xrPassthroughLayerSetStyleFB PassthroughLayerSetStyleFB;
PFN_xrCreateGeometryInstanceFB CreateGeometryInstanceFB;
PFN_xrDestroyGeometryInstanceFB DestroyGeometryInstanceFB;
PFN_xrGeometryInstanceSetTransformFB GeometryInstanceSetTransformFB;
// ---- XR_FB_render_model extension commands
PFN_xrEnumerateRenderModelPathsFB EnumerateRenderModelPathsFB;
PFN_xrGetRenderModelPropertiesFB GetRenderModelPropertiesFB;
PFN_xrLoadRenderModelFB LoadRenderModelFB;
// ---- XR_VARJO_environment_depth_estimation extension commands
PFN_xrSetEnvironmentDepthEstimationVARJO SetEnvironmentDepthEstimationVARJO;
// ---- XR_VARJO_marker_tracking extension commands
PFN_xrSetMarkerTrackingVARJO SetMarkerTrackingVARJO;
PFN_xrSetMarkerTrackingTimeoutVARJO SetMarkerTrackingTimeoutVARJO;
PFN_xrSetMarkerTrackingPredictionVARJO SetMarkerTrackingPredictionVARJO;
PFN_xrGetMarkerSizeVARJO GetMarkerSizeVARJO;
PFN_xrCreateMarkerSpaceVARJO CreateMarkerSpaceVARJO;
// ---- XR_MSFT_spatial_anchor_persistence extension commands
PFN_xrCreateSpatialAnchorStoreConnectionMSFT CreateSpatialAnchorStoreConnectionMSFT;
PFN_xrDestroySpatialAnchorStoreConnectionMSFT DestroySpatialAnchorStoreConnectionMSFT;
PFN_xrPersistSpatialAnchorMSFT PersistSpatialAnchorMSFT;
PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT EnumeratePersistedSpatialAnchorNamesMSFT;
PFN_xrCreateSpatialAnchorFromPersistedNameMSFT CreateSpatialAnchorFromPersistedNameMSFT;
PFN_xrUnpersistSpatialAnchorMSFT UnpersistSpatialAnchorMSFT;
PFN_xrClearSpatialAnchorStoreMSFT ClearSpatialAnchorStoreMSFT;
// ---- XR_OCULUS_audio_device_guid extension commands
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrGetAudioOutputDeviceGuidOculus GetAudioOutputDeviceGuidOculus;
#endif // defined(XR_USE_PLATFORM_WIN32)
#if defined(XR_USE_PLATFORM_WIN32)
PFN_xrGetAudioInputDeviceGuidOculus GetAudioInputDeviceGuidOculus;
#endif // defined(XR_USE_PLATFORM_WIN32)
// ---- XR_ALMALENCE_digital_lens_control extension commands
PFN_xrSetDigitalLensControlALMALENCE SetDigitalLensControlALMALENCE;
// ---- XR_FB_passthrough_keyboard_hands extension commands
PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB PassthroughLayerSetKeyboardHandsIntensityFB;
};
// Prototype for dispatch table helper function
void GeneratedXrPopulateDispatchTable(struct XrGeneratedDispatchTable *table,
XrInstance instance,
PFN_xrGetInstanceProcAddr get_inst_proc_addr);
#ifdef __cplusplus
} // extern "C"
#endif