Browse Source

Add OpenXR 1.0.22 to thirdparty libraries

Will be compiled and used in the next commit.

Co-authored-by: Rémi Verschelde <[email protected]>
Bastiaan Olij 3 years ago
parent
commit
65bae5a341
59 changed files with 23956 additions and 1 deletions
  1. 5 1
      COPYRIGHT.txt
  2. 25 0
      thirdparty/README.md
  3. 123 0
      thirdparty/openxr/COPYING.adoc
  4. 202 0
      thirdparty/openxr/LICENSE
  5. 3925 0
      thirdparty/openxr/include/openxr/openxr.h
  6. 675 0
      thirdparty/openxr/include/openxr/openxr_platform.h
  7. 110 0
      thirdparty/openxr/include/openxr/openxr_platform_defines.h
  8. 2746 0
      thirdparty/openxr/include/openxr/openxr_reflection.h
  9. 10 0
      thirdparty/openxr/src/.clang-format
  10. 47 0
      thirdparty/openxr/src/common/extra_algorithms.h
  11. 322 0
      thirdparty/openxr/src/common/filesystem_utils.cpp
  12. 46 0
      thirdparty/openxr/src/common/filesystem_utils.hpp
  13. 108 0
      thirdparty/openxr/src/common/hex_and_handles.h
  14. 114 0
      thirdparty/openxr/src/common/loader_interfaces.h
  15. 276 0
      thirdparty/openxr/src/common/object_info.cpp
  16. 229 0
      thirdparty/openxr/src/common/object_info.h
  17. 345 0
      thirdparty/openxr/src/common/platform_utils.hpp
  18. 45 0
      thirdparty/openxr/src/common/stdfs_conditions.h
  19. 89 0
      thirdparty/openxr/src/common/xr_dependencies.h
  20. 787 0
      thirdparty/openxr/src/common/xr_linear.h
  21. 115 0
      thirdparty/openxr/src/external/jsoncpp/AUTHORS
  22. 55 0
      thirdparty/openxr/src/external/jsoncpp/LICENSE
  23. 88 0
      thirdparty/openxr/src/external/jsoncpp/include/json/allocator.h
  24. 61 0
      thirdparty/openxr/src/external/jsoncpp/include/json/assertions.h
  25. 150 0
      thirdparty/openxr/src/external/jsoncpp/include/json/config.h
  26. 43 0
      thirdparty/openxr/src/external/jsoncpp/include/json/forwards.h
  27. 15 0
      thirdparty/openxr/src/external/jsoncpp/include/json/json.h
  28. 61 0
      thirdparty/openxr/src/external/jsoncpp/include/json/json_features.h
  29. 405 0
      thirdparty/openxr/src/external/jsoncpp/include/json/reader.h
  30. 935 0
      thirdparty/openxr/src/external/jsoncpp/include/json/value.h
  31. 28 0
      thirdparty/openxr/src/external/jsoncpp/include/json/version.h
  32. 369 0
      thirdparty/openxr/src/external/jsoncpp/include/json/writer.h
  33. 1992 0
      thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_reader.cpp
  34. 138 0
      thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_tool.h
  35. 1634 0
      thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_value.cpp
  36. 156 0
      thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_valueiterator.inl
  37. 1259 0
      thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_writer.cpp
  38. 5 0
      thirdparty/openxr/src/loader/.gitignore
  39. 319 0
      thirdparty/openxr/src/loader/android_utilities.cpp
  40. 32 0
      thirdparty/openxr/src/loader/android_utilities.h
  41. 399 0
      thirdparty/openxr/src/loader/api_layer_interface.cpp
  42. 54 0
      thirdparty/openxr/src/loader/api_layer_interface.hpp
  43. 40 0
      thirdparty/openxr/src/loader/exception_handling.hpp
  44. 847 0
      thirdparty/openxr/src/loader/loader_core.cpp
  45. 303 0
      thirdparty/openxr/src/loader/loader_instance.cpp
  46. 77 0
      thirdparty/openxr/src/loader/loader_instance.hpp
  47. 239 0
      thirdparty/openxr/src/loader/loader_logger.cpp
  48. 194 0
      thirdparty/openxr/src/loader/loader_logger.hpp
  49. 291 0
      thirdparty/openxr/src/loader/loader_logger_recorders.cpp
  50. 40 0
      thirdparty/openxr/src/loader/loader_logger_recorders.hpp
  51. 204 0
      thirdparty/openxr/src/loader/loader_platform.hpp
  52. 845 0
      thirdparty/openxr/src/loader/manifest_file.cpp
  53. 103 0
      thirdparty/openxr/src/loader/manifest_file.hpp
  54. 493 0
      thirdparty/openxr/src/loader/runtime_interface.cpp
  55. 84 0
      thirdparty/openxr/src/loader/runtime_interface.hpp
  56. 700 0
      thirdparty/openxr/src/loader/xr_generated_loader.cpp
  57. 252 0
      thirdparty/openxr/src/loader/xr_generated_loader.hpp
  58. 347 0
      thirdparty/openxr/src/xr_generated_dispatch_table.c
  59. 355 0
      thirdparty/openxr/src/xr_generated_dispatch_table.h

+ 5 - 1
COPYRIGHT.txt

@@ -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 - 0
thirdparty/README.md

@@ -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 - 0
thirdparty/openxr/COPYING.adoc

@@ -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 - 0
thirdparty/openxr/LICENSE

@@ -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 - 0
thirdparty/openxr/include/openxr/openxr.h

@@ -0,0 +1,3925 @@
+#ifndef OPENXR_H_
+#define OPENXR_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.
+**
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#define XR_VERSION_1_0 1
+#include "openxr_platform_defines.h"
+#define XR_MAKE_VERSION(major, minor, patch) \
+    ((((major) & 0xffffULL) << 48) | (((minor) & 0xffffULL) << 32) | ((patch) & 0xffffffffULL))
+
+// OpenXR current version number.
+#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(1, 0, 22)
+
+#define XR_VERSION_MAJOR(version) (uint16_t)(((uint64_t)(version) >> 48)& 0xffffULL)
+#define XR_VERSION_MINOR(version) (uint16_t)(((uint64_t)(version) >> 32) & 0xffffULL)
+#define XR_VERSION_PATCH(version) (uint32_t)((uint64_t)(version) & 0xffffffffULL)
+
+#if !defined(XR_NULL_HANDLE)
+#if (XR_PTR_SIZE == 8) && XR_CPP_NULLPTR_SUPPORTED
+    #define XR_NULL_HANDLE nullptr
+#else
+    #define XR_NULL_HANDLE 0
+#endif
+#endif
+        
+
+
+#define XR_NULL_SYSTEM_ID 0
+
+
+#define XR_NULL_PATH 0
+
+
+#define XR_SUCCEEDED(result) ((result) >= 0)
+
+
+#define XR_FAILED(result) ((result) < 0)
+
+
+#define XR_UNQUALIFIED_SUCCESS(result) ((result) == 0)
+
+
+#define XR_NO_DURATION 0
+
+
+#define XR_INFINITE_DURATION 0x7fffffffffffffffLL
+
+
+#define XR_MIN_HAPTIC_DURATION -1
+
+
+#define XR_FREQUENCY_UNSPECIFIED 0
+
+
+#define XR_MAX_EVENT_DATA_SIZE sizeof(XrEventDataBuffer)
+
+
+#if !defined(XR_MAY_ALIAS)
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4))
+#define XR_MAY_ALIAS __attribute__((__may_alias__))
+#else
+#define XR_MAY_ALIAS
+#endif
+#endif
+
+
+#if !defined(XR_DEFINE_HANDLE)
+#if (XR_PTR_SIZE == 8)
+    #define XR_DEFINE_HANDLE(object) typedef struct object##_T* object;
+#else
+    #define XR_DEFINE_HANDLE(object) typedef uint64_t object;
+#endif
+#endif
+        
+
+
+#if !defined(XR_DEFINE_ATOM)
+    #define XR_DEFINE_ATOM(object) typedef uint64_t object;
+#endif
+        
+
+typedef uint64_t XrVersion;
+typedef uint64_t XrFlags64;
+XR_DEFINE_ATOM(XrSystemId)
+typedef uint32_t XrBool32;
+XR_DEFINE_ATOM(XrPath)
+typedef int64_t XrTime;
+typedef int64_t XrDuration;
+XR_DEFINE_HANDLE(XrInstance)
+XR_DEFINE_HANDLE(XrSession)
+XR_DEFINE_HANDLE(XrSpace)
+XR_DEFINE_HANDLE(XrAction)
+XR_DEFINE_HANDLE(XrSwapchain)
+XR_DEFINE_HANDLE(XrActionSet)
+#define XR_TRUE                           1
+#define XR_FALSE                          0
+#define XR_MAX_EXTENSION_NAME_SIZE        128
+#define XR_MAX_API_LAYER_NAME_SIZE        256
+#define XR_MAX_API_LAYER_DESCRIPTION_SIZE 256
+#define XR_MAX_SYSTEM_NAME_SIZE           256
+#define XR_MAX_APPLICATION_NAME_SIZE      128
+#define XR_MAX_ENGINE_NAME_SIZE           128
+#define XR_MAX_RUNTIME_NAME_SIZE          128
+#define XR_MAX_PATH_LENGTH                256
+#define XR_MAX_STRUCTURE_NAME_SIZE        64
+#define XR_MAX_RESULT_STRING_SIZE         64
+#define XR_MIN_COMPOSITION_LAYERS_SUPPORTED 16
+#define XR_MAX_ACTION_SET_NAME_SIZE       64
+#define XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE 128
+#define XR_MAX_ACTION_NAME_SIZE           64
+#define XR_MAX_LOCALIZED_ACTION_NAME_SIZE 128
+
+typedef enum XrResult {
+    XR_SUCCESS = 0,
+    XR_TIMEOUT_EXPIRED = 1,
+    XR_SESSION_LOSS_PENDING = 3,
+    XR_EVENT_UNAVAILABLE = 4,
+    XR_SPACE_BOUNDS_UNAVAILABLE = 7,
+    XR_SESSION_NOT_FOCUSED = 8,
+    XR_FRAME_DISCARDED = 9,
+    XR_ERROR_VALIDATION_FAILURE = -1,
+    XR_ERROR_RUNTIME_FAILURE = -2,
+    XR_ERROR_OUT_OF_MEMORY = -3,
+    XR_ERROR_API_VERSION_UNSUPPORTED = -4,
+    XR_ERROR_INITIALIZATION_FAILED = -6,
+    XR_ERROR_FUNCTION_UNSUPPORTED = -7,
+    XR_ERROR_FEATURE_UNSUPPORTED = -8,
+    XR_ERROR_EXTENSION_NOT_PRESENT = -9,
+    XR_ERROR_LIMIT_REACHED = -10,
+    XR_ERROR_SIZE_INSUFFICIENT = -11,
+    XR_ERROR_HANDLE_INVALID = -12,
+    XR_ERROR_INSTANCE_LOST = -13,
+    XR_ERROR_SESSION_RUNNING = -14,
+    XR_ERROR_SESSION_NOT_RUNNING = -16,
+    XR_ERROR_SESSION_LOST = -17,
+    XR_ERROR_SYSTEM_INVALID = -18,
+    XR_ERROR_PATH_INVALID = -19,
+    XR_ERROR_PATH_COUNT_EXCEEDED = -20,
+    XR_ERROR_PATH_FORMAT_INVALID = -21,
+    XR_ERROR_PATH_UNSUPPORTED = -22,
+    XR_ERROR_LAYER_INVALID = -23,
+    XR_ERROR_LAYER_LIMIT_EXCEEDED = -24,
+    XR_ERROR_SWAPCHAIN_RECT_INVALID = -25,
+    XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -26,
+    XR_ERROR_ACTION_TYPE_MISMATCH = -27,
+    XR_ERROR_SESSION_NOT_READY = -28,
+    XR_ERROR_SESSION_NOT_STOPPING = -29,
+    XR_ERROR_TIME_INVALID = -30,
+    XR_ERROR_REFERENCE_SPACE_UNSUPPORTED = -31,
+    XR_ERROR_FILE_ACCESS_ERROR = -32,
+    XR_ERROR_FILE_CONTENTS_INVALID = -33,
+    XR_ERROR_FORM_FACTOR_UNSUPPORTED = -34,
+    XR_ERROR_FORM_FACTOR_UNAVAILABLE = -35,
+    XR_ERROR_API_LAYER_NOT_PRESENT = -36,
+    XR_ERROR_CALL_ORDER_INVALID = -37,
+    XR_ERROR_GRAPHICS_DEVICE_INVALID = -38,
+    XR_ERROR_POSE_INVALID = -39,
+    XR_ERROR_INDEX_OUT_OF_RANGE = -40,
+    XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED = -41,
+    XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED = -42,
+    XR_ERROR_NAME_DUPLICATED = -44,
+    XR_ERROR_NAME_INVALID = -45,
+    XR_ERROR_ACTIONSET_NOT_ATTACHED = -46,
+    XR_ERROR_ACTIONSETS_ALREADY_ATTACHED = -47,
+    XR_ERROR_LOCALIZED_NAME_DUPLICATED = -48,
+    XR_ERROR_LOCALIZED_NAME_INVALID = -49,
+    XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING = -50,
+    XR_ERROR_RUNTIME_UNAVAILABLE = -51,
+    XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000,
+    XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001,
+    XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT = -1000039001,
+    XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT = -1000053000,
+    XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT = -1000055000,
+    XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT = -1000066000,
+    XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT = -1000097000,
+    XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT = -1000097001,
+    XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT = -1000097002,
+    XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT = -1000097003,
+    XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT = -1000097004,
+    XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT = -1000097005,
+    XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB = -1000101000,
+    XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB = -1000108000,
+    XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB = -1000118000,
+    XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB = -1000118001,
+    XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB = -1000118002,
+    XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB = -1000118003,
+    XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB = -1000118004,
+    XR_ERROR_UNKNOWN_PASSTHROUGH_FB = -1000118050,
+    XR_ERROR_RENDER_MODEL_KEY_INVALID_FB = -1000119000,
+    XR_RENDER_MODEL_UNAVAILABLE_FB = 1000119020,
+    XR_ERROR_MARKER_NOT_TRACKED_VARJO = -1000124000,
+    XR_ERROR_MARKER_ID_INVALID_VARJO = -1000124001,
+    XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT = -1000142001,
+    XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT = -1000142002,
+    XR_RESULT_MAX_ENUM = 0x7FFFFFFF
+} XrResult;
+
+typedef enum XrStructureType {
+    XR_TYPE_UNKNOWN = 0,
+    XR_TYPE_API_LAYER_PROPERTIES = 1,
+    XR_TYPE_EXTENSION_PROPERTIES = 2,
+    XR_TYPE_INSTANCE_CREATE_INFO = 3,
+    XR_TYPE_SYSTEM_GET_INFO = 4,
+    XR_TYPE_SYSTEM_PROPERTIES = 5,
+    XR_TYPE_VIEW_LOCATE_INFO = 6,
+    XR_TYPE_VIEW = 7,
+    XR_TYPE_SESSION_CREATE_INFO = 8,
+    XR_TYPE_SWAPCHAIN_CREATE_INFO = 9,
+    XR_TYPE_SESSION_BEGIN_INFO = 10,
+    XR_TYPE_VIEW_STATE = 11,
+    XR_TYPE_FRAME_END_INFO = 12,
+    XR_TYPE_HAPTIC_VIBRATION = 13,
+    XR_TYPE_EVENT_DATA_BUFFER = 16,
+    XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING = 17,
+    XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED = 18,
+    XR_TYPE_ACTION_STATE_BOOLEAN = 23,
+    XR_TYPE_ACTION_STATE_FLOAT = 24,
+    XR_TYPE_ACTION_STATE_VECTOR2F = 25,
+    XR_TYPE_ACTION_STATE_POSE = 27,
+    XR_TYPE_ACTION_SET_CREATE_INFO = 28,
+    XR_TYPE_ACTION_CREATE_INFO = 29,
+    XR_TYPE_INSTANCE_PROPERTIES = 32,
+    XR_TYPE_FRAME_WAIT_INFO = 33,
+    XR_TYPE_COMPOSITION_LAYER_PROJECTION = 35,
+    XR_TYPE_COMPOSITION_LAYER_QUAD = 36,
+    XR_TYPE_REFERENCE_SPACE_CREATE_INFO = 37,
+    XR_TYPE_ACTION_SPACE_CREATE_INFO = 38,
+    XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING = 40,
+    XR_TYPE_VIEW_CONFIGURATION_VIEW = 41,
+    XR_TYPE_SPACE_LOCATION = 42,
+    XR_TYPE_SPACE_VELOCITY = 43,
+    XR_TYPE_FRAME_STATE = 44,
+    XR_TYPE_VIEW_CONFIGURATION_PROPERTIES = 45,
+    XR_TYPE_FRAME_BEGIN_INFO = 46,
+    XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW = 48,
+    XR_TYPE_EVENT_DATA_EVENTS_LOST = 49,
+    XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING = 51,
+    XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED = 52,
+    XR_TYPE_INTERACTION_PROFILE_STATE = 53,
+    XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO = 55,
+    XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO = 56,
+    XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO = 57,
+    XR_TYPE_ACTION_STATE_GET_INFO = 58,
+    XR_TYPE_HAPTIC_ACTION_INFO = 59,
+    XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO = 60,
+    XR_TYPE_ACTIONS_SYNC_INFO = 61,
+    XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO = 62,
+    XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO = 63,
+    XR_TYPE_COMPOSITION_LAYER_CUBE_KHR = 1000006000,
+    XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR = 1000008000,
+    XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR = 1000010000,
+    XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR = 1000014000,
+    XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT = 1000015000,
+    XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR = 1000017000,
+    XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR = 1000018000,
+    XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000019000,
+    XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000019001,
+    XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000019002,
+    XR_TYPE_DEBUG_UTILS_LABEL_EXT = 1000019003,
+    XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR = 1000023000,
+    XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR = 1000023001,
+    XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR = 1000023002,
+    XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR = 1000023003,
+    XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR = 1000023004,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR = 1000023005,
+    XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR = 1000024001,
+    XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR = 1000024002,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR = 1000024003,
+    XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR = 1000025000,
+    XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR = 1000025001,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR = 1000025002,
+    XR_TYPE_GRAPHICS_BINDING_D3D11_KHR = 1000027000,
+    XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR = 1000027001,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR = 1000027002,
+    XR_TYPE_GRAPHICS_BINDING_D3D12_KHR = 1000028000,
+    XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR = 1000028001,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR = 1000028002,
+    XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT = 1000030000,
+    XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT = 1000030001,
+    XR_TYPE_VISIBILITY_MASK_KHR = 1000031000,
+    XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR = 1000031001,
+    XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX = 1000033000,
+    XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX = 1000033003,
+    XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR = 1000034000,
+    XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT = 1000039000,
+    XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT = 1000039001,
+    XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB = 1000040000,
+    XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB = 1000041001,
+    XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT = 1000046000,
+    XR_TYPE_GRAPHICS_BINDING_EGL_MNDX = 1000048004,
+    XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT = 1000049000,
+    XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT = 1000051000,
+    XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001,
+    XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002,
+    XR_TYPE_HAND_JOINT_LOCATIONS_EXT = 1000051003,
+    XR_TYPE_HAND_JOINT_VELOCITIES_EXT = 1000051004,
+    XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT = 1000052000,
+    XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT = 1000052001,
+    XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT = 1000052002,
+    XR_TYPE_HAND_MESH_MSFT = 1000052003,
+    XR_TYPE_HAND_POSE_TYPE_INFO_MSFT = 1000052004,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT = 1000053000,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT = 1000053001,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT = 1000053002,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT = 1000053003,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT = 1000053004,
+    XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT = 1000053005,
+    XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT = 1000055000,
+    XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT = 1000055001,
+    XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT = 1000055002,
+    XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT = 1000055003,
+    XR_TYPE_CONTROLLER_MODEL_STATE_MSFT = 1000055004,
+    XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC = 1000059000,
+    XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT = 1000063000,
+    XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT = 1000066000,
+    XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT = 1000066001,
+    XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB = 1000070000,
+    XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB = 1000072000,
+    XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE = 1000079000,
+    XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT = 1000080000,
+    XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR = 1000089000,
+    XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR = 1000090000,
+    XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR = 1000090001,
+    XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR = 1000090003,
+    XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR = 1000091000,
+    XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT = 1000097000,
+    XR_TYPE_SCENE_CREATE_INFO_MSFT = 1000097001,
+    XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT = 1000097002,
+    XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT = 1000097003,
+    XR_TYPE_SCENE_COMPONENTS_MSFT = 1000097004,
+    XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT = 1000097005,
+    XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT = 1000097006,
+    XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT = 1000097007,
+    XR_TYPE_SCENE_OBJECTS_MSFT = 1000097008,
+    XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT = 1000097009,
+    XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT = 1000097010,
+    XR_TYPE_SCENE_PLANES_MSFT = 1000097011,
+    XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT = 1000097012,
+    XR_TYPE_SCENE_MESHES_MSFT = 1000097013,
+    XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT = 1000097014,
+    XR_TYPE_SCENE_MESH_BUFFERS_MSFT = 1000097015,
+    XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT = 1000097016,
+    XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT = 1000097017,
+    XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT = 1000097018,
+    XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT = 1000098000,
+    XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT = 1000098001,
+    XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB = 1000101000,
+    XR_TYPE_VIVE_TRACKER_PATHS_HTCX = 1000103000,
+    XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX = 1000103001,
+    XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC = 1000104000,
+    XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC = 1000104001,
+    XR_TYPE_FACIAL_EXPRESSIONS_HTC = 1000104002,
+    XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB = 1000108000,
+    XR_TYPE_HAND_TRACKING_MESH_FB = 1000110001,
+    XR_TYPE_HAND_TRACKING_SCALE_FB = 1000110003,
+    XR_TYPE_HAND_TRACKING_AIM_STATE_FB = 1000111001,
+    XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB = 1000112000,
+    XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB = 1000114000,
+    XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB = 1000114001,
+    XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB = 1000114002,
+    XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB = 1000115000,
+    XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB = 1000116009,
+    XR_TYPE_KEYBOARD_TRACKING_QUERY_FB = 1000116004,
+    XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB = 1000116002,
+    XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB = 1000117001,
+    XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB = 1000118000,
+    XR_TYPE_PASSTHROUGH_CREATE_INFO_FB = 1000118001,
+    XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB = 1000118002,
+    XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB = 1000118003,
+    XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB = 1000118004,
+    XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB = 1000118005,
+    XR_TYPE_PASSTHROUGH_STYLE_FB = 1000118020,
+    XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB = 1000118021,
+    XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB = 1000118022,
+    XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB = 1000118030,
+    XR_TYPE_RENDER_MODEL_PATH_INFO_FB = 1000119000,
+    XR_TYPE_RENDER_MODEL_PROPERTIES_FB = 1000119001,
+    XR_TYPE_RENDER_MODEL_BUFFER_FB = 1000119002,
+    XR_TYPE_RENDER_MODEL_LOAD_INFO_FB = 1000119003,
+    XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB = 1000119004,
+    XR_TYPE_BINDING_MODIFICATIONS_KHR = 1000120000,
+    XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO = 1000121000,
+    XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO = 1000121001,
+    XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO = 1000121002,
+    XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO = 1000122000,
+    XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO = 1000124000,
+    XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO = 1000124001,
+    XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO = 1000124002,
+    XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT = 1000142000,
+    XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT = 1000142001,
+    XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB = 1000160000,
+    XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB = 1000161000,
+    XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB = 1000162000,
+    XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB = 1000163000,
+    XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB = 1000171000,
+    XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB = 1000171001,
+    XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE = 1000196000,
+    XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB = 1000203002,
+    XR_TYPE_GRAPHICS_BINDING_VULKAN2_KHR = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR,
+    XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR,
+    XR_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrStructureType;
+
+typedef enum XrFormFactor {
+    XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY = 1,
+    XR_FORM_FACTOR_HANDHELD_DISPLAY = 2,
+    XR_FORM_FACTOR_MAX_ENUM = 0x7FFFFFFF
+} XrFormFactor;
+
+typedef enum XrViewConfigurationType {
+    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO = 1,
+    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO = 2,
+    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO = 1000037000,
+    XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT = 1000054000,
+    XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrViewConfigurationType;
+
+typedef enum XrEnvironmentBlendMode {
+    XR_ENVIRONMENT_BLEND_MODE_OPAQUE = 1,
+    XR_ENVIRONMENT_BLEND_MODE_ADDITIVE = 2,
+    XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND = 3,
+    XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM = 0x7FFFFFFF
+} XrEnvironmentBlendMode;
+
+typedef enum XrReferenceSpaceType {
+    XR_REFERENCE_SPACE_TYPE_VIEW = 1,
+    XR_REFERENCE_SPACE_TYPE_LOCAL = 2,
+    XR_REFERENCE_SPACE_TYPE_STAGE = 3,
+    XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT = 1000038000,
+    XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO = 1000121000,
+    XR_REFERENCE_SPACE_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrReferenceSpaceType;
+
+typedef enum XrActionType {
+    XR_ACTION_TYPE_BOOLEAN_INPUT = 1,
+    XR_ACTION_TYPE_FLOAT_INPUT = 2,
+    XR_ACTION_TYPE_VECTOR2F_INPUT = 3,
+    XR_ACTION_TYPE_POSE_INPUT = 4,
+    XR_ACTION_TYPE_VIBRATION_OUTPUT = 100,
+    XR_ACTION_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrActionType;
+
+typedef enum XrEyeVisibility {
+    XR_EYE_VISIBILITY_BOTH = 0,
+    XR_EYE_VISIBILITY_LEFT = 1,
+    XR_EYE_VISIBILITY_RIGHT = 2,
+    XR_EYE_VISIBILITY_MAX_ENUM = 0x7FFFFFFF
+} XrEyeVisibility;
+
+typedef enum XrSessionState {
+    XR_SESSION_STATE_UNKNOWN = 0,
+    XR_SESSION_STATE_IDLE = 1,
+    XR_SESSION_STATE_READY = 2,
+    XR_SESSION_STATE_SYNCHRONIZED = 3,
+    XR_SESSION_STATE_VISIBLE = 4,
+    XR_SESSION_STATE_FOCUSED = 5,
+    XR_SESSION_STATE_STOPPING = 6,
+    XR_SESSION_STATE_LOSS_PENDING = 7,
+    XR_SESSION_STATE_EXITING = 8,
+    XR_SESSION_STATE_MAX_ENUM = 0x7FFFFFFF
+} XrSessionState;
+
+typedef enum XrObjectType {
+    XR_OBJECT_TYPE_UNKNOWN = 0,
+    XR_OBJECT_TYPE_INSTANCE = 1,
+    XR_OBJECT_TYPE_SESSION = 2,
+    XR_OBJECT_TYPE_SWAPCHAIN = 3,
+    XR_OBJECT_TYPE_SPACE = 4,
+    XR_OBJECT_TYPE_ACTION_SET = 5,
+    XR_OBJECT_TYPE_ACTION = 6,
+    XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000019000,
+    XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT = 1000039000,
+    XR_OBJECT_TYPE_HAND_TRACKER_EXT = 1000051000,
+    XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT = 1000097000,
+    XR_OBJECT_TYPE_SCENE_MSFT = 1000097001,
+    XR_OBJECT_TYPE_FACIAL_TRACKER_HTC = 1000104000,
+    XR_OBJECT_TYPE_FOVEATION_PROFILE_FB = 1000114000,
+    XR_OBJECT_TYPE_TRIANGLE_MESH_FB = 1000117000,
+    XR_OBJECT_TYPE_PASSTHROUGH_FB = 1000118000,
+    XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB = 1000118002,
+    XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB = 1000118004,
+    XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT = 1000142000,
+    XR_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrObjectType;
+typedef XrFlags64 XrInstanceCreateFlags;
+
+// Flag bits for XrInstanceCreateFlags
+
+typedef XrFlags64 XrSessionCreateFlags;
+
+// Flag bits for XrSessionCreateFlags
+
+typedef XrFlags64 XrSpaceVelocityFlags;
+
+// Flag bits for XrSpaceVelocityFlags
+static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_LINEAR_VALID_BIT = 0x00000001;
+static const XrSpaceVelocityFlags XR_SPACE_VELOCITY_ANGULAR_VALID_BIT = 0x00000002;
+
+typedef XrFlags64 XrSpaceLocationFlags;
+
+// Flag bits for XrSpaceLocationFlags
+static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_VALID_BIT = 0x00000001;
+static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_VALID_BIT = 0x00000002;
+static const XrSpaceLocationFlags XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT = 0x00000004;
+static const XrSpaceLocationFlags XR_SPACE_LOCATION_POSITION_TRACKED_BIT = 0x00000008;
+
+typedef XrFlags64 XrSwapchainCreateFlags;
+
+// Flag bits for XrSwapchainCreateFlags
+static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT = 0x00000001;
+static const XrSwapchainCreateFlags XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT = 0x00000002;
+
+typedef XrFlags64 XrSwapchainUsageFlags;
+
+// Flag bits for XrSwapchainUsageFlags
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT = 0x00000001;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000002;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT = 0x00000004;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT = 0x00000008;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT = 0x00000010;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT = 0x00000020;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT = 0x00000040;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND = 0x00000080;
+static const XrSwapchainUsageFlags XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR = 0x00000080;  // alias of XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND
+
+typedef XrFlags64 XrCompositionLayerFlags;
+
+// Flag bits for XrCompositionLayerFlags
+static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT = 0x00000001;
+static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT = 0x00000002;
+static const XrCompositionLayerFlags XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT = 0x00000004;
+
+typedef XrFlags64 XrViewStateFlags;
+
+// Flag bits for XrViewStateFlags
+static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_VALID_BIT = 0x00000001;
+static const XrViewStateFlags XR_VIEW_STATE_POSITION_VALID_BIT = 0x00000002;
+static const XrViewStateFlags XR_VIEW_STATE_ORIENTATION_TRACKED_BIT = 0x00000004;
+static const XrViewStateFlags XR_VIEW_STATE_POSITION_TRACKED_BIT = 0x00000008;
+
+typedef XrFlags64 XrInputSourceLocalizedNameFlags;
+
+// Flag bits for XrInputSourceLocalizedNameFlags
+static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT = 0x00000001;
+static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT = 0x00000002;
+static const XrInputSourceLocalizedNameFlags XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT = 0x00000004;
+
+typedef void (XRAPI_PTR *PFN_xrVoidFunction)(void);
+typedef struct XrApiLayerProperties {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    char                  layerName[XR_MAX_API_LAYER_NAME_SIZE];
+    XrVersion             specVersion;
+    uint32_t              layerVersion;
+    char                  description[XR_MAX_API_LAYER_DESCRIPTION_SIZE];
+} XrApiLayerProperties;
+
+typedef struct XrExtensionProperties {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    char                  extensionName[XR_MAX_EXTENSION_NAME_SIZE];
+    uint32_t              extensionVersion;
+} XrExtensionProperties;
+
+typedef struct XrApplicationInfo {
+    char         applicationName[XR_MAX_APPLICATION_NAME_SIZE];
+    uint32_t     applicationVersion;
+    char         engineName[XR_MAX_ENGINE_NAME_SIZE];
+    uint32_t     engineVersion;
+    XrVersion    apiVersion;
+} XrApplicationInfo;
+
+typedef struct XrInstanceCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrInstanceCreateFlags       createFlags;
+    XrApplicationInfo           applicationInfo;
+    uint32_t                    enabledApiLayerCount;
+    const char* const*          enabledApiLayerNames;
+    uint32_t                    enabledExtensionCount;
+    const char* const*          enabledExtensionNames;
+} XrInstanceCreateInfo;
+
+typedef struct XrInstanceProperties {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrVersion             runtimeVersion;
+    char                  runtimeName[XR_MAX_RUNTIME_NAME_SIZE];
+} XrInstanceProperties;
+
+typedef struct XrEventDataBuffer {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint8_t                     varying[4000];
+} XrEventDataBuffer;
+
+typedef struct XrSystemGetInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrFormFactor                formFactor;
+} XrSystemGetInfo;
+
+typedef struct XrSystemGraphicsProperties {
+    uint32_t    maxSwapchainImageHeight;
+    uint32_t    maxSwapchainImageWidth;
+    uint32_t    maxLayerCount;
+} XrSystemGraphicsProperties;
+
+typedef struct XrSystemTrackingProperties {
+    XrBool32    orientationTracking;
+    XrBool32    positionTracking;
+} XrSystemTrackingProperties;
+
+typedef struct XrSystemProperties {
+    XrStructureType               type;
+    void* XR_MAY_ALIAS            next;
+    XrSystemId                    systemId;
+    uint32_t                      vendorId;
+    char                          systemName[XR_MAX_SYSTEM_NAME_SIZE];
+    XrSystemGraphicsProperties    graphicsProperties;
+    XrSystemTrackingProperties    trackingProperties;
+} XrSystemProperties;
+
+typedef struct XrSessionCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSessionCreateFlags        createFlags;
+    XrSystemId                  systemId;
+} XrSessionCreateInfo;
+
+typedef struct XrVector3f {
+    float    x;
+    float    y;
+    float    z;
+} XrVector3f;
+
+// XrSpaceVelocity extends XrSpaceLocation
+typedef struct XrSpaceVelocity {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    XrSpaceVelocityFlags    velocityFlags;
+    XrVector3f              linearVelocity;
+    XrVector3f              angularVelocity;
+} XrSpaceVelocity;
+
+typedef struct XrQuaternionf {
+    float    x;
+    float    y;
+    float    z;
+    float    w;
+} XrQuaternionf;
+
+typedef struct XrPosef {
+    XrQuaternionf    orientation;
+    XrVector3f       position;
+} XrPosef;
+
+typedef struct XrReferenceSpaceCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrReferenceSpaceType        referenceSpaceType;
+    XrPosef                     poseInReferenceSpace;
+} XrReferenceSpaceCreateInfo;
+
+typedef struct XrExtent2Df {
+    float    width;
+    float    height;
+} XrExtent2Df;
+
+typedef struct XrActionSpaceCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrAction                    action;
+    XrPath                      subactionPath;
+    XrPosef                     poseInActionSpace;
+} XrActionSpaceCreateInfo;
+
+typedef struct XrSpaceLocation {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    XrSpaceLocationFlags    locationFlags;
+    XrPosef                 pose;
+} XrSpaceLocation;
+
+typedef struct XrViewConfigurationProperties {
+    XrStructureType            type;
+    void* XR_MAY_ALIAS         next;
+    XrViewConfigurationType    viewConfigurationType;
+    XrBool32                   fovMutable;
+} XrViewConfigurationProperties;
+
+typedef struct XrViewConfigurationView {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              recommendedImageRectWidth;
+    uint32_t              maxImageRectWidth;
+    uint32_t              recommendedImageRectHeight;
+    uint32_t              maxImageRectHeight;
+    uint32_t              recommendedSwapchainSampleCount;
+    uint32_t              maxSwapchainSampleCount;
+} XrViewConfigurationView;
+
+typedef struct XrSwapchainCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSwapchainCreateFlags      createFlags;
+    XrSwapchainUsageFlags       usageFlags;
+    int64_t                     format;
+    uint32_t                    sampleCount;
+    uint32_t                    width;
+    uint32_t                    height;
+    uint32_t                    faceCount;
+    uint32_t                    arraySize;
+    uint32_t                    mipCount;
+} XrSwapchainCreateInfo;
+
+typedef struct XR_MAY_ALIAS XrSwapchainImageBaseHeader {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+} XrSwapchainImageBaseHeader;
+
+typedef struct XrSwapchainImageAcquireInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrSwapchainImageAcquireInfo;
+
+typedef struct XrSwapchainImageWaitInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrDuration                  timeout;
+} XrSwapchainImageWaitInfo;
+
+typedef struct XrSwapchainImageReleaseInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrSwapchainImageReleaseInfo;
+
+typedef struct XrSessionBeginInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrViewConfigurationType     primaryViewConfigurationType;
+} XrSessionBeginInfo;
+
+typedef struct XrFrameWaitInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrFrameWaitInfo;
+
+typedef struct XrFrameState {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrTime                predictedDisplayTime;
+    XrDuration            predictedDisplayPeriod;
+    XrBool32              shouldRender;
+} XrFrameState;
+
+typedef struct XrFrameBeginInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrFrameBeginInfo;
+
+typedef struct XR_MAY_ALIAS XrCompositionLayerBaseHeader {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+} XrCompositionLayerBaseHeader;
+
+typedef struct XrFrameEndInfo {
+    XrStructureType                               type;
+    const void* XR_MAY_ALIAS                      next;
+    XrTime                                        displayTime;
+    XrEnvironmentBlendMode                        environmentBlendMode;
+    uint32_t                                      layerCount;
+    const XrCompositionLayerBaseHeader* const*    layers;
+} XrFrameEndInfo;
+
+typedef struct XrViewLocateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrViewConfigurationType     viewConfigurationType;
+    XrTime                      displayTime;
+    XrSpace                     space;
+} XrViewLocateInfo;
+
+typedef struct XrViewState {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrViewStateFlags      viewStateFlags;
+} XrViewState;
+
+typedef struct XrFovf {
+    float    angleLeft;
+    float    angleRight;
+    float    angleUp;
+    float    angleDown;
+} XrFovf;
+
+typedef struct XrView {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrPosef               pose;
+    XrFovf                fov;
+} XrView;
+
+typedef struct XrActionSetCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    char                        actionSetName[XR_MAX_ACTION_SET_NAME_SIZE];
+    char                        localizedActionSetName[XR_MAX_LOCALIZED_ACTION_SET_NAME_SIZE];
+    uint32_t                    priority;
+} XrActionSetCreateInfo;
+
+typedef struct XrActionCreateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    char                        actionName[XR_MAX_ACTION_NAME_SIZE];
+    XrActionType                actionType;
+    uint32_t                    countSubactionPaths;
+    const XrPath*               subactionPaths;
+    char                        localizedActionName[XR_MAX_LOCALIZED_ACTION_NAME_SIZE];
+} XrActionCreateInfo;
+
+typedef struct XrActionSuggestedBinding {
+    XrAction    action;
+    XrPath      binding;
+} XrActionSuggestedBinding;
+
+typedef struct XrInteractionProfileSuggestedBinding {
+    XrStructureType                    type;
+    const void* XR_MAY_ALIAS           next;
+    XrPath                             interactionProfile;
+    uint32_t                           countSuggestedBindings;
+    const XrActionSuggestedBinding*    suggestedBindings;
+} XrInteractionProfileSuggestedBinding;
+
+typedef struct XrSessionActionSetsAttachInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint32_t                    countActionSets;
+    const XrActionSet*          actionSets;
+} XrSessionActionSetsAttachInfo;
+
+typedef struct XrInteractionProfileState {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrPath                interactionProfile;
+} XrInteractionProfileState;
+
+typedef struct XrActionStateGetInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrAction                    action;
+    XrPath                      subactionPath;
+} XrActionStateGetInfo;
+
+typedef struct XrActionStateBoolean {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              currentState;
+    XrBool32              changedSinceLastSync;
+    XrTime                lastChangeTime;
+    XrBool32              isActive;
+} XrActionStateBoolean;
+
+typedef struct XrActionStateFloat {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    float                 currentState;
+    XrBool32              changedSinceLastSync;
+    XrTime                lastChangeTime;
+    XrBool32              isActive;
+} XrActionStateFloat;
+
+typedef struct XrVector2f {
+    float    x;
+    float    y;
+} XrVector2f;
+
+typedef struct XrActionStateVector2f {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrVector2f            currentState;
+    XrBool32              changedSinceLastSync;
+    XrTime                lastChangeTime;
+    XrBool32              isActive;
+} XrActionStateVector2f;
+
+typedef struct XrActionStatePose {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              isActive;
+} XrActionStatePose;
+
+typedef struct XrActiveActionSet {
+    XrActionSet    actionSet;
+    XrPath         subactionPath;
+} XrActiveActionSet;
+
+typedef struct XrActionsSyncInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint32_t                    countActiveActionSets;
+    const XrActiveActionSet*    activeActionSets;
+} XrActionsSyncInfo;
+
+typedef struct XrBoundSourcesForActionEnumerateInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrAction                    action;
+} XrBoundSourcesForActionEnumerateInfo;
+
+typedef struct XrInputSourceLocalizedNameGetInfo {
+    XrStructureType                    type;
+    const void* XR_MAY_ALIAS           next;
+    XrPath                             sourcePath;
+    XrInputSourceLocalizedNameFlags    whichComponents;
+} XrInputSourceLocalizedNameGetInfo;
+
+typedef struct XrHapticActionInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrAction                    action;
+    XrPath                      subactionPath;
+} XrHapticActionInfo;
+
+typedef struct XR_MAY_ALIAS XrHapticBaseHeader {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrHapticBaseHeader;
+
+typedef struct XR_MAY_ALIAS XrBaseInStructure {
+    XrStructureType                    type;
+    const struct XrBaseInStructure*    next;
+} XrBaseInStructure;
+
+typedef struct XR_MAY_ALIAS XrBaseOutStructure {
+    XrStructureType               type;
+    struct XrBaseOutStructure*    next;
+} XrBaseOutStructure;
+
+typedef struct XrOffset2Di {
+    int32_t    x;
+    int32_t    y;
+} XrOffset2Di;
+
+typedef struct XrExtent2Di {
+    int32_t    width;
+    int32_t    height;
+} XrExtent2Di;
+
+typedef struct XrRect2Di {
+    XrOffset2Di    offset;
+    XrExtent2Di    extent;
+} XrRect2Di;
+
+typedef struct XrSwapchainSubImage {
+    XrSwapchain    swapchain;
+    XrRect2Di      imageRect;
+    uint32_t       imageArrayIndex;
+} XrSwapchainSubImage;
+
+typedef struct XrCompositionLayerProjectionView {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrPosef                     pose;
+    XrFovf                      fov;
+    XrSwapchainSubImage         subImage;
+} XrCompositionLayerProjectionView;
+
+typedef struct XrCompositionLayerProjection {
+    XrStructureType                            type;
+    const void* XR_MAY_ALIAS                   next;
+    XrCompositionLayerFlags                    layerFlags;
+    XrSpace                                    space;
+    uint32_t                                   viewCount;
+    const XrCompositionLayerProjectionView*    views;
+} XrCompositionLayerProjection;
+
+typedef struct XrCompositionLayerQuad {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+    XrEyeVisibility             eyeVisibility;
+    XrSwapchainSubImage         subImage;
+    XrPosef                     pose;
+    XrExtent2Df                 size;
+} XrCompositionLayerQuad;
+
+typedef struct XR_MAY_ALIAS XrEventDataBaseHeader {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrEventDataBaseHeader;
+
+typedef struct XrEventDataEventsLost {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint32_t                    lostEventCount;
+} XrEventDataEventsLost;
+
+typedef struct XrEventDataInstanceLossPending {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrTime                      lossTime;
+} XrEventDataInstanceLossPending;
+
+typedef struct XrEventDataSessionStateChanged {
+     XrStructureType            type;
+    const void* XR_MAY_ALIAS    next;
+    XrSession                   session;
+    XrSessionState              state;
+    XrTime                      time;
+} XrEventDataSessionStateChanged;
+
+typedef struct XrEventDataReferenceSpaceChangePending {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSession                   session;
+    XrReferenceSpaceType        referenceSpaceType;
+    XrTime                      changeTime;
+    XrBool32                    poseValid;
+    XrPosef                     poseInPreviousSpace;
+} XrEventDataReferenceSpaceChangePending;
+
+typedef struct XrEventDataInteractionProfileChanged {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSession                   session;
+} XrEventDataInteractionProfileChanged;
+
+typedef struct XrHapticVibration {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrDuration                  duration;
+    float                       frequency;
+    float                       amplitude;
+} XrHapticVibration;
+
+typedef struct XrOffset2Df {
+    float    x;
+    float    y;
+} XrOffset2Df;
+
+typedef struct XrRect2Df {
+    XrOffset2Df    offset;
+    XrExtent2Df    extent;
+} XrRect2Df;
+
+typedef struct XrVector4f {
+    float    x;
+    float    y;
+    float    z;
+    float    w;
+} XrVector4f;
+
+typedef struct XrColor4f {
+    float    r;
+    float    g;
+    float    b;
+    float    a;
+} XrColor4f;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateApiLayerProperties)(uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrApiLayerProperties* properties);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateInstanceExtensionProperties)(const char* layerName, uint32_t propertyCapacityInput, uint32_t* propertyCountOutput, XrExtensionProperties* properties);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateInstance)(const XrInstanceCreateInfo* createInfo, XrInstance* instance);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyInstance)(XrInstance instance);
+typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProperties)(XrInstance instance, XrInstanceProperties* instanceProperties);
+typedef XrResult (XRAPI_PTR *PFN_xrPollEvent)(XrInstance instance, XrEventDataBuffer* eventData);
+typedef XrResult (XRAPI_PTR *PFN_xrResultToString)(XrInstance instance, XrResult value, char buffer[XR_MAX_RESULT_STRING_SIZE]);
+typedef XrResult (XRAPI_PTR *PFN_xrStructureTypeToString)(XrInstance instance, XrStructureType value, char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSystem)(XrInstance instance, const XrSystemGetInfo* getInfo, XrSystemId* systemId);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSystemProperties)(XrInstance instance, XrSystemId systemId, XrSystemProperties* properties);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateEnvironmentBlendModes)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t environmentBlendModeCapacityInput, uint32_t* environmentBlendModeCountOutput, XrEnvironmentBlendMode* environmentBlendModes);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSession)(XrInstance instance, const XrSessionCreateInfo* createInfo, XrSession* session);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySession)(XrSession session);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReferenceSpaces)(XrSession session, uint32_t spaceCapacityInput, uint32_t* spaceCountOutput, XrReferenceSpaceType* spaces);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateReferenceSpace)(XrSession session, const XrReferenceSpaceCreateInfo* createInfo, XrSpace* space);
+typedef XrResult (XRAPI_PTR *PFN_xrGetReferenceSpaceBoundsRect)(XrSession session, XrReferenceSpaceType referenceSpaceType, XrExtent2Df* bounds);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSpace)(XrSession session, const XrActionSpaceCreateInfo* createInfo, XrSpace* space);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateSpace)(XrSpace space, XrSpace baseSpace, XrTime   time, XrSpaceLocation* location);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySpace)(XrSpace space);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurations)(XrInstance instance, XrSystemId systemId, uint32_t viewConfigurationTypeCapacityInput, uint32_t* viewConfigurationTypeCountOutput, XrViewConfigurationType* viewConfigurationTypes);
+typedef XrResult (XRAPI_PTR *PFN_xrGetViewConfigurationProperties)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, XrViewConfigurationProperties* configurationProperties);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViewConfigurationViews)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrViewConfigurationView* views);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainFormats)(XrSession session, uint32_t formatCapacityInput, uint32_t* formatCountOutput, int64_t* formats);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSwapchain)(XrSession session, const XrSwapchainCreateInfo* createInfo, XrSwapchain* swapchain);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySwapchain)(XrSwapchain swapchain);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSwapchainImages)(XrSwapchain swapchain, uint32_t imageCapacityInput, uint32_t* imageCountOutput, XrSwapchainImageBaseHeader* images);
+typedef XrResult (XRAPI_PTR *PFN_xrAcquireSwapchainImage)(XrSwapchain         swapchain, const XrSwapchainImageAcquireInfo* acquireInfo, uint32_t* index);
+typedef XrResult (XRAPI_PTR *PFN_xrWaitSwapchainImage)(XrSwapchain swapchain, const XrSwapchainImageWaitInfo* waitInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrReleaseSwapchainImage)(XrSwapchain         swapchain, const XrSwapchainImageReleaseInfo* releaseInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrBeginSession)(XrSession session, const XrSessionBeginInfo* beginInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrEndSession)(XrSession session);
+typedef XrResult (XRAPI_PTR *PFN_xrRequestExitSession)(XrSession session);
+typedef XrResult (XRAPI_PTR *PFN_xrWaitFrame)(XrSession session, const XrFrameWaitInfo* frameWaitInfo, XrFrameState* frameState);
+typedef XrResult (XRAPI_PTR *PFN_xrBeginFrame)(XrSession session, const XrFrameBeginInfo* frameBeginInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrEndFrame)(XrSession session, const XrFrameEndInfo* frameEndInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateViews)(XrSession session, const XrViewLocateInfo* viewLocateInfo, XrViewState* viewState, uint32_t viewCapacityInput, uint32_t* viewCountOutput, XrView* views);
+typedef XrResult (XRAPI_PTR *PFN_xrStringToPath)(XrInstance instance, const char* pathString, XrPath* path);
+typedef XrResult (XRAPI_PTR *PFN_xrPathToString)(XrInstance instance, XrPath path, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateActionSet)(XrInstance instance, const XrActionSetCreateInfo* createInfo, XrActionSet* actionSet);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyActionSet)(XrActionSet actionSet);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateAction)(XrActionSet actionSet, const XrActionCreateInfo* createInfo, XrAction* action);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyAction)(XrAction action);
+typedef XrResult (XRAPI_PTR *PFN_xrSuggestInteractionProfileBindings)(XrInstance instance, const XrInteractionProfileSuggestedBinding* suggestedBindings);
+typedef XrResult (XRAPI_PTR *PFN_xrAttachSessionActionSets)(XrSession session, const XrSessionActionSetsAttachInfo* attachInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetCurrentInteractionProfile)(XrSession session, XrPath topLevelUserPath, XrInteractionProfileState* interactionProfile);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateBoolean)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateBoolean* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateFloat)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateFloat* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector2f)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStateVector2f* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStatePose)(XrSession session, const XrActionStateGetInfo* getInfo, XrActionStatePose* state);
+typedef XrResult (XRAPI_PTR *PFN_xrSyncActions)(XrSession session, const XrActionsSyncInfo* syncInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateBoundSourcesForAction)(XrSession session, const XrBoundSourcesForActionEnumerateInfo* enumerateInfo, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources);
+typedef XrResult (XRAPI_PTR *PFN_xrGetInputSourceLocalizedName)(XrSession session, const XrInputSourceLocalizedNameGetInfo* getInfo, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
+typedef XrResult (XRAPI_PTR *PFN_xrApplyHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo, const XrHapticBaseHeader* hapticFeedback);
+typedef XrResult (XRAPI_PTR *PFN_xrStopHapticFeedback)(XrSession session, const XrHapticActionInfo* hapticActionInfo);
+
+#ifndef XR_NO_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProcAddr(
+    XrInstance                                  instance,
+    const char*                                 name,
+    PFN_xrVoidFunction*                         function);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateApiLayerProperties(
+    uint32_t                                    propertyCapacityInput,
+    uint32_t*                                   propertyCountOutput,
+    XrApiLayerProperties*                       properties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateInstanceExtensionProperties(
+    const char*                                 layerName,
+    uint32_t                                    propertyCapacityInput,
+    uint32_t*                                   propertyCountOutput,
+    XrExtensionProperties*                      properties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateInstance(
+    const XrInstanceCreateInfo*                 createInfo,
+    XrInstance*                                 instance);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyInstance(
+    XrInstance                                  instance);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetInstanceProperties(
+    XrInstance                                  instance,
+    XrInstanceProperties*                       instanceProperties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPollEvent(
+    XrInstance                                  instance,
+    XrEventDataBuffer*                          eventData);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrResultToString(
+    XrInstance                                  instance,
+    XrResult                                    value,
+    char                                        buffer[XR_MAX_RESULT_STRING_SIZE]);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrStructureTypeToString(
+    XrInstance                                  instance,
+    XrStructureType                             value,
+    char                                        buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSystem(
+    XrInstance                                  instance,
+    const XrSystemGetInfo*                      getInfo,
+    XrSystemId*                                 systemId);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSystemProperties(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrSystemProperties*                         properties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateEnvironmentBlendModes(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrViewConfigurationType                     viewConfigurationType,
+    uint32_t                                    environmentBlendModeCapacityInput,
+    uint32_t*                                   environmentBlendModeCountOutput,
+    XrEnvironmentBlendMode*                     environmentBlendModes);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSession(
+    XrInstance                                  instance,
+    const XrSessionCreateInfo*                  createInfo,
+    XrSession*                                  session);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySession(
+    XrSession                                   session);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReferenceSpaces(
+    XrSession                                   session,
+    uint32_t                                    spaceCapacityInput,
+    uint32_t*                                   spaceCountOutput,
+    XrReferenceSpaceType*                       spaces);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateReferenceSpace(
+    XrSession                                   session,
+    const XrReferenceSpaceCreateInfo*           createInfo,
+    XrSpace*                                    space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetReferenceSpaceBoundsRect(
+    XrSession                                   session,
+    XrReferenceSpaceType                        referenceSpaceType,
+    XrExtent2Df*                                bounds);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSpace(
+    XrSession                                   session,
+    const XrActionSpaceCreateInfo*              createInfo,
+    XrSpace*                                    space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
+    XrSpace                                     space,
+    XrSpace                                     baseSpace,
+    XrTime                                      time,
+    XrSpaceLocation*                            location);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpace(
+    XrSpace                                     space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurations(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    uint32_t                                    viewConfigurationTypeCapacityInput,
+    uint32_t*                                   viewConfigurationTypeCountOutput,
+    XrViewConfigurationType*                    viewConfigurationTypes);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetViewConfigurationProperties(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrViewConfigurationType                     viewConfigurationType,
+    XrViewConfigurationProperties*              configurationProperties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViewConfigurationViews(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrViewConfigurationType                     viewConfigurationType,
+    uint32_t                                    viewCapacityInput,
+    uint32_t*                                   viewCountOutput,
+    XrViewConfigurationView*                    views);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainFormats(
+    XrSession                                   session,
+    uint32_t                                    formatCapacityInput,
+    uint32_t*                                   formatCountOutput,
+    int64_t*                                    formats);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchain(
+    XrSession                                   session,
+    const XrSwapchainCreateInfo*                createInfo,
+    XrSwapchain*                                swapchain);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySwapchain(
+    XrSwapchain                                 swapchain);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSwapchainImages(
+    XrSwapchain                                 swapchain,
+    uint32_t                                    imageCapacityInput,
+    uint32_t*                                   imageCountOutput,
+    XrSwapchainImageBaseHeader*                 images);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrAcquireSwapchainImage(
+    XrSwapchain                                 swapchain,
+    const XrSwapchainImageAcquireInfo*          acquireInfo,
+    uint32_t*                                   index);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrWaitSwapchainImage(
+    XrSwapchain                                 swapchain,
+    const XrSwapchainImageWaitInfo*             waitInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrReleaseSwapchainImage(
+    XrSwapchain                                 swapchain,
+    const XrSwapchainImageReleaseInfo*          releaseInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrBeginSession(
+    XrSession                                   session,
+    const XrSessionBeginInfo*                   beginInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEndSession(
+    XrSession                                   session);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrRequestExitSession(
+    XrSession                                   session);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrWaitFrame(
+    XrSession                                   session,
+    const XrFrameWaitInfo*                      frameWaitInfo,
+    XrFrameState*                               frameState);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrBeginFrame(
+    XrSession                                   session,
+    const XrFrameBeginInfo*                     frameBeginInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEndFrame(
+    XrSession                                   session,
+    const XrFrameEndInfo*                       frameEndInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateViews(
+    XrSession                                   session,
+    const XrViewLocateInfo*                     viewLocateInfo,
+    XrViewState*                                viewState,
+    uint32_t                                    viewCapacityInput,
+    uint32_t*                                   viewCountOutput,
+    XrView*                                     views);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrStringToPath(
+    XrInstance                                  instance,
+    const char*                                 pathString,
+    XrPath*                                     path);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPathToString(
+    XrInstance                                  instance,
+    XrPath                                      path,
+    uint32_t                                    bufferCapacityInput,
+    uint32_t*                                   bufferCountOutput,
+    char*                                       buffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateActionSet(
+    XrInstance                                  instance,
+    const XrActionSetCreateInfo*                createInfo,
+    XrActionSet*                                actionSet);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyActionSet(
+    XrActionSet                                 actionSet);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateAction(
+    XrActionSet                                 actionSet,
+    const XrActionCreateInfo*                   createInfo,
+    XrAction*                                   action);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyAction(
+    XrAction                                    action);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSuggestInteractionProfileBindings(
+    XrInstance                                  instance,
+    const XrInteractionProfileSuggestedBinding* suggestedBindings);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrAttachSessionActionSets(
+    XrSession                                   session,
+    const XrSessionActionSetsAttachInfo*        attachInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
+    XrSession                                   session,
+    XrPath                                      topLevelUserPath,
+    XrInteractionProfileState*                  interactionProfile);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
+    XrSession                                   session,
+    const XrActionStateGetInfo*                 getInfo,
+    XrActionStateBoolean*                       state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateFloat(
+    XrSession                                   session,
+    const XrActionStateGetInfo*                 getInfo,
+    XrActionStateFloat*                         state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
+    XrSession                                   session,
+    const XrActionStateGetInfo*                 getInfo,
+    XrActionStateVector2f*                      state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
+    XrSession                                   session,
+    const XrActionStateGetInfo*                 getInfo,
+    XrActionStatePose*                          state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSyncActions(
+    XrSession                                   session,
+    const XrActionsSyncInfo*                    syncInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateBoundSourcesForAction(
+    XrSession                                   session,
+    const XrBoundSourcesForActionEnumerateInfo* enumerateInfo,
+    uint32_t                                    sourceCapacityInput,
+    uint32_t*                                   sourceCountOutput,
+    XrPath*                                     sources);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
+    XrSession                                   session,
+    const XrInputSourceLocalizedNameGetInfo*    getInfo,
+    uint32_t                                    bufferCapacityInput,
+    uint32_t*                                   bufferCountOutput,
+    char*                                       buffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
+    XrSession                                   session,
+    const XrHapticActionInfo*                   hapticActionInfo,
+    const XrHapticBaseHeader*                   hapticFeedback);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
+    XrSession                                   session,
+    const XrHapticActionInfo*                   hapticActionInfo);
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_KHR_composition_layer_cube 1
+#define XR_KHR_composition_layer_cube_SPEC_VERSION 8
+#define XR_KHR_COMPOSITION_LAYER_CUBE_EXTENSION_NAME "XR_KHR_composition_layer_cube"
+typedef struct XrCompositionLayerCubeKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+    XrEyeVisibility             eyeVisibility;
+    XrSwapchain                 swapchain;
+    uint32_t                    imageArrayIndex;
+    XrQuaternionf               orientation;
+} XrCompositionLayerCubeKHR;
+
+
+
+#define XR_KHR_composition_layer_depth 1
+#define XR_KHR_composition_layer_depth_SPEC_VERSION 5
+#define XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME "XR_KHR_composition_layer_depth"
+// XrCompositionLayerDepthInfoKHR extends XrCompositionLayerProjectionView
+typedef struct XrCompositionLayerDepthInfoKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSwapchainSubImage         subImage;
+    float                       minDepth;
+    float                       maxDepth;
+    float                       nearZ;
+    float                       farZ;
+} XrCompositionLayerDepthInfoKHR;
+
+
+
+#define XR_KHR_composition_layer_cylinder 1
+#define XR_KHR_composition_layer_cylinder_SPEC_VERSION 4
+#define XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME "XR_KHR_composition_layer_cylinder"
+typedef struct XrCompositionLayerCylinderKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+    XrEyeVisibility             eyeVisibility;
+    XrSwapchainSubImage         subImage;
+    XrPosef                     pose;
+    float                       radius;
+    float                       centralAngle;
+    float                       aspectRatio;
+} XrCompositionLayerCylinderKHR;
+
+
+
+#define XR_KHR_composition_layer_equirect 1
+#define XR_KHR_composition_layer_equirect_SPEC_VERSION 3
+#define XR_KHR_COMPOSITION_LAYER_EQUIRECT_EXTENSION_NAME "XR_KHR_composition_layer_equirect"
+typedef struct XrCompositionLayerEquirectKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+    XrEyeVisibility             eyeVisibility;
+    XrSwapchainSubImage         subImage;
+    XrPosef                     pose;
+    float                       radius;
+    XrVector2f                  scale;
+    XrVector2f                  bias;
+} XrCompositionLayerEquirectKHR;
+
+
+
+#define XR_KHR_visibility_mask 1
+#define XR_KHR_visibility_mask_SPEC_VERSION 2
+#define XR_KHR_VISIBILITY_MASK_EXTENSION_NAME "XR_KHR_visibility_mask"
+
+typedef enum XrVisibilityMaskTypeKHR {
+    XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR = 1,
+    XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR = 2,
+    XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR = 3,
+    XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
+} XrVisibilityMaskTypeKHR;
+typedef struct XrVisibilityMaskKHR {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              vertexCapacityInput;
+    uint32_t              vertexCountOutput;
+    XrVector2f*           vertices;
+    uint32_t              indexCapacityInput;
+    uint32_t              indexCountOutput;
+    uint32_t*             indices;
+} XrVisibilityMaskKHR;
+
+typedef struct XrEventDataVisibilityMaskChangedKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSession                   session;
+    XrViewConfigurationType     viewConfigurationType;
+    uint32_t                    viewIndex;
+} XrEventDataVisibilityMaskChangedKHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetVisibilityMaskKHR)(XrSession session, XrViewConfigurationType viewConfigurationType, uint32_t viewIndex, XrVisibilityMaskTypeKHR visibilityMaskType, XrVisibilityMaskKHR* visibilityMask);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR(
+    XrSession                                   session,
+    XrViewConfigurationType                     viewConfigurationType,
+    uint32_t                                    viewIndex,
+    XrVisibilityMaskTypeKHR                     visibilityMaskType,
+    XrVisibilityMaskKHR*                        visibilityMask);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_KHR_composition_layer_color_scale_bias 1
+#define XR_KHR_composition_layer_color_scale_bias_SPEC_VERSION 5
+#define XR_KHR_COMPOSITION_LAYER_COLOR_SCALE_BIAS_EXTENSION_NAME "XR_KHR_composition_layer_color_scale_bias"
+// XrCompositionLayerColorScaleBiasKHR extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerColorScaleBiasKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrColor4f                   colorScale;
+    XrColor4f                   colorBias;
+} XrCompositionLayerColorScaleBiasKHR;
+
+
+
+#define XR_KHR_loader_init 1
+#define XR_KHR_loader_init_SPEC_VERSION   1
+#define XR_KHR_LOADER_INIT_EXTENSION_NAME "XR_KHR_loader_init"
+typedef struct XR_MAY_ALIAS XrLoaderInitInfoBaseHeaderKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrLoaderInitInfoBaseHeaderKHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrInitializeLoaderKHR)(const XrLoaderInitInfoBaseHeaderKHR* loaderInitInfo);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrInitializeLoaderKHR(
+    const XrLoaderInitInfoBaseHeaderKHR*        loaderInitInfo);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_KHR_composition_layer_equirect2 1
+#define XR_KHR_composition_layer_equirect2_SPEC_VERSION 1
+#define XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME "XR_KHR_composition_layer_equirect2"
+typedef struct XrCompositionLayerEquirect2KHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     layerFlags;
+    XrSpace                     space;
+    XrEyeVisibility             eyeVisibility;
+    XrSwapchainSubImage         subImage;
+    XrPosef                     pose;
+    float                       radius;
+    float                       centralHorizontalAngle;
+    float                       upperVerticalAngle;
+    float                       lowerVerticalAngle;
+} XrCompositionLayerEquirect2KHR;
+
+
+
+#define XR_KHR_binding_modification 1
+#define XR_KHR_binding_modification_SPEC_VERSION 1
+#define XR_KHR_BINDING_MODIFICATION_EXTENSION_NAME "XR_KHR_binding_modification"
+typedef struct XR_MAY_ALIAS XrBindingModificationBaseHeaderKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrBindingModificationBaseHeaderKHR;
+
+// XrBindingModificationsKHR extends XrInteractionProfileSuggestedBinding
+typedef struct XrBindingModificationsKHR {
+    XrStructureType                                     type;
+    const void* XR_MAY_ALIAS                            next;
+    uint32_t                                            bindingModificationCount;
+    const XrBindingModificationBaseHeaderKHR* const*    bindingModifications;
+} XrBindingModificationsKHR;
+
+
+
+#define XR_KHR_swapchain_usage_input_attachment_bit 1
+#define XR_KHR_swapchain_usage_input_attachment_bit_SPEC_VERSION 3
+#define XR_KHR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_KHR_swapchain_usage_input_attachment_bit"
+
+
+#define XR_EXT_performance_settings 1
+#define XR_EXT_performance_settings_SPEC_VERSION 3
+#define XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME "XR_EXT_performance_settings"
+
+typedef enum XrPerfSettingsDomainEXT {
+    XR_PERF_SETTINGS_DOMAIN_CPU_EXT = 1,
+    XR_PERF_SETTINGS_DOMAIN_GPU_EXT = 2,
+    XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPerfSettingsDomainEXT;
+
+typedef enum XrPerfSettingsSubDomainEXT {
+    XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT = 1,
+    XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT = 2,
+    XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT = 3,
+    XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPerfSettingsSubDomainEXT;
+
+typedef enum XrPerfSettingsLevelEXT {
+    XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT = 0,
+    XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT = 25,
+    XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT = 50,
+    XR_PERF_SETTINGS_LEVEL_BOOST_EXT = 75,
+    XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPerfSettingsLevelEXT;
+
+typedef enum XrPerfSettingsNotificationLevelEXT {
+    XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT = 0,
+    XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT = 25,
+    XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT = 75,
+    XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrPerfSettingsNotificationLevelEXT;
+typedef struct XrEventDataPerfSettingsEXT {
+    XrStructureType                       type;
+    const void* XR_MAY_ALIAS              next;
+    XrPerfSettingsDomainEXT               domain;
+    XrPerfSettingsSubDomainEXT            subDomain;
+    XrPerfSettingsNotificationLevelEXT    fromLevel;
+    XrPerfSettingsNotificationLevelEXT    toLevel;
+} XrEventDataPerfSettingsEXT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrPerfSettingsSetPerformanceLevelEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsLevelEXT level);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT(
+    XrSession                                   session,
+    XrPerfSettingsDomainEXT                     domain,
+    XrPerfSettingsLevelEXT                      level);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_EXT_thermal_query 1
+#define XR_EXT_thermal_query_SPEC_VERSION 2
+#define XR_EXT_THERMAL_QUERY_EXTENSION_NAME "XR_EXT_thermal_query"
+typedef XrResult (XRAPI_PTR *PFN_xrThermalGetTemperatureTrendEXT)(XrSession session, XrPerfSettingsDomainEXT domain, XrPerfSettingsNotificationLevelEXT* notificationLevel, float* tempHeadroom, float* tempSlope);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT(
+    XrSession                                   session,
+    XrPerfSettingsDomainEXT                     domain,
+    XrPerfSettingsNotificationLevelEXT*         notificationLevel,
+    float*                                      tempHeadroom,
+    float*                                      tempSlope);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_EXT_debug_utils 1
+XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT)
+#define XR_EXT_debug_utils_SPEC_VERSION   4
+#define XR_EXT_DEBUG_UTILS_EXTENSION_NAME "XR_EXT_debug_utils"
+typedef XrFlags64 XrDebugUtilsMessageSeverityFlagsEXT;
+
+// Flag bits for XrDebugUtilsMessageSeverityFlagsEXT
+static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001;
+static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010;
+static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100;
+static const XrDebugUtilsMessageSeverityFlagsEXT XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000;
+
+typedef XrFlags64 XrDebugUtilsMessageTypeFlagsEXT;
+
+// Flag bits for XrDebugUtilsMessageTypeFlagsEXT
+static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001;
+static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002;
+static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004;
+static const XrDebugUtilsMessageTypeFlagsEXT XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT = 0x00000008;
+
+typedef struct XrDebugUtilsObjectNameInfoEXT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrObjectType                objectType;
+    uint64_t                    objectHandle;
+    const char*                 objectName;
+} XrDebugUtilsObjectNameInfoEXT;
+
+typedef struct XrDebugUtilsLabelEXT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    const char*                 labelName;
+} XrDebugUtilsLabelEXT;
+
+typedef struct XrDebugUtilsMessengerCallbackDataEXT {
+    XrStructureType                   type;
+    const void* XR_MAY_ALIAS          next;
+    const char*                       messageId;
+    const char*                       functionName;
+    const char*                       message;
+    uint32_t                          objectCount;
+    XrDebugUtilsObjectNameInfoEXT*    objects;
+    uint32_t                          sessionLabelCount;
+    XrDebugUtilsLabelEXT*             sessionLabels;
+} XrDebugUtilsMessengerCallbackDataEXT;
+
+typedef XrBool32 (XRAPI_PTR *PFN_xrDebugUtilsMessengerCallbackEXT)(
+            XrDebugUtilsMessageSeverityFlagsEXT              messageSeverity,
+            XrDebugUtilsMessageTypeFlagsEXT                  messageTypes,
+            const XrDebugUtilsMessengerCallbackDataEXT*      callbackData,
+            void*                                            userData);
+        
+
+// XrDebugUtilsMessengerCreateInfoEXT extends XrInstanceCreateInfo
+typedef struct XrDebugUtilsMessengerCreateInfoEXT {
+    XrStructureType                         type;
+    const void* XR_MAY_ALIAS                next;
+    XrDebugUtilsMessageSeverityFlagsEXT     messageSeverities;
+    XrDebugUtilsMessageTypeFlagsEXT         messageTypes;
+    PFN_xrDebugUtilsMessengerCallbackEXT    userCallback;
+    void* XR_MAY_ALIAS                      userData;
+} XrDebugUtilsMessengerCreateInfoEXT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrSetDebugUtilsObjectNameEXT)(XrInstance instance, const XrDebugUtilsObjectNameInfoEXT* nameInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateDebugUtilsMessengerEXT)(XrInstance instance, const XrDebugUtilsMessengerCreateInfoEXT* createInfo, XrDebugUtilsMessengerEXT* messenger);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyDebugUtilsMessengerEXT)(XrDebugUtilsMessengerEXT messenger);
+typedef XrResult                                    (XRAPI_PTR *PFN_xrSubmitDebugUtilsMessageEXT)(XrInstance                                  instance, XrDebugUtilsMessageSeverityFlagsEXT         messageSeverity, XrDebugUtilsMessageTypeFlagsEXT             messageTypes, const XrDebugUtilsMessengerCallbackDataEXT* callbackData);
+typedef XrResult (XRAPI_PTR *PFN_xrSessionBeginDebugUtilsLabelRegionEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrSessionEndDebugUtilsLabelRegionEXT)(XrSession session);
+typedef XrResult (XRAPI_PTR *PFN_xrSessionInsertDebugUtilsLabelEXT)(XrSession session, const XrDebugUtilsLabelEXT* labelInfo);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSetDebugUtilsObjectNameEXT(
+    XrInstance                                  instance,
+    const XrDebugUtilsObjectNameInfoEXT*        nameInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateDebugUtilsMessengerEXT(
+    XrInstance                                  instance,
+    const XrDebugUtilsMessengerCreateInfoEXT*   createInfo,
+    XrDebugUtilsMessengerEXT*                   messenger);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyDebugUtilsMessengerEXT(
+    XrDebugUtilsMessengerEXT                    messenger);
+
+XRAPI_ATTR XrResult                                    XRAPI_CALL xrSubmitDebugUtilsMessageEXT(
+    XrInstance                                  instance,
+    XrDebugUtilsMessageSeverityFlagsEXT         messageSeverity,
+    XrDebugUtilsMessageTypeFlagsEXT             messageTypes,
+    const XrDebugUtilsMessengerCallbackDataEXT* callbackData);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSessionBeginDebugUtilsLabelRegionEXT(
+    XrSession                                   session,
+    const XrDebugUtilsLabelEXT*                 labelInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSessionEndDebugUtilsLabelRegionEXT(
+    XrSession                                   session);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSessionInsertDebugUtilsLabelEXT(
+    XrSession                                   session,
+    const XrDebugUtilsLabelEXT*                 labelInfo);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_EXT_eye_gaze_interaction 1
+#define XR_EXT_eye_gaze_interaction_SPEC_VERSION 1
+#define XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME "XR_EXT_eye_gaze_interaction"
+// XrSystemEyeGazeInteractionPropertiesEXT extends XrSystemProperties
+typedef struct XrSystemEyeGazeInteractionPropertiesEXT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsEyeGazeInteraction;
+} XrSystemEyeGazeInteractionPropertiesEXT;
+
+// XrEyeGazeSampleTimeEXT extends XrSpaceLocation
+typedef struct XrEyeGazeSampleTimeEXT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrTime                time;
+} XrEyeGazeSampleTimeEXT;
+
+
+
+#define XR_EXTX_overlay 1
+#define XR_EXTX_overlay_SPEC_VERSION      5
+#define XR_EXTX_OVERLAY_EXTENSION_NAME    "XR_EXTX_overlay"
+typedef XrFlags64 XrOverlaySessionCreateFlagsEXTX;
+
+// Flag bits for XrOverlaySessionCreateFlagsEXTX
+
+typedef XrFlags64 XrOverlayMainSessionFlagsEXTX;
+
+// Flag bits for XrOverlayMainSessionFlagsEXTX
+static const XrOverlayMainSessionFlagsEXTX XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX = 0x00000001;
+
+// XrSessionCreateInfoOverlayEXTX extends XrSessionCreateInfo
+typedef struct XrSessionCreateInfoOverlayEXTX {
+    XrStructureType                    type;
+    const void* XR_MAY_ALIAS           next;
+    XrOverlaySessionCreateFlagsEXTX    createFlags;
+    uint32_t                           sessionLayersPlacement;
+} XrSessionCreateInfoOverlayEXTX;
+
+typedef struct XrEventDataMainSessionVisibilityChangedEXTX {
+    XrStructureType                  type;
+    const void* XR_MAY_ALIAS         next;
+    XrBool32                         visible;
+    XrOverlayMainSessionFlagsEXTX    flags;
+} XrEventDataMainSessionVisibilityChangedEXTX;
+
+
+
+#define XR_VARJO_quad_views 1
+#define XR_VARJO_quad_views_SPEC_VERSION  1
+#define XR_VARJO_QUAD_VIEWS_EXTENSION_NAME "XR_VARJO_quad_views"
+
+
+#define XR_MSFT_unbounded_reference_space 1
+#define XR_MSFT_unbounded_reference_space_SPEC_VERSION 1
+#define XR_MSFT_UNBOUNDED_REFERENCE_SPACE_EXTENSION_NAME "XR_MSFT_unbounded_reference_space"
+
+
+#define XR_MSFT_spatial_anchor 1
+XR_DEFINE_HANDLE(XrSpatialAnchorMSFT)
+#define XR_MSFT_spatial_anchor_SPEC_VERSION 2
+#define XR_MSFT_SPATIAL_ANCHOR_EXTENSION_NAME "XR_MSFT_spatial_anchor"
+typedef struct XrSpatialAnchorCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSpace                     space;
+    XrPosef                     pose;
+    XrTime                      time;
+} XrSpatialAnchorCreateInfoMSFT;
+
+typedef struct XrSpatialAnchorSpaceCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSpatialAnchorMSFT         anchor;
+    XrPosef                     poseInAnchorSpace;
+} XrSpatialAnchorSpaceCreateInfoMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorMSFT)(XrSession session, const XrSpatialAnchorCreateInfoMSFT* createInfo, XrSpatialAnchorMSFT* anchor);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorSpaceMSFT)(XrSession session, const XrSpatialAnchorSpaceCreateInfoMSFT* createInfo, XrSpace* space);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorMSFT)(XrSpatialAnchorMSFT anchor);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorMSFT(
+    XrSession                                   session,
+    const XrSpatialAnchorCreateInfoMSFT*        createInfo,
+    XrSpatialAnchorMSFT*                        anchor);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorSpaceMSFT(
+    XrSession                                   session,
+    const XrSpatialAnchorSpaceCreateInfoMSFT*   createInfo,
+    XrSpace*                                    space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorMSFT(
+    XrSpatialAnchorMSFT                         anchor);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_composition_layer_image_layout 1
+#define XR_FB_composition_layer_image_layout_SPEC_VERSION 1
+#define XR_FB_COMPOSITION_LAYER_IMAGE_LAYOUT_EXTENSION_NAME "XR_FB_composition_layer_image_layout"
+typedef XrFlags64 XrCompositionLayerImageLayoutFlagsFB;
+
+// Flag bits for XrCompositionLayerImageLayoutFlagsFB
+static const XrCompositionLayerImageLayoutFlagsFB XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB = 0x00000001;
+
+// XrCompositionLayerImageLayoutFB extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerImageLayoutFB {
+    XrStructureType                         type;
+    void* XR_MAY_ALIAS                      next;
+    XrCompositionLayerImageLayoutFlagsFB    flags;
+} XrCompositionLayerImageLayoutFB;
+
+
+
+#define XR_FB_composition_layer_alpha_blend 1
+#define XR_FB_composition_layer_alpha_blend_SPEC_VERSION 2
+#define XR_FB_COMPOSITION_LAYER_ALPHA_BLEND_EXTENSION_NAME "XR_FB_composition_layer_alpha_blend"
+
+typedef enum XrBlendFactorFB {
+    XR_BLEND_FACTOR_ZERO_FB = 0,
+    XR_BLEND_FACTOR_ONE_FB = 1,
+    XR_BLEND_FACTOR_SRC_ALPHA_FB = 2,
+    XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB = 3,
+    XR_BLEND_FACTOR_DST_ALPHA_FB = 4,
+    XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB = 5,
+    XR_BLEND_FACTOR_MAX_ENUM_FB = 0x7FFFFFFF
+} XrBlendFactorFB;
+// XrCompositionLayerAlphaBlendFB extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerAlphaBlendFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBlendFactorFB       srcFactorColor;
+    XrBlendFactorFB       dstFactorColor;
+    XrBlendFactorFB       srcFactorAlpha;
+    XrBlendFactorFB       dstFactorAlpha;
+} XrCompositionLayerAlphaBlendFB;
+
+
+
+#define XR_MND_headless 1
+#define XR_MND_headless_SPEC_VERSION      2
+#define XR_MND_HEADLESS_EXTENSION_NAME    "XR_MND_headless"
+
+
+#define XR_OCULUS_android_session_state_enable 1
+#define XR_OCULUS_android_session_state_enable_SPEC_VERSION 1
+#define XR_OCULUS_ANDROID_SESSION_STATE_ENABLE_EXTENSION_NAME "XR_OCULUS_android_session_state_enable"
+
+
+#define XR_EXT_view_configuration_depth_range 1
+#define XR_EXT_view_configuration_depth_range_SPEC_VERSION 1
+#define XR_EXT_VIEW_CONFIGURATION_DEPTH_RANGE_EXTENSION_NAME "XR_EXT_view_configuration_depth_range"
+// XrViewConfigurationDepthRangeEXT extends XrViewConfigurationView
+typedef struct XrViewConfigurationDepthRangeEXT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    float                 recommendedNearZ;
+    float                 minNearZ;
+    float                 recommendedFarZ;
+    float                 maxFarZ;
+} XrViewConfigurationDepthRangeEXT;
+
+
+
+#define XR_EXT_conformance_automation 1
+#define XR_EXT_conformance_automation_SPEC_VERSION 3
+#define XR_EXT_CONFORMANCE_AUTOMATION_EXTENSION_NAME "XR_EXT_conformance_automation"
+typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceActiveEXT)(XrSession session, XrPath interactionProfile, XrPath topLevelPath, XrBool32 isActive);
+typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateBoolEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrBool32 state);
+typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateFloatEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, float state);
+typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceStateVector2fEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrVector2f state);
+typedef XrResult (XRAPI_PTR *PFN_xrSetInputDeviceLocationEXT)(XrSession session, XrPath topLevelPath, XrPath inputSourcePath, XrSpace space, XrPosef pose);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceActiveEXT(
+    XrSession                                   session,
+    XrPath                                      interactionProfile,
+    XrPath                                      topLevelPath,
+    XrBool32                                    isActive);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateBoolEXT(
+    XrSession                                   session,
+    XrPath                                      topLevelPath,
+    XrPath                                      inputSourcePath,
+    XrBool32                                    state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateFloatEXT(
+    XrSession                                   session,
+    XrPath                                      topLevelPath,
+    XrPath                                      inputSourcePath,
+    float                                       state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceStateVector2fEXT(
+    XrSession                                   session,
+    XrPath                                      topLevelPath,
+    XrPath                                      inputSourcePath,
+    XrVector2f                                  state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetInputDeviceLocationEXT(
+    XrSession                                   session,
+    XrPath                                      topLevelPath,
+    XrPath                                      inputSourcePath,
+    XrSpace                                     space,
+    XrPosef                                     pose);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_spatial_graph_bridge 1
+#define XR_MSFT_spatial_graph_bridge_SPEC_VERSION 1
+#define XR_MSFT_SPATIAL_GRAPH_BRIDGE_EXTENSION_NAME "XR_MSFT_spatial_graph_bridge"
+
+typedef enum XrSpatialGraphNodeTypeMSFT {
+    XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT = 1,
+    XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT = 2,
+    XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSpatialGraphNodeTypeMSFT;
+typedef struct XrSpatialGraphNodeSpaceCreateInfoMSFT {
+    XrStructureType               type;
+    const void* XR_MAY_ALIAS      next;
+    XrSpatialGraphNodeTypeMSFT    nodeType;
+    uint8_t                       nodeId[16];
+    XrPosef                       pose;
+} XrSpatialGraphNodeSpaceCreateInfoMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialGraphNodeSpaceMSFT)(XrSession session, const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo, XrSpace* space);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialGraphNodeSpaceMSFT(
+    XrSession                                   session,
+    const XrSpatialGraphNodeSpaceCreateInfoMSFT* createInfo,
+    XrSpace*                                    space);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_hand_interaction 1
+#define XR_MSFT_hand_interaction_SPEC_VERSION 1
+#define XR_MSFT_HAND_INTERACTION_EXTENSION_NAME "XR_MSFT_hand_interaction"
+
+
+#define XR_EXT_hand_tracking 1
+
+#define XR_HAND_JOINT_COUNT_EXT 26
+
+XR_DEFINE_HANDLE(XrHandTrackerEXT)
+#define XR_EXT_hand_tracking_SPEC_VERSION 4
+#define XR_EXT_HAND_TRACKING_EXTENSION_NAME "XR_EXT_hand_tracking"
+
+typedef enum XrHandEXT {
+    XR_HAND_LEFT_EXT = 1,
+    XR_HAND_RIGHT_EXT = 2,
+    XR_HAND_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrHandEXT;
+
+typedef enum XrHandJointEXT {
+    XR_HAND_JOINT_PALM_EXT = 0,
+    XR_HAND_JOINT_WRIST_EXT = 1,
+    XR_HAND_JOINT_THUMB_METACARPAL_EXT = 2,
+    XR_HAND_JOINT_THUMB_PROXIMAL_EXT = 3,
+    XR_HAND_JOINT_THUMB_DISTAL_EXT = 4,
+    XR_HAND_JOINT_THUMB_TIP_EXT = 5,
+    XR_HAND_JOINT_INDEX_METACARPAL_EXT = 6,
+    XR_HAND_JOINT_INDEX_PROXIMAL_EXT = 7,
+    XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT = 8,
+    XR_HAND_JOINT_INDEX_DISTAL_EXT = 9,
+    XR_HAND_JOINT_INDEX_TIP_EXT = 10,
+    XR_HAND_JOINT_MIDDLE_METACARPAL_EXT = 11,
+    XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT = 12,
+    XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT = 13,
+    XR_HAND_JOINT_MIDDLE_DISTAL_EXT = 14,
+    XR_HAND_JOINT_MIDDLE_TIP_EXT = 15,
+    XR_HAND_JOINT_RING_METACARPAL_EXT = 16,
+    XR_HAND_JOINT_RING_PROXIMAL_EXT = 17,
+    XR_HAND_JOINT_RING_INTERMEDIATE_EXT = 18,
+    XR_HAND_JOINT_RING_DISTAL_EXT = 19,
+    XR_HAND_JOINT_RING_TIP_EXT = 20,
+    XR_HAND_JOINT_LITTLE_METACARPAL_EXT = 21,
+    XR_HAND_JOINT_LITTLE_PROXIMAL_EXT = 22,
+    XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT = 23,
+    XR_HAND_JOINT_LITTLE_DISTAL_EXT = 24,
+    XR_HAND_JOINT_LITTLE_TIP_EXT = 25,
+    XR_HAND_JOINT_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrHandJointEXT;
+
+typedef enum XrHandJointSetEXT {
+    XR_HAND_JOINT_SET_DEFAULT_EXT = 0,
+    XR_HAND_JOINT_SET_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrHandJointSetEXT;
+// XrSystemHandTrackingPropertiesEXT extends XrSystemProperties
+typedef struct XrSystemHandTrackingPropertiesEXT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsHandTracking;
+} XrSystemHandTrackingPropertiesEXT;
+
+typedef struct XrHandTrackerCreateInfoEXT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrHandEXT                   hand;
+    XrHandJointSetEXT           handJointSet;
+} XrHandTrackerCreateInfoEXT;
+
+typedef struct XrHandJointsLocateInfoEXT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSpace                     baseSpace;
+    XrTime                      time;
+} XrHandJointsLocateInfoEXT;
+
+typedef struct XrHandJointLocationEXT {
+    XrSpaceLocationFlags    locationFlags;
+    XrPosef                 pose;
+    float                   radius;
+} XrHandJointLocationEXT;
+
+typedef struct XrHandJointVelocityEXT {
+    XrSpaceVelocityFlags    velocityFlags;
+    XrVector3f              linearVelocity;
+    XrVector3f              angularVelocity;
+} XrHandJointVelocityEXT;
+
+typedef struct XrHandJointLocationsEXT {
+    XrStructureType            type;
+    void* XR_MAY_ALIAS         next;
+    XrBool32                   isActive;
+    uint32_t                   jointCount;
+    XrHandJointLocationEXT*    jointLocations;
+} XrHandJointLocationsEXT;
+
+// XrHandJointVelocitiesEXT extends XrHandJointLocationsEXT
+typedef struct XrHandJointVelocitiesEXT {
+    XrStructureType            type;
+    void* XR_MAY_ALIAS         next;
+    uint32_t                   jointCount;
+    XrHandJointVelocityEXT*    jointVelocities;
+} XrHandJointVelocitiesEXT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateHandTrackerEXT)(XrSession session, const XrHandTrackerCreateInfoEXT* createInfo, XrHandTrackerEXT* handTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyHandTrackerEXT)(XrHandTrackerEXT handTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateHandJointsEXT)(XrHandTrackerEXT handTracker, const XrHandJointsLocateInfoEXT* locateInfo, XrHandJointLocationsEXT* locations);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandTrackerEXT(
+    XrSession                                   session,
+    const XrHandTrackerCreateInfoEXT*           createInfo,
+    XrHandTrackerEXT*                           handTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyHandTrackerEXT(
+    XrHandTrackerEXT                            handTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateHandJointsEXT(
+    XrHandTrackerEXT                            handTracker,
+    const XrHandJointsLocateInfoEXT*            locateInfo,
+    XrHandJointLocationsEXT*                    locations);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_hand_tracking_mesh 1
+#define XR_MSFT_hand_tracking_mesh_SPEC_VERSION 4
+#define XR_MSFT_HAND_TRACKING_MESH_EXTENSION_NAME "XR_MSFT_hand_tracking_mesh"
+
+typedef enum XrHandPoseTypeMSFT {
+    XR_HAND_POSE_TYPE_TRACKED_MSFT = 0,
+    XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT = 1,
+    XR_HAND_POSE_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrHandPoseTypeMSFT;
+// XrSystemHandTrackingMeshPropertiesMSFT extends XrSystemProperties
+typedef struct XrSystemHandTrackingMeshPropertiesMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsHandTrackingMesh;
+    uint32_t              maxHandMeshIndexCount;
+    uint32_t              maxHandMeshVertexCount;
+} XrSystemHandTrackingMeshPropertiesMSFT;
+
+typedef struct XrHandMeshSpaceCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrHandPoseTypeMSFT          handPoseType;
+    XrPosef                     poseInHandMeshSpace;
+} XrHandMeshSpaceCreateInfoMSFT;
+
+typedef struct XrHandMeshUpdateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrTime                      time;
+    XrHandPoseTypeMSFT          handPoseType;
+} XrHandMeshUpdateInfoMSFT;
+
+typedef struct XrHandMeshIndexBufferMSFT {
+    uint32_t     indexBufferKey;
+    uint32_t     indexCapacityInput;
+    uint32_t     indexCountOutput;
+    uint32_t*    indices;
+} XrHandMeshIndexBufferMSFT;
+
+typedef struct XrHandMeshVertexMSFT {
+    XrVector3f    position;
+    XrVector3f    normal;
+} XrHandMeshVertexMSFT;
+
+typedef struct XrHandMeshVertexBufferMSFT {
+    XrTime                   vertexUpdateTime;
+    uint32_t                 vertexCapacityInput;
+    uint32_t                 vertexCountOutput;
+    XrHandMeshVertexMSFT*    vertices;
+} XrHandMeshVertexBufferMSFT;
+
+typedef struct XrHandMeshMSFT {
+    XrStructureType               type;
+    void* XR_MAY_ALIAS            next;
+    XrBool32                      isActive;
+    XrBool32                      indexBufferChanged;
+    XrBool32                      vertexBufferChanged;
+    XrHandMeshIndexBufferMSFT     indexBuffer;
+    XrHandMeshVertexBufferMSFT    vertexBuffer;
+} XrHandMeshMSFT;
+
+// XrHandPoseTypeInfoMSFT extends XrHandTrackerCreateInfoEXT
+typedef struct XrHandPoseTypeInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrHandPoseTypeMSFT          handPoseType;
+} XrHandPoseTypeInfoMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateHandMeshSpaceMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshSpaceCreateInfoMSFT* createInfo, XrSpace* space);
+typedef XrResult (XRAPI_PTR *PFN_xrUpdateHandMeshMSFT)(XrHandTrackerEXT handTracker, const XrHandMeshUpdateInfoMSFT* updateInfo, XrHandMeshMSFT* handMesh);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateHandMeshSpaceMSFT(
+    XrHandTrackerEXT                            handTracker,
+    const XrHandMeshSpaceCreateInfoMSFT*        createInfo,
+    XrSpace*                                    space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrUpdateHandMeshMSFT(
+    XrHandTrackerEXT                            handTracker,
+    const XrHandMeshUpdateInfoMSFT*             updateInfo,
+    XrHandMeshMSFT*                             handMesh);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_secondary_view_configuration 1
+#define XR_MSFT_secondary_view_configuration_SPEC_VERSION 1
+#define XR_MSFT_SECONDARY_VIEW_CONFIGURATION_EXTENSION_NAME "XR_MSFT_secondary_view_configuration"
+// XrSecondaryViewConfigurationSessionBeginInfoMSFT extends XrSessionBeginInfo
+typedef struct XrSecondaryViewConfigurationSessionBeginInfoMSFT {
+    XrStructureType                   type;
+    const void* XR_MAY_ALIAS          next;
+    uint32_t                          viewConfigurationCount;
+    const XrViewConfigurationType*    enabledViewConfigurationTypes;
+} XrSecondaryViewConfigurationSessionBeginInfoMSFT;
+
+typedef struct XrSecondaryViewConfigurationStateMSFT {
+    XrStructureType            type;
+    void* XR_MAY_ALIAS         next;
+    XrViewConfigurationType    viewConfigurationType;
+    XrBool32                   active;
+} XrSecondaryViewConfigurationStateMSFT;
+
+// XrSecondaryViewConfigurationFrameStateMSFT extends XrFrameState
+typedef struct XrSecondaryViewConfigurationFrameStateMSFT {
+    XrStructureType                           type;
+    void* XR_MAY_ALIAS                        next;
+    uint32_t                                  viewConfigurationCount;
+    XrSecondaryViewConfigurationStateMSFT*    viewConfigurationStates;
+} XrSecondaryViewConfigurationFrameStateMSFT;
+
+typedef struct XrSecondaryViewConfigurationLayerInfoMSFT {
+    XrStructureType                               type;
+    const void* XR_MAY_ALIAS                      next;
+    XrViewConfigurationType                       viewConfigurationType;
+    XrEnvironmentBlendMode                        environmentBlendMode;
+    uint32_t                                      layerCount;
+    const XrCompositionLayerBaseHeader* const*    layers;
+} XrSecondaryViewConfigurationLayerInfoMSFT;
+
+// XrSecondaryViewConfigurationFrameEndInfoMSFT extends XrFrameEndInfo
+typedef struct XrSecondaryViewConfigurationFrameEndInfoMSFT {
+    XrStructureType                                     type;
+    const void* XR_MAY_ALIAS                            next;
+    uint32_t                                            viewConfigurationCount;
+    const XrSecondaryViewConfigurationLayerInfoMSFT*    viewConfigurationLayersInfo;
+} XrSecondaryViewConfigurationFrameEndInfoMSFT;
+
+// XrSecondaryViewConfigurationSwapchainCreateInfoMSFT extends XrSwapchainCreateInfo
+typedef struct XrSecondaryViewConfigurationSwapchainCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrViewConfigurationType     viewConfigurationType;
+} XrSecondaryViewConfigurationSwapchainCreateInfoMSFT;
+
+
+
+#define XR_MSFT_first_person_observer 1
+#define XR_MSFT_first_person_observer_SPEC_VERSION 1
+#define XR_MSFT_FIRST_PERSON_OBSERVER_EXTENSION_NAME "XR_MSFT_first_person_observer"
+
+
+#define XR_MSFT_controller_model 1
+
+#define XR_NULL_CONTROLLER_MODEL_KEY_MSFT 0
+
+XR_DEFINE_ATOM(XrControllerModelKeyMSFT)
+#define XR_MSFT_controller_model_SPEC_VERSION 2
+#define XR_MSFT_CONTROLLER_MODEL_EXTENSION_NAME "XR_MSFT_controller_model"
+#define XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT 64
+typedef struct XrControllerModelKeyStateMSFT {
+    XrStructureType             type;
+    void* XR_MAY_ALIAS          next;
+    XrControllerModelKeyMSFT    modelKey;
+} XrControllerModelKeyStateMSFT;
+
+typedef struct XrControllerModelNodePropertiesMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    char                  parentNodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT];
+    char                  nodeName[XR_MAX_CONTROLLER_MODEL_NODE_NAME_SIZE_MSFT];
+} XrControllerModelNodePropertiesMSFT;
+
+typedef struct XrControllerModelPropertiesMSFT {
+    XrStructureType                         type;
+    void* XR_MAY_ALIAS                      next;
+    uint32_t                                nodeCapacityInput;
+    uint32_t                                nodeCountOutput;
+    XrControllerModelNodePropertiesMSFT*    nodeProperties;
+} XrControllerModelPropertiesMSFT;
+
+typedef struct XrControllerModelNodeStateMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrPosef               nodePose;
+} XrControllerModelNodeStateMSFT;
+
+typedef struct XrControllerModelStateMSFT {
+    XrStructureType                    type;
+    void* XR_MAY_ALIAS                 next;
+    uint32_t                           nodeCapacityInput;
+    uint32_t                           nodeCountOutput;
+    XrControllerModelNodeStateMSFT*    nodeStates;
+} XrControllerModelStateMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelKeyMSFT)(XrSession session, XrPath topLevelUserPath, XrControllerModelKeyStateMSFT* controllerModelKeyState);
+typedef XrResult (XRAPI_PTR *PFN_xrLoadControllerModelMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, uint8_t* buffer);
+typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelPropertiesMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelPropertiesMSFT* properties);
+typedef XrResult (XRAPI_PTR *PFN_xrGetControllerModelStateMSFT)(XrSession session, XrControllerModelKeyMSFT modelKey, XrControllerModelStateMSFT* state);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelKeyMSFT(
+    XrSession                                   session,
+    XrPath                                      topLevelUserPath,
+    XrControllerModelKeyStateMSFT*              controllerModelKeyState);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLoadControllerModelMSFT(
+    XrSession                                   session,
+    XrControllerModelKeyMSFT                    modelKey,
+    uint32_t                                    bufferCapacityInput,
+    uint32_t*                                   bufferCountOutput,
+    uint8_t*                                    buffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelPropertiesMSFT(
+    XrSession                                   session,
+    XrControllerModelKeyMSFT                    modelKey,
+    XrControllerModelPropertiesMSFT*            properties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetControllerModelStateMSFT(
+    XrSession                                   session,
+    XrControllerModelKeyMSFT                    modelKey,
+    XrControllerModelStateMSFT*                 state);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_EXT_win32_appcontainer_compatible 1
+#define XR_EXT_win32_appcontainer_compatible_SPEC_VERSION 1
+#define XR_EXT_WIN32_APPCONTAINER_COMPATIBLE_EXTENSION_NAME "XR_EXT_win32_appcontainer_compatible"
+
+
+#define XR_EPIC_view_configuration_fov 1
+#define XR_EPIC_view_configuration_fov_SPEC_VERSION 2
+#define XR_EPIC_VIEW_CONFIGURATION_FOV_EXTENSION_NAME "XR_EPIC_view_configuration_fov"
+// XrViewConfigurationViewFovEPIC extends XrViewConfigurationView
+typedef struct XrViewConfigurationViewFovEPIC {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrFovf                      recommendedFov;
+    XrFovf                      maxMutableFov;
+} XrViewConfigurationViewFovEPIC;
+
+
+
+#define XR_MSFT_composition_layer_reprojection 1
+#define XR_MSFT_composition_layer_reprojection_SPEC_VERSION 1
+#define XR_MSFT_COMPOSITION_LAYER_REPROJECTION_EXTENSION_NAME "XR_MSFT_composition_layer_reprojection"
+
+typedef enum XrReprojectionModeMSFT {
+    XR_REPROJECTION_MODE_DEPTH_MSFT = 1,
+    XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT = 2,
+    XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT = 3,
+    XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT = 4,
+    XR_REPROJECTION_MODE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrReprojectionModeMSFT;
+// XrCompositionLayerReprojectionInfoMSFT extends XrCompositionLayerProjection
+typedef struct XrCompositionLayerReprojectionInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrReprojectionModeMSFT      reprojectionMode;
+} XrCompositionLayerReprojectionInfoMSFT;
+
+// XrCompositionLayerReprojectionPlaneOverrideMSFT extends XrCompositionLayerProjection
+typedef struct XrCompositionLayerReprojectionPlaneOverrideMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrVector3f                  position;
+    XrVector3f                  normal;
+    XrVector3f                  velocity;
+} XrCompositionLayerReprojectionPlaneOverrideMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateReprojectionModesMSFT)(XrInstance instance, XrSystemId systemId, XrViewConfigurationType viewConfigurationType, uint32_t modeCapacityInput, uint32_t* modeCountOutput, XrReprojectionModeMSFT* modes);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateReprojectionModesMSFT(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrViewConfigurationType                     viewConfigurationType,
+    uint32_t                                    modeCapacityInput,
+    uint32_t*                                   modeCountOutput,
+    XrReprojectionModeMSFT*                     modes);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_HUAWEI_controller_interaction 1
+#define XR_HUAWEI_controller_interaction_SPEC_VERSION 1
+#define XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HUAWEI_controller_interaction"
+
+
+#define XR_FB_swapchain_update_state 1
+#define XR_FB_swapchain_update_state_SPEC_VERSION 3
+#define XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME "XR_FB_swapchain_update_state"
+typedef struct XR_MAY_ALIAS XrSwapchainStateBaseHeaderFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+} XrSwapchainStateBaseHeaderFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrUpdateSwapchainFB)(XrSwapchain swapchain, const XrSwapchainStateBaseHeaderFB* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSwapchainStateFB)(XrSwapchain swapchain, XrSwapchainStateBaseHeaderFB* state);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrUpdateSwapchainFB(
+    XrSwapchain                                 swapchain,
+    const XrSwapchainStateBaseHeaderFB*         state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSwapchainStateFB(
+    XrSwapchain                                 swapchain,
+    XrSwapchainStateBaseHeaderFB*               state);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_composition_layer_secure_content 1
+#define XR_FB_composition_layer_secure_content_SPEC_VERSION 1
+#define XR_FB_COMPOSITION_LAYER_SECURE_CONTENT_EXTENSION_NAME "XR_FB_composition_layer_secure_content"
+typedef XrFlags64 XrCompositionLayerSecureContentFlagsFB;
+
+// Flag bits for XrCompositionLayerSecureContentFlagsFB
+static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB = 0x00000001;
+static const XrCompositionLayerSecureContentFlagsFB XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB = 0x00000002;
+
+// XrCompositionLayerSecureContentFB extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerSecureContentFB {
+    XrStructureType                           type;
+    const void* XR_MAY_ALIAS                  next;
+    XrCompositionLayerSecureContentFlagsFB    flags;
+} XrCompositionLayerSecureContentFB;
+
+
+
+#define XR_VALVE_analog_threshold 1
+#define XR_VALVE_analog_threshold_SPEC_VERSION 2
+#define XR_VALVE_ANALOG_THRESHOLD_EXTENSION_NAME "XR_VALVE_analog_threshold"
+typedef struct XrInteractionProfileAnalogThresholdVALVE {
+    XrStructureType              type;
+    const void* XR_MAY_ALIAS     next;
+    XrAction                     action;
+    XrPath                       binding;
+    float                        onThreshold;
+    float                        offThreshold;
+    const XrHapticBaseHeader*    onHaptic;
+    const XrHapticBaseHeader*    offHaptic;
+} XrInteractionProfileAnalogThresholdVALVE;
+
+
+
+#define XR_EXT_hand_joints_motion_range 1
+#define XR_EXT_hand_joints_motion_range_SPEC_VERSION 1
+#define XR_EXT_HAND_JOINTS_MOTION_RANGE_EXTENSION_NAME "XR_EXT_hand_joints_motion_range"
+
+typedef enum XrHandJointsMotionRangeEXT {
+    XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT = 1,
+    XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT = 2,
+    XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT = 0x7FFFFFFF
+} XrHandJointsMotionRangeEXT;
+// XrHandJointsMotionRangeInfoEXT extends XrHandJointsLocateInfoEXT
+typedef struct XrHandJointsMotionRangeInfoEXT {
+    XrStructureType               type;
+    const void* XR_MAY_ALIAS      next;
+    XrHandJointsMotionRangeEXT    handJointsMotionRange;
+} XrHandJointsMotionRangeInfoEXT;
+
+
+
+#define XR_EXT_samsung_odyssey_controller 1
+#define XR_EXT_samsung_odyssey_controller_SPEC_VERSION 1
+#define XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME "XR_EXT_samsung_odyssey_controller"
+
+
+#define XR_EXT_hp_mixed_reality_controller 1
+#define XR_EXT_hp_mixed_reality_controller_SPEC_VERSION 1
+#define XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME "XR_EXT_hp_mixed_reality_controller"
+
+
+#define XR_MND_swapchain_usage_input_attachment_bit 1
+#define XR_MND_swapchain_usage_input_attachment_bit_SPEC_VERSION 2
+#define XR_MND_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_EXTENSION_NAME "XR_MND_swapchain_usage_input_attachment_bit"
+
+
+#define XR_MSFT_scene_understanding 1
+
+            XR_DEFINE_HANDLE(XrSceneObserverMSFT)
+
+
+            XR_DEFINE_HANDLE(XrSceneMSFT)
+
+#define XR_MSFT_scene_understanding_SPEC_VERSION 1
+#define XR_MSFT_SCENE_UNDERSTANDING_EXTENSION_NAME "XR_MSFT_scene_understanding"
+
+typedef enum XrSceneComputeFeatureMSFT {
+    XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT = 1,
+    XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT = 2,
+    XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT = 3,
+    XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT = 4,
+    XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT = 1000098000,
+    XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSceneComputeFeatureMSFT;
+
+typedef enum XrSceneComputeConsistencyMSFT {
+    XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT = 1,
+    XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT = 2,
+    XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT = 3,
+    XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSceneComputeConsistencyMSFT;
+
+typedef enum XrMeshComputeLodMSFT {
+    XR_MESH_COMPUTE_LOD_COARSE_MSFT = 1,
+    XR_MESH_COMPUTE_LOD_MEDIUM_MSFT = 2,
+    XR_MESH_COMPUTE_LOD_FINE_MSFT = 3,
+    XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT = 4,
+    XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrMeshComputeLodMSFT;
+
+typedef enum XrSceneComponentTypeMSFT {
+    XR_SCENE_COMPONENT_TYPE_INVALID_MSFT = -1,
+    XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT = 1,
+    XR_SCENE_COMPONENT_TYPE_PLANE_MSFT = 2,
+    XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT = 3,
+    XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT = 4,
+    XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT = 1000098000,
+    XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSceneComponentTypeMSFT;
+
+typedef enum XrSceneObjectTypeMSFT {
+    XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT = -1,
+    XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT = 1,
+    XR_SCENE_OBJECT_TYPE_WALL_MSFT = 2,
+    XR_SCENE_OBJECT_TYPE_FLOOR_MSFT = 3,
+    XR_SCENE_OBJECT_TYPE_CEILING_MSFT = 4,
+    XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT = 5,
+    XR_SCENE_OBJECT_TYPE_INFERRED_MSFT = 6,
+    XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSceneObjectTypeMSFT;
+
+typedef enum XrScenePlaneAlignmentTypeMSFT {
+    XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT = 0,
+    XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT = 1,
+    XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT = 2,
+    XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrScenePlaneAlignmentTypeMSFT;
+
+typedef enum XrSceneComputeStateMSFT {
+    XR_SCENE_COMPUTE_STATE_NONE_MSFT = 0,
+    XR_SCENE_COMPUTE_STATE_UPDATING_MSFT = 1,
+    XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT = 2,
+    XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT = 3,
+    XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT = 0x7FFFFFFF
+} XrSceneComputeStateMSFT;
+typedef struct XrUuidMSFT {
+    uint8_t    bytes[16];
+} XrUuidMSFT;
+
+typedef struct XrSceneObserverCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrSceneObserverCreateInfoMSFT;
+
+typedef struct XrSceneCreateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} XrSceneCreateInfoMSFT;
+
+typedef struct XrSceneSphereBoundMSFT {
+    XrVector3f    center;
+    float         radius;
+} XrSceneSphereBoundMSFT;
+
+typedef struct XrSceneOrientedBoxBoundMSFT {
+    XrPosef       pose;
+    XrVector3f    extents;
+} XrSceneOrientedBoxBoundMSFT;
+
+typedef struct XrSceneFrustumBoundMSFT {
+    XrPosef    pose;
+    XrFovf     fov;
+    float      farDistance;
+} XrSceneFrustumBoundMSFT;
+
+typedef struct XrSceneBoundsMSFT {
+    XrSpace                               space;
+    XrTime                                time;
+    uint32_t                              sphereCount;
+    const XrSceneSphereBoundMSFT*         spheres;
+    uint32_t                              boxCount;
+    const XrSceneOrientedBoxBoundMSFT*    boxes;
+    uint32_t                              frustumCount;
+    const XrSceneFrustumBoundMSFT*        frustums;
+} XrSceneBoundsMSFT;
+
+typedef struct XrNewSceneComputeInfoMSFT {
+    XrStructureType                     type;
+    const void* XR_MAY_ALIAS            next;
+    uint32_t                            requestedFeatureCount;
+    const XrSceneComputeFeatureMSFT*    requestedFeatures;
+    XrSceneComputeConsistencyMSFT       consistency;
+    XrSceneBoundsMSFT                   bounds;
+} XrNewSceneComputeInfoMSFT;
+
+// XrVisualMeshComputeLodInfoMSFT extends XrNewSceneComputeInfoMSFT
+typedef struct XrVisualMeshComputeLodInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrMeshComputeLodMSFT        lod;
+} XrVisualMeshComputeLodInfoMSFT;
+
+typedef struct XrSceneComponentMSFT {
+    XrSceneComponentTypeMSFT    componentType;
+    XrUuidMSFT                  id;
+    XrUuidMSFT                  parentId;
+    XrTime                      updateTime;
+} XrSceneComponentMSFT;
+
+typedef struct XrSceneComponentsMSFT {
+    XrStructureType          type;
+    void* XR_MAY_ALIAS       next;
+    uint32_t                 componentCapacityInput;
+    uint32_t                 componentCountOutput;
+    XrSceneComponentMSFT*    components;
+} XrSceneComponentsMSFT;
+
+typedef struct XrSceneComponentsGetInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSceneComponentTypeMSFT    componentType;
+} XrSceneComponentsGetInfoMSFT;
+
+typedef struct XrSceneComponentLocationMSFT {
+    XrSpaceLocationFlags    flags;
+    XrPosef                 pose;
+} XrSceneComponentLocationMSFT;
+
+typedef struct XrSceneComponentLocationsMSFT {
+    XrStructureType                  type;
+    void* XR_MAY_ALIAS               next;
+    uint32_t                         locationCount;
+    XrSceneComponentLocationMSFT*    locations;
+} XrSceneComponentLocationsMSFT;
+
+typedef struct XrSceneComponentsLocateInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSpace                     baseSpace;
+    XrTime                      time;
+    uint32_t                    componentIdCount;
+    const XrUuidMSFT*           componentIds;
+} XrSceneComponentsLocateInfoMSFT;
+
+typedef struct XrSceneObjectMSFT {
+    XrSceneObjectTypeMSFT    objectType;
+} XrSceneObjectMSFT;
+
+// XrSceneObjectsMSFT extends XrSceneComponentsMSFT
+typedef struct XrSceneObjectsMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              sceneObjectCount;
+    XrSceneObjectMSFT*    sceneObjects;
+} XrSceneObjectsMSFT;
+
+// XrSceneComponentParentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT
+typedef struct XrSceneComponentParentFilterInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrUuidMSFT                  parentId;
+} XrSceneComponentParentFilterInfoMSFT;
+
+// XrSceneObjectTypesFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT
+typedef struct XrSceneObjectTypesFilterInfoMSFT {
+    XrStructureType                 type;
+    const void* XR_MAY_ALIAS        next;
+    uint32_t                        objectTypeCount;
+    const XrSceneObjectTypeMSFT*    objectTypes;
+} XrSceneObjectTypesFilterInfoMSFT;
+
+typedef struct XrScenePlaneMSFT {
+    XrScenePlaneAlignmentTypeMSFT    alignment;
+    XrExtent2Df                      size;
+    uint64_t                         meshBufferId;
+    XrBool32                         supportsIndicesUint16;
+} XrScenePlaneMSFT;
+
+// XrScenePlanesMSFT extends XrSceneComponentsMSFT
+typedef struct XrScenePlanesMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              scenePlaneCount;
+    XrScenePlaneMSFT*     scenePlanes;
+} XrScenePlanesMSFT;
+
+// XrScenePlaneAlignmentFilterInfoMSFT extends XrSceneComponentsGetInfoMSFT
+typedef struct XrScenePlaneAlignmentFilterInfoMSFT {
+    XrStructureType                         type;
+    const void* XR_MAY_ALIAS                next;
+    uint32_t                                alignmentCount;
+    const XrScenePlaneAlignmentTypeMSFT*    alignments;
+} XrScenePlaneAlignmentFilterInfoMSFT;
+
+typedef struct XrSceneMeshMSFT {
+    uint64_t    meshBufferId;
+    XrBool32    supportsIndicesUint16;
+} XrSceneMeshMSFT;
+
+// XrSceneMeshesMSFT extends XrSceneComponentsMSFT
+typedef struct XrSceneMeshesMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              sceneMeshCount;
+    XrSceneMeshMSFT*      sceneMeshes;
+} XrSceneMeshesMSFT;
+
+typedef struct XrSceneMeshBuffersGetInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint64_t                    meshBufferId;
+} XrSceneMeshBuffersGetInfoMSFT;
+
+typedef struct XrSceneMeshBuffersMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+} XrSceneMeshBuffersMSFT;
+
+typedef struct XrSceneMeshVertexBufferMSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              vertexCapacityInput;
+    uint32_t              vertexCountOutput;
+    XrVector3f*           vertices;
+} XrSceneMeshVertexBufferMSFT;
+
+typedef struct XrSceneMeshIndicesUint32MSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              indexCapacityInput;
+    uint32_t              indexCountOutput;
+    uint32_t*             indices;
+} XrSceneMeshIndicesUint32MSFT;
+
+typedef struct XrSceneMeshIndicesUint16MSFT {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              indexCapacityInput;
+    uint32_t              indexCountOutput;
+    uint16_t*             indices;
+} XrSceneMeshIndicesUint16MSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateSceneComputeFeaturesMSFT)(XrInstance instance, XrSystemId systemId, uint32_t featureCapacityInput, uint32_t* featureCountOutput, XrSceneComputeFeatureMSFT* features);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneObserverMSFT)(XrSession session, const XrSceneObserverCreateInfoMSFT* createInfo, XrSceneObserverMSFT* sceneObserver);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneObserverMSFT)(XrSceneObserverMSFT sceneObserver);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneCreateInfoMSFT* createInfo, XrSceneMSFT* scene);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySceneMSFT)(XrSceneMSFT scene);
+typedef XrResult (XRAPI_PTR *PFN_xrComputeNewSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrNewSceneComputeInfoMSFT* computeInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComputeStateMSFT)(XrSceneObserverMSFT sceneObserver, XrSceneComputeStateMSFT* state);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsGetInfoMSFT* getInfo, XrSceneComponentsMSFT* components);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateSceneComponentsMSFT)(XrSceneMSFT scene, const XrSceneComponentsLocateInfoMSFT* locateInfo, XrSceneComponentLocationsMSFT* locations);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSceneMeshBuffersMSFT)(XrSceneMSFT scene, const XrSceneMeshBuffersGetInfoMSFT* getInfo, XrSceneMeshBuffersMSFT* buffers);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateSceneComputeFeaturesMSFT(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    uint32_t                                    featureCapacityInput,
+    uint32_t*                                   featureCountOutput,
+    XrSceneComputeFeatureMSFT*                  features);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneObserverMSFT(
+    XrSession                                   session,
+    const XrSceneObserverCreateInfoMSFT*        createInfo,
+    XrSceneObserverMSFT*                        sceneObserver);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneObserverMSFT(
+    XrSceneObserverMSFT                         sceneObserver);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSceneMSFT(
+    XrSceneObserverMSFT                         sceneObserver,
+    const XrSceneCreateInfoMSFT*                createInfo,
+    XrSceneMSFT*                                scene);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySceneMSFT(
+    XrSceneMSFT                                 scene);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrComputeNewSceneMSFT(
+    XrSceneObserverMSFT                         sceneObserver,
+    const XrNewSceneComputeInfoMSFT*            computeInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComputeStateMSFT(
+    XrSceneObserverMSFT                         sceneObserver,
+    XrSceneComputeStateMSFT*                    state);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneComponentsMSFT(
+    XrSceneMSFT                                 scene,
+    const XrSceneComponentsGetInfoMSFT*         getInfo,
+    XrSceneComponentsMSFT*                      components);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateSceneComponentsMSFT(
+    XrSceneMSFT                                 scene,
+    const XrSceneComponentsLocateInfoMSFT*      locateInfo,
+    XrSceneComponentLocationsMSFT*              locations);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSceneMeshBuffersMSFT(
+    XrSceneMSFT                                 scene,
+    const XrSceneMeshBuffersGetInfoMSFT*        getInfo,
+    XrSceneMeshBuffersMSFT*                     buffers);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_scene_understanding_serialization 1
+#define XR_MSFT_scene_understanding_serialization_SPEC_VERSION 1
+#define XR_MSFT_SCENE_UNDERSTANDING_SERIALIZATION_EXTENSION_NAME "XR_MSFT_scene_understanding_serialization"
+typedef struct XrSerializedSceneFragmentDataGetInfoMSFT {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrUuidMSFT                  sceneFragmentId;
+} XrSerializedSceneFragmentDataGetInfoMSFT;
+
+typedef struct XrDeserializeSceneFragmentMSFT {
+    uint32_t          bufferSize;
+    const uint8_t*    buffer;
+} XrDeserializeSceneFragmentMSFT;
+
+typedef struct XrSceneDeserializeInfoMSFT {
+    XrStructureType                          type;
+    const void* XR_MAY_ALIAS                 next;
+    uint32_t                                 fragmentCount;
+    const XrDeserializeSceneFragmentMSFT*    fragments;
+} XrSceneDeserializeInfoMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrDeserializeSceneMSFT)(XrSceneObserverMSFT sceneObserver, const XrSceneDeserializeInfoMSFT* deserializeInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrGetSerializedSceneFragmentDataMSFT)(XrSceneMSFT scene, const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo, uint32_t countInput, uint32_t* readOutput, uint8_t* buffer);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrDeserializeSceneMSFT(
+    XrSceneObserverMSFT                         sceneObserver,
+    const XrSceneDeserializeInfoMSFT*           deserializeInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetSerializedSceneFragmentDataMSFT(
+    XrSceneMSFT                                 scene,
+    const XrSerializedSceneFragmentDataGetInfoMSFT* getInfo,
+    uint32_t                                    countInput,
+    uint32_t*                                   readOutput,
+    uint8_t*                                    buffer);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_display_refresh_rate 1
+#define XR_FB_display_refresh_rate_SPEC_VERSION 1
+#define XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME "XR_FB_display_refresh_rate"
+typedef struct XrEventDataDisplayRefreshRateChangedFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    float                       fromDisplayRefreshRate;
+    float                       toDisplayRefreshRate;
+} XrEventDataDisplayRefreshRateChangedFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateDisplayRefreshRatesFB)(XrSession session, uint32_t displayRefreshRateCapacityInput, uint32_t* displayRefreshRateCountOutput, float* displayRefreshRates);
+typedef XrResult (XRAPI_PTR *PFN_xrGetDisplayRefreshRateFB)(XrSession session, float* displayRefreshRate);
+typedef XrResult (XRAPI_PTR *PFN_xrRequestDisplayRefreshRateFB)(XrSession session, float displayRefreshRate);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateDisplayRefreshRatesFB(
+    XrSession                                   session,
+    uint32_t                                    displayRefreshRateCapacityInput,
+    uint32_t*                                   displayRefreshRateCountOutput,
+    float*                                      displayRefreshRates);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetDisplayRefreshRateFB(
+    XrSession                                   session,
+    float*                                      displayRefreshRate);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrRequestDisplayRefreshRateFB(
+    XrSession                                   session,
+    float                                       displayRefreshRate);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_HTC_vive_cosmos_controller_interaction 1
+#define XR_HTC_vive_cosmos_controller_interaction_SPEC_VERSION 1
+#define XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_cosmos_controller_interaction"
+
+
+#define XR_HTCX_vive_tracker_interaction 1
+#define XR_HTCX_vive_tracker_interaction_SPEC_VERSION 1
+#define XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME "XR_HTCX_vive_tracker_interaction"
+typedef struct XrViveTrackerPathsHTCX {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrPath                persistentPath;
+    XrPath                rolePath;
+} XrViveTrackerPathsHTCX;
+
+typedef struct XrEventDataViveTrackerConnectedHTCX {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrViveTrackerPathsHTCX*     paths;
+} XrEventDataViveTrackerConnectedHTCX;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateViveTrackerPathsHTCX)(XrInstance instance, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrViveTrackerPathsHTCX* paths);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateViveTrackerPathsHTCX(
+    XrInstance                                  instance,
+    uint32_t                                    pathCapacityInput,
+    uint32_t*                                   pathCountOutput,
+    XrViveTrackerPathsHTCX*                     paths);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_HTC_facial_tracking 1
+
+#define XR_FACIAL_EXPRESSION_EYE_COUNT_HTC 14
+
+
+#define XR_FACIAL_EXPRESSION_LIP_COUNT_HTC 37
+
+XR_DEFINE_HANDLE(XrFacialTrackerHTC)
+#define XR_HTC_facial_tracking_SPEC_VERSION 1
+#define XR_HTC_FACIAL_TRACKING_EXTENSION_NAME "XR_HTC_facial_tracking"
+
+typedef enum XrEyeExpressionHTC {
+    XR_EYE_EXPRESSION_LEFT_BLINK_HTC = 0,
+    XR_EYE_EXPRESSION_LEFT_WIDE_HTC = 1,
+    XR_EYE_EXPRESSION_RIGHT_BLINK_HTC = 2,
+    XR_EYE_EXPRESSION_RIGHT_WIDE_HTC = 3,
+    XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC = 4,
+    XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC = 5,
+    XR_EYE_EXPRESSION_LEFT_DOWN_HTC = 6,
+    XR_EYE_EXPRESSION_RIGHT_DOWN_HTC = 7,
+    XR_EYE_EXPRESSION_LEFT_OUT_HTC = 8,
+    XR_EYE_EXPRESSION_RIGHT_IN_HTC = 9,
+    XR_EYE_EXPRESSION_LEFT_IN_HTC = 10,
+    XR_EYE_EXPRESSION_RIGHT_OUT_HTC = 11,
+    XR_EYE_EXPRESSION_LEFT_UP_HTC = 12,
+    XR_EYE_EXPRESSION_RIGHT_UP_HTC = 13,
+    XR_EYE_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF
+} XrEyeExpressionHTC;
+
+typedef enum XrLipExpressionHTC {
+    XR_LIP_EXPRESSION_JAW_RIGHT_HTC = 0,
+    XR_LIP_EXPRESSION_JAW_LEFT_HTC = 1,
+    XR_LIP_EXPRESSION_JAW_FORWARD_HTC = 2,
+    XR_LIP_EXPRESSION_JAW_OPEN_HTC = 3,
+    XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC = 4,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC = 5,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC = 6,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC = 7,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC = 8,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC = 9,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC = 10,
+    XR_LIP_EXPRESSION_MOUTH_POUT_HTC = 11,
+    XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC = 12,
+    XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC = 13,
+    XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC = 14,
+    XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC = 15,
+    XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC = 16,
+    XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC = 17,
+    XR_LIP_EXPRESSION_CHEEK_SUCK_HTC = 18,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC = 19,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC = 20,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC = 21,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC = 22,
+    XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC = 23,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC = 24,
+    XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC = 25,
+    XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC = 26,
+    XR_LIP_EXPRESSION_TONGUE_LEFT_HTC = 27,
+    XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC = 28,
+    XR_LIP_EXPRESSION_TONGUE_UP_HTC = 29,
+    XR_LIP_EXPRESSION_TONGUE_DOWN_HTC = 30,
+    XR_LIP_EXPRESSION_TONGUE_ROLL_HTC = 31,
+    XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC = 32,
+    XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC = 33,
+    XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC = 34,
+    XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC = 35,
+    XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC = 36,
+    XR_LIP_EXPRESSION_MAX_ENUM_HTC = 0x7FFFFFFF
+} XrLipExpressionHTC;
+
+typedef enum XrFacialTrackingTypeHTC {
+    XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC = 1,
+    XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC = 2,
+    XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC = 0x7FFFFFFF
+} XrFacialTrackingTypeHTC;
+// XrSystemFacialTrackingPropertiesHTC extends XrSystemProperties
+typedef struct XrSystemFacialTrackingPropertiesHTC {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportEyeFacialTracking;
+    XrBool32              supportLipFacialTracking;
+} XrSystemFacialTrackingPropertiesHTC;
+
+typedef struct XrFacialExpressionsHTC {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrBool32                    isActive;
+    XrTime                      sampleTime;
+    uint32_t                    expressionCount;
+    float*                      expressionWeightings;
+} XrFacialExpressionsHTC;
+
+typedef struct XrFacialTrackerCreateInfoHTC {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrFacialTrackingTypeHTC     facialTrackingType;
+} XrFacialTrackerCreateInfoHTC;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateFacialTrackerHTC)(XrSession session, const XrFacialTrackerCreateInfoHTC* createInfo, XrFacialTrackerHTC* facialTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyFacialTrackerHTC)(XrFacialTrackerHTC facialTracker);
+typedef XrResult (XRAPI_PTR *PFN_xrGetFacialExpressionsHTC)(XrFacialTrackerHTC facialTracker, XrFacialExpressionsHTC* facialExpressions);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateFacialTrackerHTC(
+    XrSession                                   session,
+    const XrFacialTrackerCreateInfoHTC*         createInfo,
+    XrFacialTrackerHTC*                         facialTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFacialTrackerHTC(
+    XrFacialTrackerHTC                          facialTracker);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetFacialExpressionsHTC(
+    XrFacialTrackerHTC                          facialTracker,
+    XrFacialExpressionsHTC*                     facialExpressions);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_HTC_vive_focus3_controller_interaction 1
+#define XR_HTC_vive_focus3_controller_interaction_SPEC_VERSION 1
+#define XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME "XR_HTC_vive_focus3_controller_interaction"
+
+
+#define XR_FB_color_space 1
+#define XR_FB_color_space_SPEC_VERSION    2
+#define XR_FB_COLOR_SPACE_EXTENSION_NAME  "XR_FB_color_space"
+
+typedef enum XrColorSpaceFB {
+    XR_COLOR_SPACE_UNMANAGED_FB = 0,
+    XR_COLOR_SPACE_REC2020_FB = 1,
+    XR_COLOR_SPACE_REC709_FB = 2,
+    XR_COLOR_SPACE_RIFT_CV1_FB = 3,
+    XR_COLOR_SPACE_RIFT_S_FB = 4,
+    XR_COLOR_SPACE_QUEST_FB = 5,
+    XR_COLOR_SPACE_P3_FB = 6,
+    XR_COLOR_SPACE_ADOBE_RGB_FB = 7,
+    XR_COLOR_SPACE_MAX_ENUM_FB = 0x7FFFFFFF
+} XrColorSpaceFB;
+// XrSystemColorSpacePropertiesFB extends XrSystemProperties
+typedef struct XrSystemColorSpacePropertiesFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrColorSpaceFB        colorSpace;
+} XrSystemColorSpacePropertiesFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateColorSpacesFB)(XrSession session, uint32_t colorSpaceCapacityInput, uint32_t* colorSpaceCountOutput, XrColorSpaceFB* colorSpaces);
+typedef XrResult (XRAPI_PTR *PFN_xrSetColorSpaceFB)(XrSession session, const XrColorSpaceFB colorspace);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateColorSpacesFB(
+    XrSession                                   session,
+    uint32_t                                    colorSpaceCapacityInput,
+    uint32_t*                                   colorSpaceCountOutput,
+    XrColorSpaceFB*                             colorSpaces);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetColorSpaceFB(
+    XrSession                                   session,
+    const XrColorSpaceFB                        colorspace);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_hand_tracking_mesh 1
+#define XR_FB_hand_tracking_mesh_SPEC_VERSION 1
+#define XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME "XR_FB_hand_tracking_mesh"
+typedef struct XrVector4sFB {
+    int16_t    x;
+    int16_t    y;
+    int16_t    z;
+    int16_t    w;
+} XrVector4sFB;
+
+typedef struct XrHandTrackingMeshFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              jointCapacityInput;
+    uint32_t              jointCountOutput;
+    XrPosef*              jointBindPoses;
+    float*                jointRadii;
+    XrHandJointEXT*       jointParents;
+    uint32_t              vertexCapacityInput;
+    uint32_t              vertexCountOutput;
+    XrVector3f*           vertexPositions;
+    XrVector3f*           vertexNormals;
+    XrVector2f*           vertexUVs;
+    XrVector4sFB*         vertexBlendIndices;
+    XrVector4f*           vertexBlendWeights;
+    uint32_t              indexCapacityInput;
+    uint32_t              indexCountOutput;
+    int16_t*              indices;
+} XrHandTrackingMeshFB;
+
+// XrHandTrackingScaleFB extends XrHandJointsLocateInfoEXT
+typedef struct XrHandTrackingScaleFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    float                 sensorOutput;
+    float                 currentOutput;
+    XrBool32              overrideHandScale;
+    float                 overrideValueInput;
+} XrHandTrackingScaleFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetHandMeshFB)(XrHandTrackerEXT handTracker, XrHandTrackingMeshFB* mesh);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetHandMeshFB(
+    XrHandTrackerEXT                            handTracker,
+    XrHandTrackingMeshFB*                       mesh);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_hand_tracking_aim 1
+#define XR_FB_hand_tracking_aim_SPEC_VERSION 1
+#define XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME "XR_FB_hand_tracking_aim"
+typedef XrFlags64 XrHandTrackingAimFlagsFB;
+
+// Flag bits for XrHandTrackingAimFlagsFB
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB = 0x00000001;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_VALID_BIT_FB = 0x00000002;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB = 0x00000004;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB = 0x00000008;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB = 0x00000010;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB = 0x00000020;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB = 0x00000040;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB = 0x00000080;
+static const XrHandTrackingAimFlagsFB XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB = 0x00000100;
+
+// XrHandTrackingAimStateFB extends XrHandJointsLocateInfoEXT
+typedef struct XrHandTrackingAimStateFB {
+    XrStructureType             type;
+    void* XR_MAY_ALIAS          next;
+    XrHandTrackingAimFlagsFB    status;
+    XrPosef                     aimPose;
+    float                       pinchStrengthIndex;
+    float                       pinchStrengthMiddle;
+    float                       pinchStrengthRing;
+    float                       pinchStrengthLittle;
+} XrHandTrackingAimStateFB;
+
+
+
+#define XR_FB_hand_tracking_capsules 1
+#define XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB 2
+#define XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT XR_HAND_TRACKING_CAPSULE_POINT_COUNT_FB
+#define XR_HAND_TRACKING_CAPSULE_COUNT_FB 19
+#define XR_FB_HAND_TRACKING_CAPSULE_COUNT XR_HAND_TRACKING_CAPSULE_COUNT_FB
+#define XR_FB_hand_tracking_capsules_SPEC_VERSION 2
+#define XR_FB_HAND_TRACKING_CAPSULES_EXTENSION_NAME "XR_FB_hand_tracking_capsules"
+typedef struct XrHandCapsuleFB {
+    XrVector3f        points[XR_FB_HAND_TRACKING_CAPSULE_POINT_COUNT];
+    float             radius;
+    XrHandJointEXT    joint;
+} XrHandCapsuleFB;
+
+// XrHandTrackingCapsulesStateFB extends XrHandJointsLocateInfoEXT
+typedef struct XrHandTrackingCapsulesStateFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrHandCapsuleFB       capsules[XR_FB_HAND_TRACKING_CAPSULE_COUNT];
+} XrHandTrackingCapsulesStateFB;
+
+
+
+#define XR_FB_foveation 1
+XR_DEFINE_HANDLE(XrFoveationProfileFB)
+#define XR_FB_foveation_SPEC_VERSION      1
+#define XR_FB_FOVEATION_EXTENSION_NAME    "XR_FB_foveation"
+typedef XrFlags64 XrSwapchainCreateFoveationFlagsFB;
+
+// Flag bits for XrSwapchainCreateFoveationFlagsFB
+static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB = 0x00000001;
+static const XrSwapchainCreateFoveationFlagsFB XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB = 0x00000002;
+
+typedef XrFlags64 XrSwapchainStateFoveationFlagsFB;
+
+// Flag bits for XrSwapchainStateFoveationFlagsFB
+
+typedef struct XrFoveationProfileCreateInfoFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+} XrFoveationProfileCreateInfoFB;
+
+// XrSwapchainCreateInfoFoveationFB extends XrSwapchainCreateInfo
+typedef struct XrSwapchainCreateInfoFoveationFB {
+    XrStructureType                      type;
+    void* XR_MAY_ALIAS                   next;
+    XrSwapchainCreateFoveationFlagsFB    flags;
+} XrSwapchainCreateInfoFoveationFB;
+
+typedef struct XrSwapchainStateFoveationFB {
+    XrStructureType                     type;
+    void* XR_MAY_ALIAS                  next;
+    XrSwapchainStateFoveationFlagsFB    flags;
+    XrFoveationProfileFB                profile;
+} XrSwapchainStateFoveationFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateFoveationProfileFB)(XrSession session, const XrFoveationProfileCreateInfoFB* createInfo, XrFoveationProfileFB* profile);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyFoveationProfileFB)(XrFoveationProfileFB profile);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateFoveationProfileFB(
+    XrSession                                   session,
+    const XrFoveationProfileCreateInfoFB*       createInfo,
+    XrFoveationProfileFB*                       profile);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyFoveationProfileFB(
+    XrFoveationProfileFB                        profile);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_foveation_configuration 1
+#define XR_FB_foveation_configuration_SPEC_VERSION 1
+#define XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME "XR_FB_foveation_configuration"
+
+typedef enum XrFoveationLevelFB {
+    XR_FOVEATION_LEVEL_NONE_FB = 0,
+    XR_FOVEATION_LEVEL_LOW_FB = 1,
+    XR_FOVEATION_LEVEL_MEDIUM_FB = 2,
+    XR_FOVEATION_LEVEL_HIGH_FB = 3,
+    XR_FOVEATION_LEVEL_MAX_ENUM_FB = 0x7FFFFFFF
+} XrFoveationLevelFB;
+
+typedef enum XrFoveationDynamicFB {
+    XR_FOVEATION_DYNAMIC_DISABLED_FB = 0,
+    XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB = 1,
+    XR_FOVEATION_DYNAMIC_MAX_ENUM_FB = 0x7FFFFFFF
+} XrFoveationDynamicFB;
+// XrFoveationLevelProfileCreateInfoFB extends XrFoveationProfileCreateInfoFB
+typedef struct XrFoveationLevelProfileCreateInfoFB {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    XrFoveationLevelFB      level;
+    float                   verticalOffset;
+    XrFoveationDynamicFB    dynamic;
+} XrFoveationLevelProfileCreateInfoFB;
+
+
+
+#define XR_FB_keyboard_tracking 1
+#define XR_FB_keyboard_tracking_SPEC_VERSION 1
+#define XR_FB_KEYBOARD_TRACKING_EXTENSION_NAME "XR_FB_keyboard_tracking"
+#define XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB 128
+typedef XrFlags64 XrKeyboardTrackingFlagsFB;
+
+// Flag bits for XrKeyboardTrackingFlagsFB
+static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_EXISTS_BIT_FB = 0x00000001;
+static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_LOCAL_BIT_FB = 0x00000002;
+static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_REMOTE_BIT_FB = 0x00000004;
+static const XrKeyboardTrackingFlagsFB XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB = 0x00000008;
+
+typedef XrFlags64 XrKeyboardTrackingQueryFlagsFB;
+
+// Flag bits for XrKeyboardTrackingQueryFlagsFB
+static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB = 0x00000002;
+static const XrKeyboardTrackingQueryFlagsFB XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB = 0x00000004;
+
+// XrSystemKeyboardTrackingPropertiesFB extends XrSystemProperties
+typedef struct XrSystemKeyboardTrackingPropertiesFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsKeyboardTracking;
+} XrSystemKeyboardTrackingPropertiesFB;
+
+typedef struct XrKeyboardTrackingDescriptionFB {
+    uint64_t                     trackedKeyboardId;
+    XrVector3f                   size;
+    XrKeyboardTrackingFlagsFB    flags;
+    char                         name[XR_MAX_KEYBOARD_TRACKING_NAME_SIZE_FB];
+} XrKeyboardTrackingDescriptionFB;
+
+typedef struct XrKeyboardSpaceCreateInfoFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint64_t              trackedKeyboardId;
+} XrKeyboardSpaceCreateInfoFB;
+
+typedef struct XrKeyboardTrackingQueryFB {
+    XrStructureType                   type;
+    void* XR_MAY_ALIAS                next;
+    XrKeyboardTrackingQueryFlagsFB    flags;
+} XrKeyboardTrackingQueryFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrQuerySystemTrackedKeyboardFB)(XrSession session, const XrKeyboardTrackingQueryFB* queryInfo, XrKeyboardTrackingDescriptionFB* keyboard);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateKeyboardSpaceFB)(XrSession session, const XrKeyboardSpaceCreateInfoFB* createInfo, XrSpace* keyboardSpace);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrQuerySystemTrackedKeyboardFB(
+    XrSession                                   session,
+    const XrKeyboardTrackingQueryFB*            queryInfo,
+    XrKeyboardTrackingDescriptionFB*            keyboard);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateKeyboardSpaceFB(
+    XrSession                                   session,
+    const XrKeyboardSpaceCreateInfoFB*          createInfo,
+    XrSpace*                                    keyboardSpace);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_triangle_mesh 1
+XR_DEFINE_HANDLE(XrTriangleMeshFB)
+#define XR_FB_triangle_mesh_SPEC_VERSION  1
+#define XR_FB_TRIANGLE_MESH_EXTENSION_NAME "XR_FB_triangle_mesh"
+
+typedef enum XrWindingOrderFB {
+    XR_WINDING_ORDER_UNKNOWN_FB = 0,
+    XR_WINDING_ORDER_CW_FB = 1,
+    XR_WINDING_ORDER_CCW_FB = 2,
+    XR_WINDING_ORDER_MAX_ENUM_FB = 0x7FFFFFFF
+} XrWindingOrderFB;
+typedef XrFlags64 XrTriangleMeshFlagsFB;
+
+// Flag bits for XrTriangleMeshFlagsFB
+static const XrTriangleMeshFlagsFB XR_TRIANGLE_MESH_MUTABLE_BIT_FB = 0x00000001;
+
+typedef struct XrTriangleMeshCreateInfoFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrTriangleMeshFlagsFB       flags;
+    XrWindingOrderFB            windingOrder;
+    uint32_t                    vertexCount;
+    const XrVector3f*           vertexBuffer;
+    uint32_t                    triangleCount;
+    const uint32_t*             indexBuffer;
+} XrTriangleMeshCreateInfoFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateTriangleMeshFB)(XrSession session, const XrTriangleMeshCreateInfoFB* createInfo, XrTriangleMeshFB* outTriangleMesh);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyTriangleMeshFB)(XrTriangleMeshFB mesh);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetVertexBufferFB)(XrTriangleMeshFB mesh, XrVector3f** outVertexBuffer);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshGetIndexBufferFB)(XrTriangleMeshFB mesh, uint32_t** outIndexBuffer);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginUpdateFB)(XrTriangleMeshFB mesh);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndUpdateFB)(XrTriangleMeshFB mesh, uint32_t vertexCount, uint32_t triangleCount);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshBeginVertexBufferUpdateFB)(XrTriangleMeshFB mesh, uint32_t* outVertexCount);
+typedef XrResult (XRAPI_PTR *PFN_xrTriangleMeshEndVertexBufferUpdateFB)(XrTriangleMeshFB mesh);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateTriangleMeshFB(
+    XrSession                                   session,
+    const XrTriangleMeshCreateInfoFB*           createInfo,
+    XrTriangleMeshFB*                           outTriangleMesh);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyTriangleMeshFB(
+    XrTriangleMeshFB                            mesh);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetVertexBufferFB(
+    XrTriangleMeshFB                            mesh,
+    XrVector3f**                                outVertexBuffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshGetIndexBufferFB(
+    XrTriangleMeshFB                            mesh,
+    uint32_t**                                  outIndexBuffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginUpdateFB(
+    XrTriangleMeshFB                            mesh);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndUpdateFB(
+    XrTriangleMeshFB                            mesh,
+    uint32_t                                    vertexCount,
+    uint32_t                                    triangleCount);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshBeginVertexBufferUpdateFB(
+    XrTriangleMeshFB                            mesh,
+    uint32_t*                                   outVertexCount);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrTriangleMeshEndVertexBufferUpdateFB(
+    XrTriangleMeshFB                            mesh);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_passthrough 1
+XR_DEFINE_HANDLE(XrPassthroughFB)
+XR_DEFINE_HANDLE(XrPassthroughLayerFB)
+XR_DEFINE_HANDLE(XrGeometryInstanceFB)
+#define XR_FB_passthrough_SPEC_VERSION    1
+#define XR_FB_PASSTHROUGH_EXTENSION_NAME  "XR_FB_passthrough"
+#define XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB 256
+
+typedef enum XrPassthroughLayerPurposeFB {
+    XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB = 0,
+    XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB = 1,
+    XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB = 1000203001,
+    XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB = 0x7FFFFFFF
+} XrPassthroughLayerPurposeFB;
+typedef XrFlags64 XrPassthroughFlagsFB;
+
+// Flag bits for XrPassthroughFlagsFB
+static const XrPassthroughFlagsFB XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB = 0x00000001;
+
+typedef XrFlags64 XrPassthroughStateChangedFlagsFB;
+
+// Flag bits for XrPassthroughStateChangedFlagsFB
+static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB = 0x00000001;
+static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB = 0x00000002;
+static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB = 0x00000004;
+static const XrPassthroughStateChangedFlagsFB XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB = 0x00000008;
+
+// XrSystemPassthroughPropertiesFB extends XrSystemProperties
+typedef struct XrSystemPassthroughPropertiesFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrBool32                    supportsPassthrough;
+} XrSystemPassthroughPropertiesFB;
+
+typedef struct XrPassthroughCreateInfoFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrPassthroughFlagsFB        flags;
+} XrPassthroughCreateInfoFB;
+
+typedef struct XrPassthroughLayerCreateInfoFB {
+    XrStructureType                type;
+    const void* XR_MAY_ALIAS       next;
+    XrPassthroughFB                passthrough;
+    XrPassthroughFlagsFB           flags;
+    XrPassthroughLayerPurposeFB    purpose;
+} XrPassthroughLayerCreateInfoFB;
+
+// XrCompositionLayerPassthroughFB extends XrCompositionLayerBaseHeader
+typedef struct XrCompositionLayerPassthroughFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrCompositionLayerFlags     flags;
+    XrSpace                     space;
+    XrPassthroughLayerFB        layerHandle;
+} XrCompositionLayerPassthroughFB;
+
+typedef struct XrGeometryInstanceCreateInfoFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrPassthroughLayerFB        layer;
+    XrTriangleMeshFB            mesh;
+    XrSpace                     baseSpace;
+    XrPosef                     pose;
+    XrVector3f                  scale;
+} XrGeometryInstanceCreateInfoFB;
+
+typedef struct XrGeometryInstanceTransformFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrSpace                     baseSpace;
+    XrTime                      time;
+    XrPosef                     pose;
+    XrVector3f                  scale;
+} XrGeometryInstanceTransformFB;
+
+typedef struct XrPassthroughStyleFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    float                       textureOpacityFactor;
+    XrColor4f                   edgeColor;
+} XrPassthroughStyleFB;
+
+typedef struct XrPassthroughColorMapMonoToRgbaFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrColor4f                   textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
+} XrPassthroughColorMapMonoToRgbaFB;
+
+typedef struct XrPassthroughColorMapMonoToMonoFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint8_t                     textureColorMap[XR_PASSTHROUGH_COLOR_MAP_MONO_SIZE_FB];
+} XrPassthroughColorMapMonoToMonoFB;
+
+typedef struct XrEventDataPassthroughStateChangedFB {
+    XrStructureType                     type;
+    const void* XR_MAY_ALIAS            next;
+    XrPassthroughStateChangedFlagsFB    flags;
+} XrEventDataPassthroughStateChangedFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughFB)(XrSession session, const XrPassthroughCreateInfoFB* createInfo, XrPassthroughFB* outPassthrough);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughFB)(XrPassthroughFB passthrough);
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughStartFB)(XrPassthroughFB passthrough);
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughPauseFB)(XrPassthroughFB passthrough);
+typedef XrResult (XRAPI_PTR *PFN_xrCreatePassthroughLayerFB)(XrSession session, const XrPassthroughLayerCreateInfoFB* createInfo, XrPassthroughLayerFB* outLayer);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyPassthroughLayerFB)(XrPassthroughLayerFB layer);
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerPauseFB)(XrPassthroughLayerFB layer);
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerResumeFB)(XrPassthroughLayerFB layer);
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetStyleFB)(XrPassthroughLayerFB layer, const XrPassthroughStyleFB* style);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateGeometryInstanceFB)(XrSession session, const XrGeometryInstanceCreateInfoFB* createInfo, XrGeometryInstanceFB* outGeometryInstance);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroyGeometryInstanceFB)(XrGeometryInstanceFB instance);
+typedef XrResult (XRAPI_PTR *PFN_xrGeometryInstanceSetTransformFB)(XrGeometryInstanceFB instance, const XrGeometryInstanceTransformFB* transformation);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughFB(
+    XrSession                                   session,
+    const XrPassthroughCreateInfoFB*            createInfo,
+    XrPassthroughFB*                            outPassthrough);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughFB(
+    XrPassthroughFB                             passthrough);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughStartFB(
+    XrPassthroughFB                             passthrough);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughPauseFB(
+    XrPassthroughFB                             passthrough);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreatePassthroughLayerFB(
+    XrSession                                   session,
+    const XrPassthroughLayerCreateInfoFB*       createInfo,
+    XrPassthroughLayerFB*                       outLayer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyPassthroughLayerFB(
+    XrPassthroughLayerFB                        layer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerPauseFB(
+    XrPassthroughLayerFB                        layer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerResumeFB(
+    XrPassthroughLayerFB                        layer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetStyleFB(
+    XrPassthroughLayerFB                        layer,
+    const XrPassthroughStyleFB*                 style);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateGeometryInstanceFB(
+    XrSession                                   session,
+    const XrGeometryInstanceCreateInfoFB*       createInfo,
+    XrGeometryInstanceFB*                       outGeometryInstance);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroyGeometryInstanceFB(
+    XrGeometryInstanceFB                        instance);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGeometryInstanceSetTransformFB(
+    XrGeometryInstanceFB                        instance,
+    const XrGeometryInstanceTransformFB*        transformation);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_render_model 1
+
+#define XR_NULL_RENDER_MODEL_KEY_FB 0
+
+XR_DEFINE_ATOM(XrRenderModelKeyFB)
+#define XR_FB_render_model_SPEC_VERSION   1
+#define XR_FB_RENDER_MODEL_EXTENSION_NAME "XR_FB_render_model"
+#define XR_MAX_RENDER_MODEL_NAME_SIZE_FB  64
+typedef XrFlags64 XrRenderModelFlagsFB;
+
+// Flag bits for XrRenderModelFlagsFB
+
+typedef struct XrRenderModelPathInfoFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrPath                path;
+} XrRenderModelPathInfoFB;
+
+typedef struct XrRenderModelPropertiesFB {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    uint32_t                vendorId;
+    char                    modelName[XR_MAX_RENDER_MODEL_NAME_SIZE_FB];
+    XrRenderModelKeyFB      modelKey;
+    uint32_t                modelVersion;
+    XrRenderModelFlagsFB    flags;
+} XrRenderModelPropertiesFB;
+
+typedef struct XrRenderModelBufferFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              bufferCapacityInput;
+    uint32_t              bufferCountOutput;
+    uint8_t*              buffer;
+} XrRenderModelBufferFB;
+
+typedef struct XrRenderModelLoadInfoFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrRenderModelKeyFB    modelKey;
+} XrRenderModelLoadInfoFB;
+
+// XrSystemRenderModelPropertiesFB extends XrSystemProperties
+typedef struct XrSystemRenderModelPropertiesFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsRenderModelLoading;
+} XrSystemRenderModelPropertiesFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrEnumerateRenderModelPathsFB)(XrSession session, uint32_t pathCapacityInput, uint32_t* pathCountOutput, XrRenderModelPathInfoFB* paths);
+typedef XrResult (XRAPI_PTR *PFN_xrGetRenderModelPropertiesFB)(XrSession session, XrPath path, XrRenderModelPropertiesFB* properties);
+typedef XrResult (XRAPI_PTR *PFN_xrLoadRenderModelFB)(XrSession session, const XrRenderModelLoadInfoFB* info, XrRenderModelBufferFB* buffer);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumerateRenderModelPathsFB(
+    XrSession                                   session,
+    uint32_t                                    pathCapacityInput,
+    uint32_t*                                   pathCountOutput,
+    XrRenderModelPathInfoFB*                    paths);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetRenderModelPropertiesFB(
+    XrSession                                   session,
+    XrPath                                      path,
+    XrRenderModelPropertiesFB*                  properties);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLoadRenderModelFB(
+    XrSession                                   session,
+    const XrRenderModelLoadInfoFB*              info,
+    XrRenderModelBufferFB*                      buffer);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_VARJO_foveated_rendering 1
+#define XR_VARJO_foveated_rendering_SPEC_VERSION 2
+#define XR_VARJO_FOVEATED_RENDERING_EXTENSION_NAME "XR_VARJO_foveated_rendering"
+// XrViewLocateFoveatedRenderingVARJO extends XrViewLocateInfo
+typedef struct XrViewLocateFoveatedRenderingVARJO {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrBool32                    foveatedRenderingActive;
+} XrViewLocateFoveatedRenderingVARJO;
+
+// XrFoveatedViewConfigurationViewVARJO extends XrViewConfigurationView
+typedef struct XrFoveatedViewConfigurationViewVARJO {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              foveatedRenderingActive;
+} XrFoveatedViewConfigurationViewVARJO;
+
+// XrSystemFoveatedRenderingPropertiesVARJO extends XrSystemProperties
+typedef struct XrSystemFoveatedRenderingPropertiesVARJO {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsFoveatedRendering;
+} XrSystemFoveatedRenderingPropertiesVARJO;
+
+
+
+#define XR_VARJO_composition_layer_depth_test 1
+#define XR_VARJO_composition_layer_depth_test_SPEC_VERSION 2
+#define XR_VARJO_COMPOSITION_LAYER_DEPTH_TEST_EXTENSION_NAME "XR_VARJO_composition_layer_depth_test"
+// XrCompositionLayerDepthTestVARJO extends XrCompositionLayerProjection
+typedef struct XrCompositionLayerDepthTestVARJO {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    float                       depthTestRangeNearZ;
+    float                       depthTestRangeFarZ;
+} XrCompositionLayerDepthTestVARJO;
+
+
+
+#define XR_VARJO_environment_depth_estimation 1
+#define XR_VARJO_environment_depth_estimation_SPEC_VERSION 1
+#define XR_VARJO_ENVIRONMENT_DEPTH_ESTIMATION_EXTENSION_NAME "XR_VARJO_environment_depth_estimation"
+typedef XrResult (XRAPI_PTR *PFN_xrSetEnvironmentDepthEstimationVARJO)(XrSession session, XrBool32 enabled);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSetEnvironmentDepthEstimationVARJO(
+    XrSession                                   session,
+    XrBool32                                    enabled);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_VARJO_marker_tracking 1
+#define XR_VARJO_marker_tracking_SPEC_VERSION 1
+#define XR_VARJO_MARKER_TRACKING_EXTENSION_NAME "XR_VARJO_marker_tracking"
+// XrSystemMarkerTrackingPropertiesVARJO extends XrSystemProperties
+typedef struct XrSystemMarkerTrackingPropertiesVARJO {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              supportsMarkerTracking;
+} XrSystemMarkerTrackingPropertiesVARJO;
+
+typedef struct XrEventDataMarkerTrackingUpdateVARJO {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint64_t                    markerId;
+    XrBool32                    isActive;
+    XrBool32                    isPredicted;
+    XrTime                      time;
+} XrEventDataMarkerTrackingUpdateVARJO;
+
+typedef struct XrMarkerSpaceCreateInfoVARJO {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    uint64_t                    markerId;
+    XrPosef                     poseInMarkerSpace;
+} XrMarkerSpaceCreateInfoVARJO;
+
+typedef XrResult  (XRAPI_PTR *PFN_xrSetMarkerTrackingVARJO)(XrSession session, XrBool32  enabled);
+typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingTimeoutVARJO)(XrSession session, uint64_t markerId, XrDuration timeout);
+typedef XrResult (XRAPI_PTR *PFN_xrSetMarkerTrackingPredictionVARJO)(XrSession session, uint64_t markerId, XrBool32 enabled);
+typedef XrResult (XRAPI_PTR *PFN_xrGetMarkerSizeVARJO)(XrSession session, uint64_t markerId, XrExtent2Df* size);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateMarkerSpaceVARJO)(XrSession session, const XrMarkerSpaceCreateInfoVARJO* createInfo, XrSpace* space);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult  XRAPI_CALL xrSetMarkerTrackingVARJO(
+    XrSession                                   session,
+    XrBool32                                    enabled);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingTimeoutVARJO(
+    XrSession                                   session,
+    uint64_t                                    markerId,
+    XrDuration                                  timeout);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSetMarkerTrackingPredictionVARJO(
+    XrSession                                   session,
+    uint64_t                                    markerId,
+    XrBool32                                    enabled);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetMarkerSizeVARJO(
+    XrSession                                   session,
+    uint64_t                                    markerId,
+    XrExtent2Df*                                size);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateMarkerSpaceVARJO(
+    XrSession                                   session,
+    const XrMarkerSpaceCreateInfoVARJO*         createInfo,
+    XrSpace*                                    space);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_MSFT_spatial_anchor_persistence 1
+XR_DEFINE_HANDLE(XrSpatialAnchorStoreConnectionMSFT)
+#define XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT 256
+#define XR_MSFT_spatial_anchor_persistence_SPEC_VERSION 2
+#define XR_MSFT_SPATIAL_ANCHOR_PERSISTENCE_EXTENSION_NAME "XR_MSFT_spatial_anchor_persistence"
+typedef struct XrSpatialAnchorPersistenceNameMSFT {
+    char    name[XR_MAX_SPATIAL_ANCHOR_NAME_SIZE_MSFT];
+} XrSpatialAnchorPersistenceNameMSFT;
+
+typedef struct XrSpatialAnchorPersistenceInfoMSFT {
+    XrStructureType                       type;
+    const void* XR_MAY_ALIAS              next;
+    XrSpatialAnchorPersistenceNameMSFT    spatialAnchorPersistenceName;
+    XrSpatialAnchorMSFT                   spatialAnchor;
+} XrSpatialAnchorPersistenceInfoMSFT;
+
+typedef struct XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT {
+    XrStructureType                       type;
+    const void* XR_MAY_ALIAS              next;
+    XrSpatialAnchorStoreConnectionMSFT    spatialAnchorStore;
+    XrSpatialAnchorPersistenceNameMSFT    spatialAnchorPersistenceName;
+} XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT;
+
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorStoreConnectionMSFT)(XrSession session, XrSpatialAnchorStoreConnectionMSFT* spatialAnchorStore);
+typedef XrResult (XRAPI_PTR *PFN_xrDestroySpatialAnchorStoreConnectionMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore);
+typedef XrResult (XRAPI_PTR *PFN_xrPersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, const XrSpatialAnchorPersistenceInfoMSFT* spatialAnchorPersistenceInfo);
+typedef XrResult (XRAPI_PTR *PFN_xrEnumeratePersistedSpatialAnchorNamesMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore, uint32_t spatialAnchorNamesCapacityInput, uint32_t* spatialAnchorNamesCountOutput, XrSpatialAnchorPersistenceNameMSFT* persistedAnchorNames);
+typedef XrResult (XRAPI_PTR *PFN_xrCreateSpatialAnchorFromPersistedNameMSFT)(XrSession session, const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo, XrSpatialAnchorMSFT* spatialAnchor);
+typedef XrResult (XRAPI_PTR *PFN_xrUnpersistSpatialAnchorMSFT)(XrSpatialAnchorStoreConnectionMSFT        spatialAnchorStore, const XrSpatialAnchorPersistenceNameMSFT* spatialAnchorPersistenceName);
+typedef XrResult (XRAPI_PTR *PFN_xrClearSpatialAnchorStoreMSFT)(XrSpatialAnchorStoreConnectionMSFT spatialAnchorStore);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorStoreConnectionMSFT(
+    XrSession                                   session,
+    XrSpatialAnchorStoreConnectionMSFT*         spatialAnchorStore);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrDestroySpatialAnchorStoreConnectionMSFT(
+    XrSpatialAnchorStoreConnectionMSFT          spatialAnchorStore);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrPersistSpatialAnchorMSFT(
+    XrSpatialAnchorStoreConnectionMSFT          spatialAnchorStore,
+    const XrSpatialAnchorPersistenceInfoMSFT*   spatialAnchorPersistenceInfo);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrEnumeratePersistedSpatialAnchorNamesMSFT(
+    XrSpatialAnchorStoreConnectionMSFT          spatialAnchorStore,
+    uint32_t                                    spatialAnchorNamesCapacityInput,
+    uint32_t*                                   spatialAnchorNamesCountOutput,
+    XrSpatialAnchorPersistenceNameMSFT*         persistedAnchorNames);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSpatialAnchorFromPersistedNameMSFT(
+    XrSession                                   session,
+    const XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT* spatialAnchorCreateInfo,
+    XrSpatialAnchorMSFT*                        spatialAnchor);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrUnpersistSpatialAnchorMSFT(
+    XrSpatialAnchorStoreConnectionMSFT          spatialAnchorStore,
+    const XrSpatialAnchorPersistenceNameMSFT*   spatialAnchorPersistenceName);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrClearSpatialAnchorStoreMSFT(
+    XrSpatialAnchorStoreConnectionMSFT          spatialAnchorStore);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_space_warp 1
+#define XR_FB_space_warp_SPEC_VERSION     1
+#define XR_FB_SPACE_WARP_EXTENSION_NAME   "XR_FB_space_warp"
+typedef XrFlags64 XrCompositionLayerSpaceWarpInfoFlagsFB;
+
+// Flag bits for XrCompositionLayerSpaceWarpInfoFlagsFB
+
+// XrCompositionLayerSpaceWarpInfoFB extends XrCompositionLayerProjectionView
+typedef struct XrCompositionLayerSpaceWarpInfoFB {
+    XrStructureType                           type;
+    const void* XR_MAY_ALIAS                  next;
+    XrCompositionLayerSpaceWarpInfoFlagsFB    layerFlags;
+    XrSwapchainSubImage                       motionVectorSubImage;
+    XrPosef                                   appSpaceDeltaPose;
+    XrSwapchainSubImage                       depthSubImage;
+    float                                     minDepth;
+    float                                     maxDepth;
+    float                                     nearZ;
+    float                                     farZ;
+} XrCompositionLayerSpaceWarpInfoFB;
+
+// XrSystemSpaceWarpPropertiesFB extends XrSystemProperties
+typedef struct XrSystemSpaceWarpPropertiesFB {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    uint32_t              recommendedMotionVectorImageRectWidth;
+    uint32_t              recommendedMotionVectorImageRectHeight;
+} XrSystemSpaceWarpPropertiesFB;
+
+
+
+#define XR_ALMALENCE_digital_lens_control 1
+#define XR_ALMALENCE_digital_lens_control_SPEC_VERSION 1
+#define XR_ALMALENCE_DIGITAL_LENS_CONTROL_EXTENSION_NAME "XR_ALMALENCE_digital_lens_control"
+typedef XrFlags64 XrDigitalLensControlFlagsALMALENCE;
+
+// Flag bits for XrDigitalLensControlFlagsALMALENCE
+static const XrDigitalLensControlFlagsALMALENCE XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE = 0x00000001;
+
+typedef struct XrDigitalLensControlALMALENCE {
+    XrStructureType                       type;
+    const void* XR_MAY_ALIAS              next;
+    XrDigitalLensControlFlagsALMALENCE    flags;
+} XrDigitalLensControlALMALENCE;
+
+typedef XrResult (XRAPI_PTR *PFN_xrSetDigitalLensControlALMALENCE)(XrSession session, const XrDigitalLensControlALMALENCE* digitalLensControl);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrSetDigitalLensControlALMALENCE(
+    XrSession                                   session,
+    const XrDigitalLensControlALMALENCE*        digitalLensControl);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_FB_passthrough_keyboard_hands 1
+#define XR_FB_passthrough_keyboard_hands_SPEC_VERSION 1
+#define XR_FB_PASSTHROUGH_KEYBOARD_HANDS_EXTENSION_NAME "XR_FB_passthrough_keyboard_hands"
+typedef struct XrPassthroughKeyboardHandsIntensityFB {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    float                       leftHandIntensity;
+    float                       rightHandIntensity;
+} XrPassthroughKeyboardHandsIntensityFB;
+
+typedef XrResult (XRAPI_PTR *PFN_xrPassthroughLayerSetKeyboardHandsIntensityFB)(XrPassthroughLayerFB layer, const XrPassthroughKeyboardHandsIntensityFB* intensity);
+
+#ifndef XR_NO_PROTOTYPES
+#ifdef XR_EXTENSION_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrPassthroughLayerSetKeyboardHandsIntensityFB(
+    XrPassthroughLayerFB                        layer,
+    const XrPassthroughKeyboardHandsIntensityFB* intensity);
+#endif /* XR_EXTENSION_PROTOTYPES */
+#endif /* !XR_NO_PROTOTYPES */
+
+
+#define XR_EXT_uuid 1
+#define XR_EXT_uuid_SPEC_VERSION          1
+#define XR_EXT_UUID_EXTENSION_NAME        "XR_EXT_uuid"
+#define XR_UUID_SIZE_EXT                  16
+typedef struct XrUuidEXT {
+    uint8_t    data[XR_UUID_SIZE_EXT];
+} XrUuidEXT;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 675 - 0
thirdparty/openxr/include/openxr/openxr_platform.h

@@ -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

+ 110 - 0
thirdparty/openxr/include/openxr/openxr_platform_defines.h

@@ -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

+ 2746 - 0
thirdparty/openxr/include/openxr/openxr_reflection.h

@@ -0,0 +1,2746 @@
+#ifndef OPENXR_REFLECTION_H_
+#define OPENXR_REFLECTION_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"
+
+/*
+This file contains expansion macros (X Macros) for OpenXR enumerations and structures.
+Example of how to use expansion macros to make an enum-to-string function:
+
+#define XR_ENUM_CASE_STR(name, val) case name: return #name;
+#define XR_ENUM_STR(enumType)                         \
+    constexpr const char* XrEnumStr(enumType e) {     \
+        switch (e) {                                  \
+            XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) \
+            default: return "Unknown";                \
+        }                                             \
+    }                                                 \
+
+XR_ENUM_STR(XrResult);
+*/
+
+#define XR_LIST_ENUM_XrResult(_) \
+    _(XR_SUCCESS, 0) \
+    _(XR_TIMEOUT_EXPIRED, 1) \
+    _(XR_SESSION_LOSS_PENDING, 3) \
+    _(XR_EVENT_UNAVAILABLE, 4) \
+    _(XR_SPACE_BOUNDS_UNAVAILABLE, 7) \
+    _(XR_SESSION_NOT_FOCUSED, 8) \
+    _(XR_FRAME_DISCARDED, 9) \
+    _(XR_ERROR_VALIDATION_FAILURE, -1) \
+    _(XR_ERROR_RUNTIME_FAILURE, -2) \
+    _(XR_ERROR_OUT_OF_MEMORY, -3) \
+    _(XR_ERROR_API_VERSION_UNSUPPORTED, -4) \
+    _(XR_ERROR_INITIALIZATION_FAILED, -6) \
+    _(XR_ERROR_FUNCTION_UNSUPPORTED, -7) \
+    _(XR_ERROR_FEATURE_UNSUPPORTED, -8) \
+    _(XR_ERROR_EXTENSION_NOT_PRESENT, -9) \
+    _(XR_ERROR_LIMIT_REACHED, -10) \
+    _(XR_ERROR_SIZE_INSUFFICIENT, -11) \
+    _(XR_ERROR_HANDLE_INVALID, -12) \
+    _(XR_ERROR_INSTANCE_LOST, -13) \
+    _(XR_ERROR_SESSION_RUNNING, -14) \
+    _(XR_ERROR_SESSION_NOT_RUNNING, -16) \
+    _(XR_ERROR_SESSION_LOST, -17) \
+    _(XR_ERROR_SYSTEM_INVALID, -18) \
+    _(XR_ERROR_PATH_INVALID, -19) \
+    _(XR_ERROR_PATH_COUNT_EXCEEDED, -20) \
+    _(XR_ERROR_PATH_FORMAT_INVALID, -21) \
+    _(XR_ERROR_PATH_UNSUPPORTED, -22) \
+    _(XR_ERROR_LAYER_INVALID, -23) \
+    _(XR_ERROR_LAYER_LIMIT_EXCEEDED, -24) \
+    _(XR_ERROR_SWAPCHAIN_RECT_INVALID, -25) \
+    _(XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED, -26) \
+    _(XR_ERROR_ACTION_TYPE_MISMATCH, -27) \
+    _(XR_ERROR_SESSION_NOT_READY, -28) \
+    _(XR_ERROR_SESSION_NOT_STOPPING, -29) \
+    _(XR_ERROR_TIME_INVALID, -30) \
+    _(XR_ERROR_REFERENCE_SPACE_UNSUPPORTED, -31) \
+    _(XR_ERROR_FILE_ACCESS_ERROR, -32) \
+    _(XR_ERROR_FILE_CONTENTS_INVALID, -33) \
+    _(XR_ERROR_FORM_FACTOR_UNSUPPORTED, -34) \
+    _(XR_ERROR_FORM_FACTOR_UNAVAILABLE, -35) \
+    _(XR_ERROR_API_LAYER_NOT_PRESENT, -36) \
+    _(XR_ERROR_CALL_ORDER_INVALID, -37) \
+    _(XR_ERROR_GRAPHICS_DEVICE_INVALID, -38) \
+    _(XR_ERROR_POSE_INVALID, -39) \
+    _(XR_ERROR_INDEX_OUT_OF_RANGE, -40) \
+    _(XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED, -41) \
+    _(XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED, -42) \
+    _(XR_ERROR_NAME_DUPLICATED, -44) \
+    _(XR_ERROR_NAME_INVALID, -45) \
+    _(XR_ERROR_ACTIONSET_NOT_ATTACHED, -46) \
+    _(XR_ERROR_ACTIONSETS_ALREADY_ATTACHED, -47) \
+    _(XR_ERROR_LOCALIZED_NAME_DUPLICATED, -48) \
+    _(XR_ERROR_LOCALIZED_NAME_INVALID, -49) \
+    _(XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, -50) \
+    _(XR_ERROR_RUNTIME_UNAVAILABLE, -51) \
+    _(XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR, -1000003000) \
+    _(XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR, -1000003001) \
+    _(XR_ERROR_CREATE_SPATIAL_ANCHOR_FAILED_MSFT, -1000039001) \
+    _(XR_ERROR_SECONDARY_VIEW_CONFIGURATION_TYPE_NOT_ENABLED_MSFT, -1000053000) \
+    _(XR_ERROR_CONTROLLER_MODEL_KEY_INVALID_MSFT, -1000055000) \
+    _(XR_ERROR_REPROJECTION_MODE_UNSUPPORTED_MSFT, -1000066000) \
+    _(XR_ERROR_COMPUTE_NEW_SCENE_NOT_COMPLETED_MSFT, -1000097000) \
+    _(XR_ERROR_SCENE_COMPONENT_ID_INVALID_MSFT, -1000097001) \
+    _(XR_ERROR_SCENE_COMPONENT_TYPE_MISMATCH_MSFT, -1000097002) \
+    _(XR_ERROR_SCENE_MESH_BUFFER_ID_INVALID_MSFT, -1000097003) \
+    _(XR_ERROR_SCENE_COMPUTE_FEATURE_INCOMPATIBLE_MSFT, -1000097004) \
+    _(XR_ERROR_SCENE_COMPUTE_CONSISTENCY_MISMATCH_MSFT, -1000097005) \
+    _(XR_ERROR_DISPLAY_REFRESH_RATE_UNSUPPORTED_FB, -1000101000) \
+    _(XR_ERROR_COLOR_SPACE_UNSUPPORTED_FB, -1000108000) \
+    _(XR_ERROR_UNEXPECTED_STATE_PASSTHROUGH_FB, -1000118000) \
+    _(XR_ERROR_FEATURE_ALREADY_CREATED_PASSTHROUGH_FB, -1000118001) \
+    _(XR_ERROR_FEATURE_REQUIRED_PASSTHROUGH_FB, -1000118002) \
+    _(XR_ERROR_NOT_PERMITTED_PASSTHROUGH_FB, -1000118003) \
+    _(XR_ERROR_INSUFFICIENT_RESOURCES_PASSTHROUGH_FB, -1000118004) \
+    _(XR_ERROR_UNKNOWN_PASSTHROUGH_FB, -1000118050) \
+    _(XR_ERROR_RENDER_MODEL_KEY_INVALID_FB, -1000119000) \
+    _(XR_RENDER_MODEL_UNAVAILABLE_FB, 1000119020) \
+    _(XR_ERROR_MARKER_NOT_TRACKED_VARJO, -1000124000) \
+    _(XR_ERROR_MARKER_ID_INVALID_VARJO, -1000124001) \
+    _(XR_ERROR_SPATIAL_ANCHOR_NAME_NOT_FOUND_MSFT, -1000142001) \
+    _(XR_ERROR_SPATIAL_ANCHOR_NAME_INVALID_MSFT, -1000142002) \
+    _(XR_RESULT_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrStructureType(_) \
+    _(XR_TYPE_UNKNOWN, 0) \
+    _(XR_TYPE_API_LAYER_PROPERTIES, 1) \
+    _(XR_TYPE_EXTENSION_PROPERTIES, 2) \
+    _(XR_TYPE_INSTANCE_CREATE_INFO, 3) \
+    _(XR_TYPE_SYSTEM_GET_INFO, 4) \
+    _(XR_TYPE_SYSTEM_PROPERTIES, 5) \
+    _(XR_TYPE_VIEW_LOCATE_INFO, 6) \
+    _(XR_TYPE_VIEW, 7) \
+    _(XR_TYPE_SESSION_CREATE_INFO, 8) \
+    _(XR_TYPE_SWAPCHAIN_CREATE_INFO, 9) \
+    _(XR_TYPE_SESSION_BEGIN_INFO, 10) \
+    _(XR_TYPE_VIEW_STATE, 11) \
+    _(XR_TYPE_FRAME_END_INFO, 12) \
+    _(XR_TYPE_HAPTIC_VIBRATION, 13) \
+    _(XR_TYPE_EVENT_DATA_BUFFER, 16) \
+    _(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING, 17) \
+    _(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED, 18) \
+    _(XR_TYPE_ACTION_STATE_BOOLEAN, 23) \
+    _(XR_TYPE_ACTION_STATE_FLOAT, 24) \
+    _(XR_TYPE_ACTION_STATE_VECTOR2F, 25) \
+    _(XR_TYPE_ACTION_STATE_POSE, 27) \
+    _(XR_TYPE_ACTION_SET_CREATE_INFO, 28) \
+    _(XR_TYPE_ACTION_CREATE_INFO, 29) \
+    _(XR_TYPE_INSTANCE_PROPERTIES, 32) \
+    _(XR_TYPE_FRAME_WAIT_INFO, 33) \
+    _(XR_TYPE_COMPOSITION_LAYER_PROJECTION, 35) \
+    _(XR_TYPE_COMPOSITION_LAYER_QUAD, 36) \
+    _(XR_TYPE_REFERENCE_SPACE_CREATE_INFO, 37) \
+    _(XR_TYPE_ACTION_SPACE_CREATE_INFO, 38) \
+    _(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING, 40) \
+    _(XR_TYPE_VIEW_CONFIGURATION_VIEW, 41) \
+    _(XR_TYPE_SPACE_LOCATION, 42) \
+    _(XR_TYPE_SPACE_VELOCITY, 43) \
+    _(XR_TYPE_FRAME_STATE, 44) \
+    _(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES, 45) \
+    _(XR_TYPE_FRAME_BEGIN_INFO, 46) \
+    _(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW, 48) \
+    _(XR_TYPE_EVENT_DATA_EVENTS_LOST, 49) \
+    _(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING, 51) \
+    _(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED, 52) \
+    _(XR_TYPE_INTERACTION_PROFILE_STATE, 53) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, 55) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO, 56) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, 57) \
+    _(XR_TYPE_ACTION_STATE_GET_INFO, 58) \
+    _(XR_TYPE_HAPTIC_ACTION_INFO, 59) \
+    _(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO, 60) \
+    _(XR_TYPE_ACTIONS_SYNC_INFO, 61) \
+    _(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO, 62) \
+    _(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO, 63) \
+    _(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR, 1000006000) \
+    _(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR, 1000008000) \
+    _(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR, 1000010000) \
+    _(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR, 1000014000) \
+    _(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT, 1000015000) \
+    _(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR, 1000017000) \
+    _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR, 1000018000) \
+    _(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 1000019000) \
+    _(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT, 1000019001) \
+    _(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, 1000019002) \
+    _(XR_TYPE_DEBUG_UTILS_LABEL_EXT, 1000019003) \
+    _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, 1000023000) \
+    _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR, 1000023001) \
+    _(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR, 1000023002) \
+    _(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR, 1000023003) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR, 1000023004) \
+    _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR, 1000023005) \
+    _(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR, 1000024001) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR, 1000024002) \
+    _(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR, 1000024003) \
+    _(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR, 1000025000) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR, 1000025001) \
+    _(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR, 1000025002) \
+    _(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR, 1000027000) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR, 1000027001) \
+    _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR, 1000027002) \
+    _(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR, 1000028000) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR, 1000028001) \
+    _(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR, 1000028002) \
+    _(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT, 1000030000) \
+    _(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT, 1000030001) \
+    _(XR_TYPE_VISIBILITY_MASK_KHR, 1000031000) \
+    _(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR, 1000031001) \
+    _(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX, 1000033000) \
+    _(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX, 1000033003) \
+    _(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR, 1000034000) \
+    _(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT, 1000039000) \
+    _(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT, 1000039001) \
+    _(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB, 1000040000) \
+    _(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB, 1000041001) \
+    _(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT, 1000046000) \
+    _(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX, 1000048004) \
+    _(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT, 1000049000) \
+    _(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT, 1000051000) \
+    _(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT, 1000051001) \
+    _(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT, 1000051002) \
+    _(XR_TYPE_HAND_JOINT_LOCATIONS_EXT, 1000051003) \
+    _(XR_TYPE_HAND_JOINT_VELOCITIES_EXT, 1000051004) \
+    _(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT, 1000052000) \
+    _(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT, 1000052001) \
+    _(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT, 1000052002) \
+    _(XR_TYPE_HAND_MESH_MSFT, 1000052003) \
+    _(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT, 1000052004) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT, 1000053000) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT, 1000053001) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT, 1000053002) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT, 1000053003) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT, 1000053004) \
+    _(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT, 1000053005) \
+    _(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT, 1000055000) \
+    _(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT, 1000055001) \
+    _(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT, 1000055002) \
+    _(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT, 1000055003) \
+    _(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT, 1000055004) \
+    _(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC, 1000059000) \
+    _(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT, 1000063000) \
+    _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT, 1000066000) \
+    _(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT, 1000066001) \
+    _(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB, 1000070000) \
+    _(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB, 1000072000) \
+    _(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE, 1000079000) \
+    _(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT, 1000080000) \
+    _(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR, 1000089000) \
+    _(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, 1000090000) \
+    _(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, 1000090001) \
+    _(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, 1000090003) \
+    _(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR, 1000091000) \
+    _(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT, 1000097000) \
+    _(XR_TYPE_SCENE_CREATE_INFO_MSFT, 1000097001) \
+    _(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT, 1000097002) \
+    _(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT, 1000097003) \
+    _(XR_TYPE_SCENE_COMPONENTS_MSFT, 1000097004) \
+    _(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT, 1000097005) \
+    _(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT, 1000097006) \
+    _(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT, 1000097007) \
+    _(XR_TYPE_SCENE_OBJECTS_MSFT, 1000097008) \
+    _(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT, 1000097009) \
+    _(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT, 1000097010) \
+    _(XR_TYPE_SCENE_PLANES_MSFT, 1000097011) \
+    _(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT, 1000097012) \
+    _(XR_TYPE_SCENE_MESHES_MSFT, 1000097013) \
+    _(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT, 1000097014) \
+    _(XR_TYPE_SCENE_MESH_BUFFERS_MSFT, 1000097015) \
+    _(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT, 1000097016) \
+    _(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT, 1000097017) \
+    _(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT, 1000097018) \
+    _(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT, 1000098000) \
+    _(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT, 1000098001) \
+    _(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB, 1000101000) \
+    _(XR_TYPE_VIVE_TRACKER_PATHS_HTCX, 1000103000) \
+    _(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX, 1000103001) \
+    _(XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC, 1000104000) \
+    _(XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC, 1000104001) \
+    _(XR_TYPE_FACIAL_EXPRESSIONS_HTC, 1000104002) \
+    _(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB, 1000108000) \
+    _(XR_TYPE_HAND_TRACKING_MESH_FB, 1000110001) \
+    _(XR_TYPE_HAND_TRACKING_SCALE_FB, 1000110003) \
+    _(XR_TYPE_HAND_TRACKING_AIM_STATE_FB, 1000111001) \
+    _(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB, 1000112000) \
+    _(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB, 1000114000) \
+    _(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB, 1000114001) \
+    _(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB, 1000114002) \
+    _(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB, 1000115000) \
+    _(XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB, 1000116009) \
+    _(XR_TYPE_KEYBOARD_TRACKING_QUERY_FB, 1000116004) \
+    _(XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB, 1000116002) \
+    _(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB, 1000117001) \
+    _(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB, 1000118000) \
+    _(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB, 1000118001) \
+    _(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB, 1000118002) \
+    _(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB, 1000118003) \
+    _(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB, 1000118004) \
+    _(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB, 1000118005) \
+    _(XR_TYPE_PASSTHROUGH_STYLE_FB, 1000118020) \
+    _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB, 1000118021) \
+    _(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB, 1000118022) \
+    _(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB, 1000118030) \
+    _(XR_TYPE_RENDER_MODEL_PATH_INFO_FB, 1000119000) \
+    _(XR_TYPE_RENDER_MODEL_PROPERTIES_FB, 1000119001) \
+    _(XR_TYPE_RENDER_MODEL_BUFFER_FB, 1000119002) \
+    _(XR_TYPE_RENDER_MODEL_LOAD_INFO_FB, 1000119003) \
+    _(XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB, 1000119004) \
+    _(XR_TYPE_BINDING_MODIFICATIONS_KHR, 1000120000) \
+    _(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO, 1000121000) \
+    _(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO, 1000121001) \
+    _(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO, 1000121002) \
+    _(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO, 1000122000) \
+    _(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO, 1000124000) \
+    _(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO, 1000124001) \
+    _(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO, 1000124002) \
+    _(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT, 1000142000) \
+    _(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT, 1000142001) \
+    _(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB, 1000160000) \
+    _(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB, 1000161000) \
+    _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB, 1000162000) \
+    _(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB, 1000163000) \
+    _(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB, 1000171000) \
+    _(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB, 1000171001) \
+    _(XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE, 1000196000) \
+    _(XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB, 1000203002) \
+    _(XR_STRUCTURE_TYPE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFormFactor(_) \
+    _(XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY, 1) \
+    _(XR_FORM_FACTOR_HANDHELD_DISPLAY, 2) \
+    _(XR_FORM_FACTOR_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrViewConfigurationType(_) \
+    _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO, 1) \
+    _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, 2) \
+    _(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO, 1000037000) \
+    _(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT, 1000054000) \
+    _(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrEnvironmentBlendMode(_) \
+    _(XR_ENVIRONMENT_BLEND_MODE_OPAQUE, 1) \
+    _(XR_ENVIRONMENT_BLEND_MODE_ADDITIVE, 2) \
+    _(XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND, 3) \
+    _(XR_ENVIRONMENT_BLEND_MODE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrReferenceSpaceType(_) \
+    _(XR_REFERENCE_SPACE_TYPE_VIEW, 1) \
+    _(XR_REFERENCE_SPACE_TYPE_LOCAL, 2) \
+    _(XR_REFERENCE_SPACE_TYPE_STAGE, 3) \
+    _(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT, 1000038000) \
+    _(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO, 1000121000) \
+    _(XR_REFERENCE_SPACE_TYPE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrActionType(_) \
+    _(XR_ACTION_TYPE_BOOLEAN_INPUT, 1) \
+    _(XR_ACTION_TYPE_FLOAT_INPUT, 2) \
+    _(XR_ACTION_TYPE_VECTOR2F_INPUT, 3) \
+    _(XR_ACTION_TYPE_POSE_INPUT, 4) \
+    _(XR_ACTION_TYPE_VIBRATION_OUTPUT, 100) \
+    _(XR_ACTION_TYPE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrEyeVisibility(_) \
+    _(XR_EYE_VISIBILITY_BOTH, 0) \
+    _(XR_EYE_VISIBILITY_LEFT, 1) \
+    _(XR_EYE_VISIBILITY_RIGHT, 2) \
+    _(XR_EYE_VISIBILITY_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSessionState(_) \
+    _(XR_SESSION_STATE_UNKNOWN, 0) \
+    _(XR_SESSION_STATE_IDLE, 1) \
+    _(XR_SESSION_STATE_READY, 2) \
+    _(XR_SESSION_STATE_SYNCHRONIZED, 3) \
+    _(XR_SESSION_STATE_VISIBLE, 4) \
+    _(XR_SESSION_STATE_FOCUSED, 5) \
+    _(XR_SESSION_STATE_STOPPING, 6) \
+    _(XR_SESSION_STATE_LOSS_PENDING, 7) \
+    _(XR_SESSION_STATE_EXITING, 8) \
+    _(XR_SESSION_STATE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrObjectType(_) \
+    _(XR_OBJECT_TYPE_UNKNOWN, 0) \
+    _(XR_OBJECT_TYPE_INSTANCE, 1) \
+    _(XR_OBJECT_TYPE_SESSION, 2) \
+    _(XR_OBJECT_TYPE_SWAPCHAIN, 3) \
+    _(XR_OBJECT_TYPE_SPACE, 4) \
+    _(XR_OBJECT_TYPE_ACTION_SET, 5) \
+    _(XR_OBJECT_TYPE_ACTION, 6) \
+    _(XR_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, 1000019000) \
+    _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_MSFT, 1000039000) \
+    _(XR_OBJECT_TYPE_HAND_TRACKER_EXT, 1000051000) \
+    _(XR_OBJECT_TYPE_SCENE_OBSERVER_MSFT, 1000097000) \
+    _(XR_OBJECT_TYPE_SCENE_MSFT, 1000097001) \
+    _(XR_OBJECT_TYPE_FACIAL_TRACKER_HTC, 1000104000) \
+    _(XR_OBJECT_TYPE_FOVEATION_PROFILE_FB, 1000114000) \
+    _(XR_OBJECT_TYPE_TRIANGLE_MESH_FB, 1000117000) \
+    _(XR_OBJECT_TYPE_PASSTHROUGH_FB, 1000118000) \
+    _(XR_OBJECT_TYPE_PASSTHROUGH_LAYER_FB, 1000118002) \
+    _(XR_OBJECT_TYPE_GEOMETRY_INSTANCE_FB, 1000118004) \
+    _(XR_OBJECT_TYPE_SPATIAL_ANCHOR_STORE_CONNECTION_MSFT, 1000142000) \
+    _(XR_OBJECT_TYPE_MAX_ENUM, 0x7FFFFFFF)
+
+#define XR_LIST_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)
+
+#define XR_LIST_ENUM_XrVisibilityMaskTypeKHR(_) \
+    _(XR_VISIBILITY_MASK_TYPE_HIDDEN_TRIANGLE_MESH_KHR, 1) \
+    _(XR_VISIBILITY_MASK_TYPE_VISIBLE_TRIANGLE_MESH_KHR, 2) \
+    _(XR_VISIBILITY_MASK_TYPE_LINE_LOOP_KHR, 3) \
+    _(XR_VISIBILITY_MASK_TYPE_MAX_ENUM_KHR, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPerfSettingsDomainEXT(_) \
+    _(XR_PERF_SETTINGS_DOMAIN_CPU_EXT, 1) \
+    _(XR_PERF_SETTINGS_DOMAIN_GPU_EXT, 2) \
+    _(XR_PERF_SETTINGS_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPerfSettingsSubDomainEXT(_) \
+    _(XR_PERF_SETTINGS_SUB_DOMAIN_COMPOSITING_EXT, 1) \
+    _(XR_PERF_SETTINGS_SUB_DOMAIN_RENDERING_EXT, 2) \
+    _(XR_PERF_SETTINGS_SUB_DOMAIN_THERMAL_EXT, 3) \
+    _(XR_PERF_SETTINGS_SUB_DOMAIN_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPerfSettingsLevelEXT(_) \
+    _(XR_PERF_SETTINGS_LEVEL_POWER_SAVINGS_EXT, 0) \
+    _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_LOW_EXT, 25) \
+    _(XR_PERF_SETTINGS_LEVEL_SUSTAINED_HIGH_EXT, 50) \
+    _(XR_PERF_SETTINGS_LEVEL_BOOST_EXT, 75) \
+    _(XR_PERF_SETTINGS_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPerfSettingsNotificationLevelEXT(_) \
+    _(XR_PERF_SETTINGS_NOTIF_LEVEL_NORMAL_EXT, 0) \
+    _(XR_PERF_SETTINGS_NOTIF_LEVEL_WARNING_EXT, 25) \
+    _(XR_PERF_SETTINGS_NOTIF_LEVEL_IMPAIRED_EXT, 75) \
+    _(XR_PERF_SETTINGS_NOTIFICATION_LEVEL_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrBlendFactorFB(_) \
+    _(XR_BLEND_FACTOR_ZERO_FB, 0) \
+    _(XR_BLEND_FACTOR_ONE_FB, 1) \
+    _(XR_BLEND_FACTOR_SRC_ALPHA_FB, 2) \
+    _(XR_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA_FB, 3) \
+    _(XR_BLEND_FACTOR_DST_ALPHA_FB, 4) \
+    _(XR_BLEND_FACTOR_ONE_MINUS_DST_ALPHA_FB, 5) \
+    _(XR_BLEND_FACTOR_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSpatialGraphNodeTypeMSFT(_) \
+    _(XR_SPATIAL_GRAPH_NODE_TYPE_STATIC_MSFT, 1) \
+    _(XR_SPATIAL_GRAPH_NODE_TYPE_DYNAMIC_MSFT, 2) \
+    _(XR_SPATIAL_GRAPH_NODE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandEXT(_) \
+    _(XR_HAND_LEFT_EXT, 1) \
+    _(XR_HAND_RIGHT_EXT, 2) \
+    _(XR_HAND_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandJointEXT(_) \
+    _(XR_HAND_JOINT_PALM_EXT, 0) \
+    _(XR_HAND_JOINT_WRIST_EXT, 1) \
+    _(XR_HAND_JOINT_THUMB_METACARPAL_EXT, 2) \
+    _(XR_HAND_JOINT_THUMB_PROXIMAL_EXT, 3) \
+    _(XR_HAND_JOINT_THUMB_DISTAL_EXT, 4) \
+    _(XR_HAND_JOINT_THUMB_TIP_EXT, 5) \
+    _(XR_HAND_JOINT_INDEX_METACARPAL_EXT, 6) \
+    _(XR_HAND_JOINT_INDEX_PROXIMAL_EXT, 7) \
+    _(XR_HAND_JOINT_INDEX_INTERMEDIATE_EXT, 8) \
+    _(XR_HAND_JOINT_INDEX_DISTAL_EXT, 9) \
+    _(XR_HAND_JOINT_INDEX_TIP_EXT, 10) \
+    _(XR_HAND_JOINT_MIDDLE_METACARPAL_EXT, 11) \
+    _(XR_HAND_JOINT_MIDDLE_PROXIMAL_EXT, 12) \
+    _(XR_HAND_JOINT_MIDDLE_INTERMEDIATE_EXT, 13) \
+    _(XR_HAND_JOINT_MIDDLE_DISTAL_EXT, 14) \
+    _(XR_HAND_JOINT_MIDDLE_TIP_EXT, 15) \
+    _(XR_HAND_JOINT_RING_METACARPAL_EXT, 16) \
+    _(XR_HAND_JOINT_RING_PROXIMAL_EXT, 17) \
+    _(XR_HAND_JOINT_RING_INTERMEDIATE_EXT, 18) \
+    _(XR_HAND_JOINT_RING_DISTAL_EXT, 19) \
+    _(XR_HAND_JOINT_RING_TIP_EXT, 20) \
+    _(XR_HAND_JOINT_LITTLE_METACARPAL_EXT, 21) \
+    _(XR_HAND_JOINT_LITTLE_PROXIMAL_EXT, 22) \
+    _(XR_HAND_JOINT_LITTLE_INTERMEDIATE_EXT, 23) \
+    _(XR_HAND_JOINT_LITTLE_DISTAL_EXT, 24) \
+    _(XR_HAND_JOINT_LITTLE_TIP_EXT, 25) \
+    _(XR_HAND_JOINT_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandJointSetEXT(_) \
+    _(XR_HAND_JOINT_SET_DEFAULT_EXT, 0) \
+    _(XR_HAND_JOINT_SET_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandPoseTypeMSFT(_) \
+    _(XR_HAND_POSE_TYPE_TRACKED_MSFT, 0) \
+    _(XR_HAND_POSE_TYPE_REFERENCE_OPEN_PALM_MSFT, 1) \
+    _(XR_HAND_POSE_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrReprojectionModeMSFT(_) \
+    _(XR_REPROJECTION_MODE_DEPTH_MSFT, 1) \
+    _(XR_REPROJECTION_MODE_PLANAR_FROM_DEPTH_MSFT, 2) \
+    _(XR_REPROJECTION_MODE_PLANAR_MANUAL_MSFT, 3) \
+    _(XR_REPROJECTION_MODE_ORIENTATION_ONLY_MSFT, 4) \
+    _(XR_REPROJECTION_MODE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrHandJointsMotionRangeEXT(_) \
+    _(XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT, 1) \
+    _(XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT, 2) \
+    _(XR_HAND_JOINTS_MOTION_RANGE_MAX_ENUM_EXT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSceneComputeFeatureMSFT(_) \
+    _(XR_SCENE_COMPUTE_FEATURE_PLANE_MSFT, 1) \
+    _(XR_SCENE_COMPUTE_FEATURE_PLANE_MESH_MSFT, 2) \
+    _(XR_SCENE_COMPUTE_FEATURE_VISUAL_MESH_MSFT, 3) \
+    _(XR_SCENE_COMPUTE_FEATURE_COLLIDER_MESH_MSFT, 4) \
+    _(XR_SCENE_COMPUTE_FEATURE_SERIALIZE_SCENE_MSFT, 1000098000) \
+    _(XR_SCENE_COMPUTE_FEATURE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSceneComputeConsistencyMSFT(_) \
+    _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_COMPLETE_MSFT, 1) \
+    _(XR_SCENE_COMPUTE_CONSISTENCY_SNAPSHOT_INCOMPLETE_FAST_MSFT, 2) \
+    _(XR_SCENE_COMPUTE_CONSISTENCY_OCCLUSION_OPTIMIZED_MSFT, 3) \
+    _(XR_SCENE_COMPUTE_CONSISTENCY_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrMeshComputeLodMSFT(_) \
+    _(XR_MESH_COMPUTE_LOD_COARSE_MSFT, 1) \
+    _(XR_MESH_COMPUTE_LOD_MEDIUM_MSFT, 2) \
+    _(XR_MESH_COMPUTE_LOD_FINE_MSFT, 3) \
+    _(XR_MESH_COMPUTE_LOD_UNLIMITED_MSFT, 4) \
+    _(XR_MESH_COMPUTE_LOD_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSceneComponentTypeMSFT(_) \
+    _(XR_SCENE_COMPONENT_TYPE_INVALID_MSFT, -1) \
+    _(XR_SCENE_COMPONENT_TYPE_OBJECT_MSFT, 1) \
+    _(XR_SCENE_COMPONENT_TYPE_PLANE_MSFT, 2) \
+    _(XR_SCENE_COMPONENT_TYPE_VISUAL_MESH_MSFT, 3) \
+    _(XR_SCENE_COMPONENT_TYPE_COLLIDER_MESH_MSFT, 4) \
+    _(XR_SCENE_COMPONENT_TYPE_SERIALIZED_SCENE_FRAGMENT_MSFT, 1000098000) \
+    _(XR_SCENE_COMPONENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSceneObjectTypeMSFT(_) \
+    _(XR_SCENE_OBJECT_TYPE_UNCATEGORIZED_MSFT, -1) \
+    _(XR_SCENE_OBJECT_TYPE_BACKGROUND_MSFT, 1) \
+    _(XR_SCENE_OBJECT_TYPE_WALL_MSFT, 2) \
+    _(XR_SCENE_OBJECT_TYPE_FLOOR_MSFT, 3) \
+    _(XR_SCENE_OBJECT_TYPE_CEILING_MSFT, 4) \
+    _(XR_SCENE_OBJECT_TYPE_PLATFORM_MSFT, 5) \
+    _(XR_SCENE_OBJECT_TYPE_INFERRED_MSFT, 6) \
+    _(XR_SCENE_OBJECT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrScenePlaneAlignmentTypeMSFT(_) \
+    _(XR_SCENE_PLANE_ALIGNMENT_TYPE_NON_ORTHOGONAL_MSFT, 0) \
+    _(XR_SCENE_PLANE_ALIGNMENT_TYPE_HORIZONTAL_MSFT, 1) \
+    _(XR_SCENE_PLANE_ALIGNMENT_TYPE_VERTICAL_MSFT, 2) \
+    _(XR_SCENE_PLANE_ALIGNMENT_TYPE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrSceneComputeStateMSFT(_) \
+    _(XR_SCENE_COMPUTE_STATE_NONE_MSFT, 0) \
+    _(XR_SCENE_COMPUTE_STATE_UPDATING_MSFT, 1) \
+    _(XR_SCENE_COMPUTE_STATE_COMPLETED_MSFT, 2) \
+    _(XR_SCENE_COMPUTE_STATE_COMPLETED_WITH_ERROR_MSFT, 3) \
+    _(XR_SCENE_COMPUTE_STATE_MAX_ENUM_MSFT, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrEyeExpressionHTC(_) \
+    _(XR_EYE_EXPRESSION_LEFT_BLINK_HTC, 0) \
+    _(XR_EYE_EXPRESSION_LEFT_WIDE_HTC, 1) \
+    _(XR_EYE_EXPRESSION_RIGHT_BLINK_HTC, 2) \
+    _(XR_EYE_EXPRESSION_RIGHT_WIDE_HTC, 3) \
+    _(XR_EYE_EXPRESSION_LEFT_SQUEEZE_HTC, 4) \
+    _(XR_EYE_EXPRESSION_RIGHT_SQUEEZE_HTC, 5) \
+    _(XR_EYE_EXPRESSION_LEFT_DOWN_HTC, 6) \
+    _(XR_EYE_EXPRESSION_RIGHT_DOWN_HTC, 7) \
+    _(XR_EYE_EXPRESSION_LEFT_OUT_HTC, 8) \
+    _(XR_EYE_EXPRESSION_RIGHT_IN_HTC, 9) \
+    _(XR_EYE_EXPRESSION_LEFT_IN_HTC, 10) \
+    _(XR_EYE_EXPRESSION_RIGHT_OUT_HTC, 11) \
+    _(XR_EYE_EXPRESSION_LEFT_UP_HTC, 12) \
+    _(XR_EYE_EXPRESSION_RIGHT_UP_HTC, 13) \
+    _(XR_EYE_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrLipExpressionHTC(_) \
+    _(XR_LIP_EXPRESSION_JAW_RIGHT_HTC, 0) \
+    _(XR_LIP_EXPRESSION_JAW_LEFT_HTC, 1) \
+    _(XR_LIP_EXPRESSION_JAW_FORWARD_HTC, 2) \
+    _(XR_LIP_EXPRESSION_JAW_OPEN_HTC, 3) \
+    _(XR_LIP_EXPRESSION_MOUTH_APE_SHAPE_HTC, 4) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_RIGHT_HTC, 5) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_LEFT_HTC, 6) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_RIGHT_HTC, 7) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_LEFT_HTC, 8) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_OVERTURN_HTC, 9) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERTURN_HTC, 10) \
+    _(XR_LIP_EXPRESSION_MOUTH_POUT_HTC, 11) \
+    _(XR_LIP_EXPRESSION_MOUTH_SMILE_RIGHT_HTC, 12) \
+    _(XR_LIP_EXPRESSION_MOUTH_SMILE_LEFT_HTC, 13) \
+    _(XR_LIP_EXPRESSION_MOUTH_SAD_RIGHT_HTC, 14) \
+    _(XR_LIP_EXPRESSION_MOUTH_SAD_LEFT_HTC, 15) \
+    _(XR_LIP_EXPRESSION_CHEEK_PUFF_RIGHT_HTC, 16) \
+    _(XR_LIP_EXPRESSION_CHEEK_PUFF_LEFT_HTC, 17) \
+    _(XR_LIP_EXPRESSION_CHEEK_SUCK_HTC, 18) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPRIGHT_HTC, 19) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_UPLEFT_HTC, 20) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNRIGHT_HTC, 21) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_DOWNLEFT_HTC, 22) \
+    _(XR_LIP_EXPRESSION_MOUTH_UPPER_INSIDE_HTC, 23) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_INSIDE_HTC, 24) \
+    _(XR_LIP_EXPRESSION_MOUTH_LOWER_OVERLAY_HTC, 25) \
+    _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP1_HTC, 26) \
+    _(XR_LIP_EXPRESSION_TONGUE_LEFT_HTC, 27) \
+    _(XR_LIP_EXPRESSION_TONGUE_RIGHT_HTC, 28) \
+    _(XR_LIP_EXPRESSION_TONGUE_UP_HTC, 29) \
+    _(XR_LIP_EXPRESSION_TONGUE_DOWN_HTC, 30) \
+    _(XR_LIP_EXPRESSION_TONGUE_ROLL_HTC, 31) \
+    _(XR_LIP_EXPRESSION_TONGUE_LONGSTEP2_HTC, 32) \
+    _(XR_LIP_EXPRESSION_TONGUE_UPRIGHT_MORPH_HTC, 33) \
+    _(XR_LIP_EXPRESSION_TONGUE_UPLEFT_MORPH_HTC, 34) \
+    _(XR_LIP_EXPRESSION_TONGUE_DOWNRIGHT_MORPH_HTC, 35) \
+    _(XR_LIP_EXPRESSION_TONGUE_DOWNLEFT_MORPH_HTC, 36) \
+    _(XR_LIP_EXPRESSION_MAX_ENUM_HTC, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFacialTrackingTypeHTC(_) \
+    _(XR_FACIAL_TRACKING_TYPE_EYE_DEFAULT_HTC, 1) \
+    _(XR_FACIAL_TRACKING_TYPE_LIP_DEFAULT_HTC, 2) \
+    _(XR_FACIAL_TRACKING_TYPE_MAX_ENUM_HTC, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrColorSpaceFB(_) \
+    _(XR_COLOR_SPACE_UNMANAGED_FB, 0) \
+    _(XR_COLOR_SPACE_REC2020_FB, 1) \
+    _(XR_COLOR_SPACE_REC709_FB, 2) \
+    _(XR_COLOR_SPACE_RIFT_CV1_FB, 3) \
+    _(XR_COLOR_SPACE_RIFT_S_FB, 4) \
+    _(XR_COLOR_SPACE_QUEST_FB, 5) \
+    _(XR_COLOR_SPACE_P3_FB, 6) \
+    _(XR_COLOR_SPACE_ADOBE_RGB_FB, 7) \
+    _(XR_COLOR_SPACE_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFoveationLevelFB(_) \
+    _(XR_FOVEATION_LEVEL_NONE_FB, 0) \
+    _(XR_FOVEATION_LEVEL_LOW_FB, 1) \
+    _(XR_FOVEATION_LEVEL_MEDIUM_FB, 2) \
+    _(XR_FOVEATION_LEVEL_HIGH_FB, 3) \
+    _(XR_FOVEATION_LEVEL_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrFoveationDynamicFB(_) \
+    _(XR_FOVEATION_DYNAMIC_DISABLED_FB, 0) \
+    _(XR_FOVEATION_DYNAMIC_LEVEL_ENABLED_FB, 1) \
+    _(XR_FOVEATION_DYNAMIC_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrWindingOrderFB(_) \
+    _(XR_WINDING_ORDER_UNKNOWN_FB, 0) \
+    _(XR_WINDING_ORDER_CW_FB, 1) \
+    _(XR_WINDING_ORDER_CCW_FB, 2) \
+    _(XR_WINDING_ORDER_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_ENUM_XrPassthroughLayerPurposeFB(_) \
+    _(XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB, 0) \
+    _(XR_PASSTHROUGH_LAYER_PURPOSE_PROJECTED_FB, 1) \
+    _(XR_PASSTHROUGH_LAYER_PURPOSE_TRACKED_KEYBOARD_HANDS_FB, 1000203001) \
+    _(XR_PASSTHROUGH_LAYER_PURPOSE_MAX_ENUM_FB, 0x7FFFFFFF)
+
+#define XR_LIST_BITS_XrInstanceCreateFlags(_)
+
+#define XR_LIST_BITS_XrSessionCreateFlags(_)
+
+#define XR_LIST_BITS_XrSpaceVelocityFlags(_) \
+    _(XR_SPACE_VELOCITY_LINEAR_VALID_BIT, 0x00000001) \
+    _(XR_SPACE_VELOCITY_ANGULAR_VALID_BIT, 0x00000002) \
+
+#define XR_LIST_BITS_XrSpaceLocationFlags(_) \
+    _(XR_SPACE_LOCATION_ORIENTATION_VALID_BIT, 0x00000001) \
+    _(XR_SPACE_LOCATION_POSITION_VALID_BIT, 0x00000002) \
+    _(XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT, 0x00000004) \
+    _(XR_SPACE_LOCATION_POSITION_TRACKED_BIT, 0x00000008) \
+
+#define XR_LIST_BITS_XrSwapchainCreateFlags(_) \
+    _(XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT, 0x00000001) \
+    _(XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT, 0x00000002) \
+
+#define XR_LIST_BITS_XrSwapchainUsageFlags(_) \
+    _(XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, 0x00000001) \
+    _(XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, 0x00000002) \
+    _(XR_SWAPCHAIN_USAGE_UNORDERED_ACCESS_BIT, 0x00000004) \
+    _(XR_SWAPCHAIN_USAGE_TRANSFER_SRC_BIT, 0x00000008) \
+    _(XR_SWAPCHAIN_USAGE_TRANSFER_DST_BIT, 0x00000010) \
+    _(XR_SWAPCHAIN_USAGE_SAMPLED_BIT, 0x00000020) \
+    _(XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, 0x00000040) \
+    _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND, 0x00000080) \
+    _(XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_KHR, XR_SWAPCHAIN_USAGE_INPUT_ATTACHMENT_BIT_MND) \
+
+#define XR_LIST_BITS_XrCompositionLayerFlags(_) \
+    _(XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, 0x00000001) \
+    _(XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT, 0x00000002) \
+    _(XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT, 0x00000004) \
+
+#define XR_LIST_BITS_XrViewStateFlags(_) \
+    _(XR_VIEW_STATE_ORIENTATION_VALID_BIT, 0x00000001) \
+    _(XR_VIEW_STATE_POSITION_VALID_BIT, 0x00000002) \
+    _(XR_VIEW_STATE_ORIENTATION_TRACKED_BIT, 0x00000004) \
+    _(XR_VIEW_STATE_POSITION_TRACKED_BIT, 0x00000008) \
+
+#define XR_LIST_BITS_XrInputSourceLocalizedNameFlags(_) \
+    _(XR_INPUT_SOURCE_LOCALIZED_NAME_USER_PATH_BIT, 0x00000001) \
+    _(XR_INPUT_SOURCE_LOCALIZED_NAME_INTERACTION_PROFILE_BIT, 0x00000002) \
+    _(XR_INPUT_SOURCE_LOCALIZED_NAME_COMPONENT_BIT, 0x00000004) \
+
+#define XR_LIST_BITS_XrVulkanInstanceCreateFlagsKHR(_)
+
+#define XR_LIST_BITS_XrVulkanDeviceCreateFlagsKHR(_)
+
+#define XR_LIST_BITS_XrDebugUtilsMessageSeverityFlagsEXT(_) \
+    _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, 0x00000001) \
+    _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, 0x00000010) \
+    _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, 0x00000100) \
+    _(XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, 0x00001000) \
+
+#define XR_LIST_BITS_XrDebugUtilsMessageTypeFlagsEXT(_) \
+    _(XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, 0x00000001) \
+    _(XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, 0x00000002) \
+    _(XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, 0x00000004) \
+    _(XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT, 0x00000008) \
+
+#define XR_LIST_BITS_XrOverlaySessionCreateFlagsEXTX(_)
+
+#define XR_LIST_BITS_XrOverlayMainSessionFlagsEXTX(_) \
+    _(XR_OVERLAY_MAIN_SESSION_ENABLED_COMPOSITION_LAYER_INFO_DEPTH_BIT_EXTX, 0x00000001) \
+
+#define XR_LIST_BITS_XrCompositionLayerImageLayoutFlagsFB(_) \
+    _(XR_COMPOSITION_LAYER_IMAGE_LAYOUT_VERTICAL_FLIP_BIT_FB, 0x00000001) \
+
+#define XR_LIST_BITS_XrAndroidSurfaceSwapchainFlagsFB(_) \
+    _(XR_ANDROID_SURFACE_SWAPCHAIN_SYNCHRONOUS_BIT_FB, 0x00000001) \
+    _(XR_ANDROID_SURFACE_SWAPCHAIN_USE_TIMESTAMPS_BIT_FB, 0x00000002) \
+
+#define XR_LIST_BITS_XrCompositionLayerSecureContentFlagsFB(_) \
+    _(XR_COMPOSITION_LAYER_SECURE_CONTENT_EXCLUDE_LAYER_BIT_FB, 0x00000001) \
+    _(XR_COMPOSITION_LAYER_SECURE_CONTENT_REPLACE_LAYER_BIT_FB, 0x00000002) \
+
+#define XR_LIST_BITS_XrHandTrackingAimFlagsFB(_) \
+    _(XR_HAND_TRACKING_AIM_COMPUTED_BIT_FB, 0x00000001) \
+    _(XR_HAND_TRACKING_AIM_VALID_BIT_FB, 0x00000002) \
+    _(XR_HAND_TRACKING_AIM_INDEX_PINCHING_BIT_FB, 0x00000004) \
+    _(XR_HAND_TRACKING_AIM_MIDDLE_PINCHING_BIT_FB, 0x00000008) \
+    _(XR_HAND_TRACKING_AIM_RING_PINCHING_BIT_FB, 0x00000010) \
+    _(XR_HAND_TRACKING_AIM_LITTLE_PINCHING_BIT_FB, 0x00000020) \
+    _(XR_HAND_TRACKING_AIM_SYSTEM_GESTURE_BIT_FB, 0x00000040) \
+    _(XR_HAND_TRACKING_AIM_DOMINANT_HAND_BIT_FB, 0x00000080) \
+    _(XR_HAND_TRACKING_AIM_MENU_PRESSED_BIT_FB, 0x00000100) \
+
+#define XR_LIST_BITS_XrSwapchainCreateFoveationFlagsFB(_) \
+    _(XR_SWAPCHAIN_CREATE_FOVEATION_SCALED_BIN_BIT_FB, 0x00000001) \
+    _(XR_SWAPCHAIN_CREATE_FOVEATION_FRAGMENT_DENSITY_MAP_BIT_FB, 0x00000002) \
+
+#define XR_LIST_BITS_XrSwapchainStateFoveationFlagsFB(_)
+
+#define XR_LIST_BITS_XrKeyboardTrackingFlagsFB(_) \
+    _(XR_KEYBOARD_TRACKING_EXISTS_BIT_FB, 0x00000001) \
+    _(XR_KEYBOARD_TRACKING_LOCAL_BIT_FB, 0x00000002) \
+    _(XR_KEYBOARD_TRACKING_REMOTE_BIT_FB, 0x00000004) \
+    _(XR_KEYBOARD_TRACKING_CONNECTED_BIT_FB, 0x00000008) \
+
+#define XR_LIST_BITS_XrKeyboardTrackingQueryFlagsFB(_) \
+    _(XR_KEYBOARD_TRACKING_QUERY_LOCAL_BIT_FB, 0x00000002) \
+    _(XR_KEYBOARD_TRACKING_QUERY_REMOTE_BIT_FB, 0x00000004) \
+
+#define XR_LIST_BITS_XrTriangleMeshFlagsFB(_) \
+    _(XR_TRIANGLE_MESH_MUTABLE_BIT_FB, 0x00000001) \
+
+#define XR_LIST_BITS_XrPassthroughFlagsFB(_) \
+    _(XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB, 0x00000001) \
+
+#define XR_LIST_BITS_XrPassthroughStateChangedFlagsFB(_) \
+    _(XR_PASSTHROUGH_STATE_CHANGED_REINIT_REQUIRED_BIT_FB, 0x00000001) \
+    _(XR_PASSTHROUGH_STATE_CHANGED_NON_RECOVERABLE_ERROR_BIT_FB, 0x00000002) \
+    _(XR_PASSTHROUGH_STATE_CHANGED_RECOVERABLE_ERROR_BIT_FB, 0x00000004) \
+    _(XR_PASSTHROUGH_STATE_CHANGED_RESTORED_ERROR_BIT_FB, 0x00000008) \
+
+#define XR_LIST_BITS_XrRenderModelFlagsFB(_)
+
+#define XR_LIST_BITS_XrCompositionLayerSpaceWarpInfoFlagsFB(_)
+
+#define XR_LIST_BITS_XrDigitalLensControlFlagsALMALENCE(_) \
+    _(XR_DIGITAL_LENS_CONTROL_PROCESSING_DISABLE_BIT_ALMALENCE, 0x00000001) \
+
+#define XR_LIST_STRUCT_XrApiLayerProperties(_) \
+    _(type) \
+    _(next) \
+    _(layerName) \
+    _(specVersion) \
+    _(layerVersion) \
+    _(description) \
+
+#define XR_LIST_STRUCT_XrExtensionProperties(_) \
+    _(type) \
+    _(next) \
+    _(extensionName) \
+    _(extensionVersion) \
+
+#define XR_LIST_STRUCT_XrApplicationInfo(_) \
+    _(applicationName) \
+    _(applicationVersion) \
+    _(engineName) \
+    _(engineVersion) \
+    _(apiVersion) \
+
+#define XR_LIST_STRUCT_XrInstanceCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(createFlags) \
+    _(applicationInfo) \
+    _(enabledApiLayerCount) \
+    _(enabledApiLayerNames) \
+    _(enabledExtensionCount) \
+    _(enabledExtensionNames) \
+
+#define XR_LIST_STRUCT_XrInstanceProperties(_) \
+    _(type) \
+    _(next) \
+    _(runtimeVersion) \
+    _(runtimeName) \
+
+#define XR_LIST_STRUCT_XrEventDataBuffer(_) \
+    _(type) \
+    _(next) \
+    _(varying) \
+
+#define XR_LIST_STRUCT_XrSystemGetInfo(_) \
+    _(type) \
+    _(next) \
+    _(formFactor) \
+
+#define XR_LIST_STRUCT_XrSystemGraphicsProperties(_) \
+    _(maxSwapchainImageHeight) \
+    _(maxSwapchainImageWidth) \
+    _(maxLayerCount) \
+
+#define XR_LIST_STRUCT_XrSystemTrackingProperties(_) \
+    _(orientationTracking) \
+    _(positionTracking) \
+
+#define XR_LIST_STRUCT_XrSystemProperties(_) \
+    _(type) \
+    _(next) \
+    _(systemId) \
+    _(vendorId) \
+    _(systemName) \
+    _(graphicsProperties) \
+    _(trackingProperties) \
+
+#define XR_LIST_STRUCT_XrSessionCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(createFlags) \
+    _(systemId) \
+
+#define XR_LIST_STRUCT_XrVector3f(_) \
+    _(x) \
+    _(y) \
+    _(z) \
+
+#define XR_LIST_STRUCT_XrSpaceVelocity(_) \
+    _(type) \
+    _(next) \
+    _(velocityFlags) \
+    _(linearVelocity) \
+    _(angularVelocity) \
+
+#define XR_LIST_STRUCT_XrQuaternionf(_) \
+    _(x) \
+    _(y) \
+    _(z) \
+    _(w) \
+
+#define XR_LIST_STRUCT_XrPosef(_) \
+    _(orientation) \
+    _(position) \
+
+#define XR_LIST_STRUCT_XrReferenceSpaceCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(referenceSpaceType) \
+    _(poseInReferenceSpace) \
+
+#define XR_LIST_STRUCT_XrExtent2Df(_) \
+    _(width) \
+    _(height) \
+
+#define XR_LIST_STRUCT_XrActionSpaceCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(action) \
+    _(subactionPath) \
+    _(poseInActionSpace) \
+
+#define XR_LIST_STRUCT_XrSpaceLocation(_) \
+    _(type) \
+    _(next) \
+    _(locationFlags) \
+    _(pose) \
+
+#define XR_LIST_STRUCT_XrViewConfigurationProperties(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationType) \
+    _(fovMutable) \
+
+#define XR_LIST_STRUCT_XrViewConfigurationView(_) \
+    _(type) \
+    _(next) \
+    _(recommendedImageRectWidth) \
+    _(maxImageRectWidth) \
+    _(recommendedImageRectHeight) \
+    _(maxImageRectHeight) \
+    _(recommendedSwapchainSampleCount) \
+    _(maxSwapchainSampleCount) \
+
+#define XR_LIST_STRUCT_XrSwapchainCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(createFlags) \
+    _(usageFlags) \
+    _(format) \
+    _(sampleCount) \
+    _(width) \
+    _(height) \
+    _(faceCount) \
+    _(arraySize) \
+    _(mipCount) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageBaseHeader(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageAcquireInfo(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageWaitInfo(_) \
+    _(type) \
+    _(next) \
+    _(timeout) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageReleaseInfo(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSessionBeginInfo(_) \
+    _(type) \
+    _(next) \
+    _(primaryViewConfigurationType) \
+
+#define XR_LIST_STRUCT_XrFrameWaitInfo(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrFrameState(_) \
+    _(type) \
+    _(next) \
+    _(predictedDisplayTime) \
+    _(predictedDisplayPeriod) \
+    _(shouldRender) \
+
+#define XR_LIST_STRUCT_XrFrameBeginInfo(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerBaseHeader(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+
+#define XR_LIST_STRUCT_XrFrameEndInfo(_) \
+    _(type) \
+    _(next) \
+    _(displayTime) \
+    _(environmentBlendMode) \
+    _(layerCount) \
+    _(layers) \
+
+#define XR_LIST_STRUCT_XrViewLocateInfo(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationType) \
+    _(displayTime) \
+    _(space) \
+
+#define XR_LIST_STRUCT_XrViewState(_) \
+    _(type) \
+    _(next) \
+    _(viewStateFlags) \
+
+#define XR_LIST_STRUCT_XrFovf(_) \
+    _(angleLeft) \
+    _(angleRight) \
+    _(angleUp) \
+    _(angleDown) \
+
+#define XR_LIST_STRUCT_XrView(_) \
+    _(type) \
+    _(next) \
+    _(pose) \
+    _(fov) \
+
+#define XR_LIST_STRUCT_XrActionSetCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(actionSetName) \
+    _(localizedActionSetName) \
+    _(priority) \
+
+#define XR_LIST_STRUCT_XrActionCreateInfo(_) \
+    _(type) \
+    _(next) \
+    _(actionName) \
+    _(actionType) \
+    _(countSubactionPaths) \
+    _(subactionPaths) \
+    _(localizedActionName) \
+
+#define XR_LIST_STRUCT_XrActionSuggestedBinding(_) \
+    _(action) \
+    _(binding) \
+
+#define XR_LIST_STRUCT_XrInteractionProfileSuggestedBinding(_) \
+    _(type) \
+    _(next) \
+    _(interactionProfile) \
+    _(countSuggestedBindings) \
+    _(suggestedBindings) \
+
+#define XR_LIST_STRUCT_XrSessionActionSetsAttachInfo(_) \
+    _(type) \
+    _(next) \
+    _(countActionSets) \
+    _(actionSets) \
+
+#define XR_LIST_STRUCT_XrInteractionProfileState(_) \
+    _(type) \
+    _(next) \
+    _(interactionProfile) \
+
+#define XR_LIST_STRUCT_XrActionStateGetInfo(_) \
+    _(type) \
+    _(next) \
+    _(action) \
+    _(subactionPath) \
+
+#define XR_LIST_STRUCT_XrActionStateBoolean(_) \
+    _(type) \
+    _(next) \
+    _(currentState) \
+    _(changedSinceLastSync) \
+    _(lastChangeTime) \
+    _(isActive) \
+
+#define XR_LIST_STRUCT_XrActionStateFloat(_) \
+    _(type) \
+    _(next) \
+    _(currentState) \
+    _(changedSinceLastSync) \
+    _(lastChangeTime) \
+    _(isActive) \
+
+#define XR_LIST_STRUCT_XrVector2f(_) \
+    _(x) \
+    _(y) \
+
+#define XR_LIST_STRUCT_XrActionStateVector2f(_) \
+    _(type) \
+    _(next) \
+    _(currentState) \
+    _(changedSinceLastSync) \
+    _(lastChangeTime) \
+    _(isActive) \
+
+#define XR_LIST_STRUCT_XrActionStatePose(_) \
+    _(type) \
+    _(next) \
+    _(isActive) \
+
+#define XR_LIST_STRUCT_XrActiveActionSet(_) \
+    _(actionSet) \
+    _(subactionPath) \
+
+#define XR_LIST_STRUCT_XrActionsSyncInfo(_) \
+    _(type) \
+    _(next) \
+    _(countActiveActionSets) \
+    _(activeActionSets) \
+
+#define XR_LIST_STRUCT_XrBoundSourcesForActionEnumerateInfo(_) \
+    _(type) \
+    _(next) \
+    _(action) \
+
+#define XR_LIST_STRUCT_XrInputSourceLocalizedNameGetInfo(_) \
+    _(type) \
+    _(next) \
+    _(sourcePath) \
+    _(whichComponents) \
+
+#define XR_LIST_STRUCT_XrHapticActionInfo(_) \
+    _(type) \
+    _(next) \
+    _(action) \
+    _(subactionPath) \
+
+#define XR_LIST_STRUCT_XrHapticBaseHeader(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrBaseInStructure(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrBaseOutStructure(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrOffset2Di(_) \
+    _(x) \
+    _(y) \
+
+#define XR_LIST_STRUCT_XrExtent2Di(_) \
+    _(width) \
+    _(height) \
+
+#define XR_LIST_STRUCT_XrRect2Di(_) \
+    _(offset) \
+    _(extent) \
+
+#define XR_LIST_STRUCT_XrSwapchainSubImage(_) \
+    _(swapchain) \
+    _(imageRect) \
+    _(imageArrayIndex) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerProjectionView(_) \
+    _(type) \
+    _(next) \
+    _(pose) \
+    _(fov) \
+    _(subImage) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerProjection(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(viewCount) \
+    _(views) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerQuad(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(eyeVisibility) \
+    _(subImage) \
+    _(pose) \
+    _(size) \
+
+#define XR_LIST_STRUCT_XrEventDataBaseHeader(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrEventDataEventsLost(_) \
+    _(type) \
+    _(next) \
+    _(lostEventCount) \
+
+#define XR_LIST_STRUCT_XrEventDataInstanceLossPending(_) \
+    _(type) \
+    _(next) \
+    _(lossTime) \
+
+#define XR_LIST_STRUCT_XrEventDataSessionStateChanged(_) \
+    _(type) \
+    _(next) \
+    _(session) \
+    _(state) \
+    _(time) \
+
+#define XR_LIST_STRUCT_XrEventDataReferenceSpaceChangePending(_) \
+    _(type) \
+    _(next) \
+    _(session) \
+    _(referenceSpaceType) \
+    _(changeTime) \
+    _(poseValid) \
+    _(poseInPreviousSpace) \
+
+#define XR_LIST_STRUCT_XrEventDataInteractionProfileChanged(_) \
+    _(type) \
+    _(next) \
+    _(session) \
+
+#define XR_LIST_STRUCT_XrHapticVibration(_) \
+    _(type) \
+    _(next) \
+    _(duration) \
+    _(frequency) \
+    _(amplitude) \
+
+#define XR_LIST_STRUCT_XrOffset2Df(_) \
+    _(x) \
+    _(y) \
+
+#define XR_LIST_STRUCT_XrRect2Df(_) \
+    _(offset) \
+    _(extent) \
+
+#define XR_LIST_STRUCT_XrVector4f(_) \
+    _(x) \
+    _(y) \
+    _(z) \
+    _(w) \
+
+#define XR_LIST_STRUCT_XrColor4f(_) \
+    _(r) \
+    _(g) \
+    _(b) \
+    _(a) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerCubeKHR(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(eyeVisibility) \
+    _(swapchain) \
+    _(imageArrayIndex) \
+    _(orientation) \
+
+#define XR_LIST_STRUCT_XrInstanceCreateInfoAndroidKHR(_) \
+    _(type) \
+    _(next) \
+    _(applicationVM) \
+    _(applicationActivity) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerDepthInfoKHR(_) \
+    _(type) \
+    _(next) \
+    _(subImage) \
+    _(minDepth) \
+    _(maxDepth) \
+    _(nearZ) \
+    _(farZ) \
+
+#define XR_LIST_STRUCT_XrVulkanSwapchainFormatListCreateInfoKHR(_) \
+    _(type) \
+    _(next) \
+    _(viewFormatCount) \
+    _(viewFormats) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerCylinderKHR(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(eyeVisibility) \
+    _(subImage) \
+    _(pose) \
+    _(radius) \
+    _(centralAngle) \
+    _(aspectRatio) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerEquirectKHR(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(eyeVisibility) \
+    _(subImage) \
+    _(pose) \
+    _(radius) \
+    _(scale) \
+    _(bias) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWin32KHR(_) \
+    _(type) \
+    _(next) \
+    _(hDC) \
+    _(hGLRC) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXlibKHR(_) \
+    _(type) \
+    _(next) \
+    _(xDisplay) \
+    _(visualid) \
+    _(glxFBConfig) \
+    _(glxDrawable) \
+    _(glxContext) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLXcbKHR(_) \
+    _(type) \
+    _(next) \
+    _(connection) \
+    _(screenNumber) \
+    _(fbconfigid) \
+    _(visualid) \
+    _(glxDrawable) \
+    _(glxContext) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLWaylandKHR(_) \
+    _(type) \
+    _(next) \
+    _(display) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageOpenGLKHR(_) \
+    _(type) \
+    _(next) \
+    _(image) \
+
+#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLKHR(_) \
+    _(type) \
+    _(next) \
+    _(minApiVersionSupported) \
+    _(maxApiVersionSupported) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingOpenGLESAndroidKHR(_) \
+    _(type) \
+    _(next) \
+    _(display) \
+    _(config) \
+    _(context) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageOpenGLESKHR(_) \
+    _(type) \
+    _(next) \
+    _(image) \
+
+#define XR_LIST_STRUCT_XrGraphicsRequirementsOpenGLESKHR(_) \
+    _(type) \
+    _(next) \
+    _(minApiVersionSupported) \
+    _(maxApiVersionSupported) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingVulkanKHR(_) \
+    _(type) \
+    _(next) \
+    _(instance) \
+    _(physicalDevice) \
+    _(device) \
+    _(queueFamilyIndex) \
+    _(queueIndex) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageVulkanKHR(_) \
+    _(type) \
+    _(next) \
+    _(image) \
+
+#define XR_LIST_STRUCT_XrGraphicsRequirementsVulkanKHR(_) \
+    _(type) \
+    _(next) \
+    _(minApiVersionSupported) \
+    _(maxApiVersionSupported) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingD3D11KHR(_) \
+    _(type) \
+    _(next) \
+    _(device) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageD3D11KHR(_) \
+    _(type) \
+    _(next) \
+    _(texture) \
+
+#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D11KHR(_) \
+    _(type) \
+    _(next) \
+    _(adapterLuid) \
+    _(minFeatureLevel) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingD3D12KHR(_) \
+    _(type) \
+    _(next) \
+    _(device) \
+    _(queue) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageD3D12KHR(_) \
+    _(type) \
+    _(next) \
+    _(texture) \
+
+#define XR_LIST_STRUCT_XrGraphicsRequirementsD3D12KHR(_) \
+    _(type) \
+    _(next) \
+    _(adapterLuid) \
+    _(minFeatureLevel) \
+
+#define XR_LIST_STRUCT_XrVisibilityMaskKHR(_) \
+    _(type) \
+    _(next) \
+    _(vertexCapacityInput) \
+    _(vertexCountOutput) \
+    _(vertices) \
+    _(indexCapacityInput) \
+    _(indexCountOutput) \
+    _(indices) \
+
+#define XR_LIST_STRUCT_XrEventDataVisibilityMaskChangedKHR(_) \
+    _(type) \
+    _(next) \
+    _(session) \
+    _(viewConfigurationType) \
+    _(viewIndex) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerColorScaleBiasKHR(_) \
+    _(type) \
+    _(next) \
+    _(colorScale) \
+    _(colorBias) \
+
+#define XR_LIST_STRUCT_XrLoaderInitInfoBaseHeaderKHR(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrLoaderInitInfoAndroidKHR(_) \
+    _(type) \
+    _(next) \
+    _(applicationVM) \
+    _(applicationContext) \
+
+#define XR_LIST_STRUCT_XrVulkanInstanceCreateInfoKHR(_) \
+    _(type) \
+    _(next) \
+    _(systemId) \
+    _(createFlags) \
+    _(pfnGetInstanceProcAddr) \
+    _(vulkanCreateInfo) \
+    _(vulkanAllocator) \
+
+#define XR_LIST_STRUCT_XrVulkanDeviceCreateInfoKHR(_) \
+    _(type) \
+    _(next) \
+    _(systemId) \
+    _(createFlags) \
+    _(pfnGetInstanceProcAddr) \
+    _(vulkanPhysicalDevice) \
+    _(vulkanCreateInfo) \
+    _(vulkanAllocator) \
+
+#define XR_LIST_STRUCT_XrVulkanGraphicsDeviceGetInfoKHR(_) \
+    _(type) \
+    _(next) \
+    _(systemId) \
+    _(vulkanInstance) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerEquirect2KHR(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(space) \
+    _(eyeVisibility) \
+    _(subImage) \
+    _(pose) \
+    _(radius) \
+    _(centralHorizontalAngle) \
+    _(upperVerticalAngle) \
+    _(lowerVerticalAngle) \
+
+#define XR_LIST_STRUCT_XrBindingModificationBaseHeaderKHR(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrBindingModificationsKHR(_) \
+    _(type) \
+    _(next) \
+    _(bindingModificationCount) \
+    _(bindingModifications) \
+
+#define XR_LIST_STRUCT_XrEventDataPerfSettingsEXT(_) \
+    _(type) \
+    _(next) \
+    _(domain) \
+    _(subDomain) \
+    _(fromLevel) \
+    _(toLevel) \
+
+#define XR_LIST_STRUCT_XrDebugUtilsObjectNameInfoEXT(_) \
+    _(type) \
+    _(next) \
+    _(objectType) \
+    _(objectHandle) \
+    _(objectName) \
+
+#define XR_LIST_STRUCT_XrDebugUtilsLabelEXT(_) \
+    _(type) \
+    _(next) \
+    _(labelName) \
+
+#define XR_LIST_STRUCT_XrDebugUtilsMessengerCallbackDataEXT(_) \
+    _(type) \
+    _(next) \
+    _(messageId) \
+    _(functionName) \
+    _(message) \
+    _(objectCount) \
+    _(objects) \
+    _(sessionLabelCount) \
+    _(sessionLabels) \
+
+#define XR_LIST_STRUCT_XrDebugUtilsMessengerCreateInfoEXT(_) \
+    _(type) \
+    _(next) \
+    _(messageSeverities) \
+    _(messageTypes) \
+    _(userCallback) \
+    _(userData) \
+
+#define XR_LIST_STRUCT_XrSystemEyeGazeInteractionPropertiesEXT(_) \
+    _(type) \
+    _(next) \
+    _(supportsEyeGazeInteraction) \
+
+#define XR_LIST_STRUCT_XrEyeGazeSampleTimeEXT(_) \
+    _(type) \
+    _(next) \
+    _(time) \
+
+#define XR_LIST_STRUCT_XrSessionCreateInfoOverlayEXTX(_) \
+    _(type) \
+    _(next) \
+    _(createFlags) \
+    _(sessionLayersPlacement) \
+
+#define XR_LIST_STRUCT_XrEventDataMainSessionVisibilityChangedEXTX(_) \
+    _(type) \
+    _(next) \
+    _(visible) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrSpatialAnchorCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(space) \
+    _(pose) \
+    _(time) \
+
+#define XR_LIST_STRUCT_XrSpatialAnchorSpaceCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(anchor) \
+    _(poseInAnchorSpace) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerImageLayoutFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerAlphaBlendFB(_) \
+    _(type) \
+    _(next) \
+    _(srcFactorColor) \
+    _(dstFactorColor) \
+    _(srcFactorAlpha) \
+    _(dstFactorAlpha) \
+
+#define XR_LIST_STRUCT_XrViewConfigurationDepthRangeEXT(_) \
+    _(type) \
+    _(next) \
+    _(recommendedNearZ) \
+    _(minNearZ) \
+    _(recommendedFarZ) \
+    _(maxFarZ) \
+
+#define XR_LIST_STRUCT_XrGraphicsBindingEGLMNDX(_) \
+    _(type) \
+    _(next) \
+    _(getProcAddress) \
+    _(display) \
+    _(config) \
+    _(context) \
+
+#define XR_LIST_STRUCT_XrSpatialGraphNodeSpaceCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(nodeType) \
+    _(nodeId) \
+    _(pose) \
+
+#define XR_LIST_STRUCT_XrSystemHandTrackingPropertiesEXT(_) \
+    _(type) \
+    _(next) \
+    _(supportsHandTracking) \
+
+#define XR_LIST_STRUCT_XrHandTrackerCreateInfoEXT(_) \
+    _(type) \
+    _(next) \
+    _(hand) \
+    _(handJointSet) \
+
+#define XR_LIST_STRUCT_XrHandJointsLocateInfoEXT(_) \
+    _(type) \
+    _(next) \
+    _(baseSpace) \
+    _(time) \
+
+#define XR_LIST_STRUCT_XrHandJointLocationEXT(_) \
+    _(locationFlags) \
+    _(pose) \
+    _(radius) \
+
+#define XR_LIST_STRUCT_XrHandJointVelocityEXT(_) \
+    _(velocityFlags) \
+    _(linearVelocity) \
+    _(angularVelocity) \
+
+#define XR_LIST_STRUCT_XrHandJointLocationsEXT(_) \
+    _(type) \
+    _(next) \
+    _(isActive) \
+    _(jointCount) \
+    _(jointLocations) \
+
+#define XR_LIST_STRUCT_XrHandJointVelocitiesEXT(_) \
+    _(type) \
+    _(next) \
+    _(jointCount) \
+    _(jointVelocities) \
+
+#define XR_LIST_STRUCT_XrSystemHandTrackingMeshPropertiesMSFT(_) \
+    _(type) \
+    _(next) \
+    _(supportsHandTrackingMesh) \
+    _(maxHandMeshIndexCount) \
+    _(maxHandMeshVertexCount) \
+
+#define XR_LIST_STRUCT_XrHandMeshSpaceCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(handPoseType) \
+    _(poseInHandMeshSpace) \
+
+#define XR_LIST_STRUCT_XrHandMeshUpdateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(time) \
+    _(handPoseType) \
+
+#define XR_LIST_STRUCT_XrHandMeshIndexBufferMSFT(_) \
+    _(indexBufferKey) \
+    _(indexCapacityInput) \
+    _(indexCountOutput) \
+    _(indices) \
+
+#define XR_LIST_STRUCT_XrHandMeshVertexMSFT(_) \
+    _(position) \
+    _(normal) \
+
+#define XR_LIST_STRUCT_XrHandMeshVertexBufferMSFT(_) \
+    _(vertexUpdateTime) \
+    _(vertexCapacityInput) \
+    _(vertexCountOutput) \
+    _(vertices) \
+
+#define XR_LIST_STRUCT_XrHandMeshMSFT(_) \
+    _(type) \
+    _(next) \
+    _(isActive) \
+    _(indexBufferChanged) \
+    _(vertexBufferChanged) \
+    _(indexBuffer) \
+    _(vertexBuffer) \
+
+#define XR_LIST_STRUCT_XrHandPoseTypeInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(handPoseType) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSessionBeginInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationCount) \
+    _(enabledViewConfigurationTypes) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationStateMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationType) \
+    _(active) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameStateMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationCount) \
+    _(viewConfigurationStates) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationLayerInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationType) \
+    _(environmentBlendMode) \
+    _(layerCount) \
+    _(layers) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationFrameEndInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationCount) \
+    _(viewConfigurationLayersInfo) \
+
+#define XR_LIST_STRUCT_XrSecondaryViewConfigurationSwapchainCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(viewConfigurationType) \
+
+#define XR_LIST_STRUCT_XrControllerModelKeyStateMSFT(_) \
+    _(type) \
+    _(next) \
+    _(modelKey) \
+
+#define XR_LIST_STRUCT_XrControllerModelNodePropertiesMSFT(_) \
+    _(type) \
+    _(next) \
+    _(parentNodeName) \
+    _(nodeName) \
+
+#define XR_LIST_STRUCT_XrControllerModelPropertiesMSFT(_) \
+    _(type) \
+    _(next) \
+    _(nodeCapacityInput) \
+    _(nodeCountOutput) \
+    _(nodeProperties) \
+
+#define XR_LIST_STRUCT_XrControllerModelNodeStateMSFT(_) \
+    _(type) \
+    _(next) \
+    _(nodePose) \
+
+#define XR_LIST_STRUCT_XrControllerModelStateMSFT(_) \
+    _(type) \
+    _(next) \
+    _(nodeCapacityInput) \
+    _(nodeCountOutput) \
+    _(nodeStates) \
+
+#define XR_LIST_STRUCT_XrViewConfigurationViewFovEPIC(_) \
+    _(type) \
+    _(next) \
+    _(recommendedFov) \
+    _(maxMutableFov) \
+
+#define XR_LIST_STRUCT_XrHolographicWindowAttachmentMSFT(_) \
+    _(type) \
+    _(next) \
+    _(holographicSpace) \
+    _(coreWindow) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerReprojectionInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(reprojectionMode) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerReprojectionPlaneOverrideMSFT(_) \
+    _(type) \
+    _(next) \
+    _(position) \
+    _(normal) \
+    _(velocity) \
+
+#define XR_LIST_STRUCT_XrAndroidSurfaceSwapchainCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(createFlags) \
+
+#define XR_LIST_STRUCT_XrSwapchainStateBaseHeaderFB(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerSecureContentFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrInteractionProfileAnalogThresholdVALVE(_) \
+    _(type) \
+    _(next) \
+    _(action) \
+    _(binding) \
+    _(onThreshold) \
+    _(offThreshold) \
+    _(onHaptic) \
+    _(offHaptic) \
+
+#define XR_LIST_STRUCT_XrHandJointsMotionRangeInfoEXT(_) \
+    _(type) \
+    _(next) \
+    _(handJointsMotionRange) \
+
+#define XR_LIST_STRUCT_XrUuidMSFT(_) \
+    _(bytes) \
+
+#define XR_LIST_STRUCT_XrSceneObserverCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSceneCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSceneSphereBoundMSFT(_) \
+    _(center) \
+    _(radius) \
+
+#define XR_LIST_STRUCT_XrSceneOrientedBoxBoundMSFT(_) \
+    _(pose) \
+    _(extents) \
+
+#define XR_LIST_STRUCT_XrSceneFrustumBoundMSFT(_) \
+    _(pose) \
+    _(fov) \
+    _(farDistance) \
+
+#define XR_LIST_STRUCT_XrSceneBoundsMSFT(_) \
+    _(space) \
+    _(time) \
+    _(sphereCount) \
+    _(spheres) \
+    _(boxCount) \
+    _(boxes) \
+    _(frustumCount) \
+    _(frustums) \
+
+#define XR_LIST_STRUCT_XrNewSceneComputeInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(requestedFeatureCount) \
+    _(requestedFeatures) \
+    _(consistency) \
+    _(bounds) \
+
+#define XR_LIST_STRUCT_XrVisualMeshComputeLodInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(lod) \
+
+#define XR_LIST_STRUCT_XrSceneComponentMSFT(_) \
+    _(componentType) \
+    _(id) \
+    _(parentId) \
+    _(updateTime) \
+
+#define XR_LIST_STRUCT_XrSceneComponentsMSFT(_) \
+    _(type) \
+    _(next) \
+    _(componentCapacityInput) \
+    _(componentCountOutput) \
+    _(components) \
+
+#define XR_LIST_STRUCT_XrSceneComponentsGetInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(componentType) \
+
+#define XR_LIST_STRUCT_XrSceneComponentLocationMSFT(_) \
+    _(flags) \
+    _(pose) \
+
+#define XR_LIST_STRUCT_XrSceneComponentLocationsMSFT(_) \
+    _(type) \
+    _(next) \
+    _(locationCount) \
+    _(locations) \
+
+#define XR_LIST_STRUCT_XrSceneComponentsLocateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(baseSpace) \
+    _(time) \
+    _(componentIdCount) \
+    _(componentIds) \
+
+#define XR_LIST_STRUCT_XrSceneObjectMSFT(_) \
+    _(objectType) \
+
+#define XR_LIST_STRUCT_XrSceneObjectsMSFT(_) \
+    _(type) \
+    _(next) \
+    _(sceneObjectCount) \
+    _(sceneObjects) \
+
+#define XR_LIST_STRUCT_XrSceneComponentParentFilterInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(parentId) \
+
+#define XR_LIST_STRUCT_XrSceneObjectTypesFilterInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(objectTypeCount) \
+    _(objectTypes) \
+
+#define XR_LIST_STRUCT_XrScenePlaneMSFT(_) \
+    _(alignment) \
+    _(size) \
+    _(meshBufferId) \
+    _(supportsIndicesUint16) \
+
+#define XR_LIST_STRUCT_XrScenePlanesMSFT(_) \
+    _(type) \
+    _(next) \
+    _(scenePlaneCount) \
+    _(scenePlanes) \
+
+#define XR_LIST_STRUCT_XrScenePlaneAlignmentFilterInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(alignmentCount) \
+    _(alignments) \
+
+#define XR_LIST_STRUCT_XrSceneMeshMSFT(_) \
+    _(meshBufferId) \
+    _(supportsIndicesUint16) \
+
+#define XR_LIST_STRUCT_XrSceneMeshesMSFT(_) \
+    _(type) \
+    _(next) \
+    _(sceneMeshCount) \
+    _(sceneMeshes) \
+
+#define XR_LIST_STRUCT_XrSceneMeshBuffersGetInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(meshBufferId) \
+
+#define XR_LIST_STRUCT_XrSceneMeshBuffersMSFT(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSceneMeshVertexBufferMSFT(_) \
+    _(type) \
+    _(next) \
+    _(vertexCapacityInput) \
+    _(vertexCountOutput) \
+    _(vertices) \
+
+#define XR_LIST_STRUCT_XrSceneMeshIndicesUint32MSFT(_) \
+    _(type) \
+    _(next) \
+    _(indexCapacityInput) \
+    _(indexCountOutput) \
+    _(indices) \
+
+#define XR_LIST_STRUCT_XrSceneMeshIndicesUint16MSFT(_) \
+    _(type) \
+    _(next) \
+    _(indexCapacityInput) \
+    _(indexCountOutput) \
+    _(indices) \
+
+#define XR_LIST_STRUCT_XrSerializedSceneFragmentDataGetInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(sceneFragmentId) \
+
+#define XR_LIST_STRUCT_XrDeserializeSceneFragmentMSFT(_) \
+    _(bufferSize) \
+    _(buffer) \
+
+#define XR_LIST_STRUCT_XrSceneDeserializeInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(fragmentCount) \
+    _(fragments) \
+
+#define XR_LIST_STRUCT_XrEventDataDisplayRefreshRateChangedFB(_) \
+    _(type) \
+    _(next) \
+    _(fromDisplayRefreshRate) \
+    _(toDisplayRefreshRate) \
+
+#define XR_LIST_STRUCT_XrViveTrackerPathsHTCX(_) \
+    _(type) \
+    _(next) \
+    _(persistentPath) \
+    _(rolePath) \
+
+#define XR_LIST_STRUCT_XrEventDataViveTrackerConnectedHTCX(_) \
+    _(type) \
+    _(next) \
+    _(paths) \
+
+#define XR_LIST_STRUCT_XrSystemFacialTrackingPropertiesHTC(_) \
+    _(type) \
+    _(next) \
+    _(supportEyeFacialTracking) \
+    _(supportLipFacialTracking) \
+
+#define XR_LIST_STRUCT_XrFacialExpressionsHTC(_) \
+    _(type) \
+    _(next) \
+    _(isActive) \
+    _(sampleTime) \
+    _(expressionCount) \
+    _(expressionWeightings) \
+
+#define XR_LIST_STRUCT_XrFacialTrackerCreateInfoHTC(_) \
+    _(type) \
+    _(next) \
+    _(facialTrackingType) \
+
+#define XR_LIST_STRUCT_XrSystemColorSpacePropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(colorSpace) \
+
+#define XR_LIST_STRUCT_XrVector4sFB(_) \
+    _(x) \
+    _(y) \
+    _(z) \
+    _(w) \
+
+#define XR_LIST_STRUCT_XrHandTrackingMeshFB(_) \
+    _(type) \
+    _(next) \
+    _(jointCapacityInput) \
+    _(jointCountOutput) \
+    _(jointBindPoses) \
+    _(jointRadii) \
+    _(jointParents) \
+    _(vertexCapacityInput) \
+    _(vertexCountOutput) \
+    _(vertexPositions) \
+    _(vertexNormals) \
+    _(vertexUVs) \
+    _(vertexBlendIndices) \
+    _(vertexBlendWeights) \
+    _(indexCapacityInput) \
+    _(indexCountOutput) \
+    _(indices) \
+
+#define XR_LIST_STRUCT_XrHandTrackingScaleFB(_) \
+    _(type) \
+    _(next) \
+    _(sensorOutput) \
+    _(currentOutput) \
+    _(overrideHandScale) \
+    _(overrideValueInput) \
+
+#define XR_LIST_STRUCT_XrHandTrackingAimStateFB(_) \
+    _(type) \
+    _(next) \
+    _(status) \
+    _(aimPose) \
+    _(pinchStrengthIndex) \
+    _(pinchStrengthMiddle) \
+    _(pinchStrengthRing) \
+    _(pinchStrengthLittle) \
+
+#define XR_LIST_STRUCT_XrHandCapsuleFB(_) \
+    _(points) \
+    _(radius) \
+    _(joint) \
+
+#define XR_LIST_STRUCT_XrHandTrackingCapsulesStateFB(_) \
+    _(type) \
+    _(next) \
+    _(capsules) \
+
+#define XR_LIST_STRUCT_XrFoveationProfileCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+
+#define XR_LIST_STRUCT_XrSwapchainCreateInfoFoveationFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrSwapchainStateFoveationFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+    _(profile) \
+
+#define XR_LIST_STRUCT_XrFoveationLevelProfileCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(level) \
+    _(verticalOffset) \
+    _(dynamic) \
+
+#define XR_LIST_STRUCT_XrSystemKeyboardTrackingPropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(supportsKeyboardTracking) \
+
+#define XR_LIST_STRUCT_XrKeyboardTrackingDescriptionFB(_) \
+    _(trackedKeyboardId) \
+    _(size) \
+    _(flags) \
+    _(name) \
+
+#define XR_LIST_STRUCT_XrKeyboardSpaceCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(trackedKeyboardId) \
+
+#define XR_LIST_STRUCT_XrKeyboardTrackingQueryFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrTriangleMeshCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+    _(windingOrder) \
+    _(vertexCount) \
+    _(vertexBuffer) \
+    _(triangleCount) \
+    _(indexBuffer) \
+
+#define XR_LIST_STRUCT_XrSystemPassthroughPropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(supportsPassthrough) \
+
+#define XR_LIST_STRUCT_XrPassthroughCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrPassthroughLayerCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(passthrough) \
+    _(flags) \
+    _(purpose) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerPassthroughFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+    _(space) \
+    _(layerHandle) \
+
+#define XR_LIST_STRUCT_XrGeometryInstanceCreateInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(layer) \
+    _(mesh) \
+    _(baseSpace) \
+    _(pose) \
+    _(scale) \
+
+#define XR_LIST_STRUCT_XrGeometryInstanceTransformFB(_) \
+    _(type) \
+    _(next) \
+    _(baseSpace) \
+    _(time) \
+    _(pose) \
+    _(scale) \
+
+#define XR_LIST_STRUCT_XrPassthroughStyleFB(_) \
+    _(type) \
+    _(next) \
+    _(textureOpacityFactor) \
+    _(edgeColor) \
+
+#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToRgbaFB(_) \
+    _(type) \
+    _(next) \
+    _(textureColorMap) \
+
+#define XR_LIST_STRUCT_XrPassthroughColorMapMonoToMonoFB(_) \
+    _(type) \
+    _(next) \
+    _(textureColorMap) \
+
+#define XR_LIST_STRUCT_XrEventDataPassthroughStateChangedFB(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrRenderModelPathInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(path) \
+
+#define XR_LIST_STRUCT_XrRenderModelPropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(vendorId) \
+    _(modelName) \
+    _(modelKey) \
+    _(modelVersion) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrRenderModelBufferFB(_) \
+    _(type) \
+    _(next) \
+    _(bufferCapacityInput) \
+    _(bufferCountOutput) \
+    _(buffer) \
+
+#define XR_LIST_STRUCT_XrRenderModelLoadInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(modelKey) \
+
+#define XR_LIST_STRUCT_XrSystemRenderModelPropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(supportsRenderModelLoading) \
+
+#define XR_LIST_STRUCT_XrViewLocateFoveatedRenderingVARJO(_) \
+    _(type) \
+    _(next) \
+    _(foveatedRenderingActive) \
+
+#define XR_LIST_STRUCT_XrFoveatedViewConfigurationViewVARJO(_) \
+    _(type) \
+    _(next) \
+    _(foveatedRenderingActive) \
+
+#define XR_LIST_STRUCT_XrSystemFoveatedRenderingPropertiesVARJO(_) \
+    _(type) \
+    _(next) \
+    _(supportsFoveatedRendering) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerDepthTestVARJO(_) \
+    _(type) \
+    _(next) \
+    _(depthTestRangeNearZ) \
+    _(depthTestRangeFarZ) \
+
+#define XR_LIST_STRUCT_XrSystemMarkerTrackingPropertiesVARJO(_) \
+    _(type) \
+    _(next) \
+    _(supportsMarkerTracking) \
+
+#define XR_LIST_STRUCT_XrEventDataMarkerTrackingUpdateVARJO(_) \
+    _(type) \
+    _(next) \
+    _(markerId) \
+    _(isActive) \
+    _(isPredicted) \
+    _(time) \
+
+#define XR_LIST_STRUCT_XrMarkerSpaceCreateInfoVARJO(_) \
+    _(type) \
+    _(next) \
+    _(markerId) \
+    _(poseInMarkerSpace) \
+
+#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceNameMSFT(_) \
+    _(name) \
+
+#define XR_LIST_STRUCT_XrSpatialAnchorPersistenceInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(spatialAnchorPersistenceName) \
+    _(spatialAnchor) \
+
+#define XR_LIST_STRUCT_XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT(_) \
+    _(type) \
+    _(next) \
+    _(spatialAnchorStore) \
+    _(spatialAnchorPersistenceName) \
+
+#define XR_LIST_STRUCT_XrSwapchainImageFoveationVulkanFB(_) \
+    _(type) \
+    _(next) \
+    _(image) \
+    _(width) \
+    _(height) \
+
+#define XR_LIST_STRUCT_XrSwapchainStateAndroidSurfaceDimensionsFB(_) \
+    _(type) \
+    _(next) \
+    _(width) \
+    _(height) \
+
+#define XR_LIST_STRUCT_XrSwapchainStateSamplerOpenGLESFB(_) \
+    _(type) \
+    _(next) \
+    _(minFilter) \
+    _(magFilter) \
+    _(wrapModeS) \
+    _(wrapModeT) \
+    _(swizzleRed) \
+    _(swizzleGreen) \
+    _(swizzleBlue) \
+    _(swizzleAlpha) \
+    _(maxAnisotropy) \
+    _(borderColor) \
+
+#define XR_LIST_STRUCT_XrSwapchainStateSamplerVulkanFB(_) \
+    _(type) \
+    _(next) \
+    _(minFilter) \
+    _(magFilter) \
+    _(mipmapMode) \
+    _(wrapModeS) \
+    _(wrapModeT) \
+    _(swizzleRed) \
+    _(swizzleGreen) \
+    _(swizzleBlue) \
+    _(swizzleAlpha) \
+    _(maxAnisotropy) \
+    _(borderColor) \
+
+#define XR_LIST_STRUCT_XrCompositionLayerSpaceWarpInfoFB(_) \
+    _(type) \
+    _(next) \
+    _(layerFlags) \
+    _(motionVectorSubImage) \
+    _(appSpaceDeltaPose) \
+    _(depthSubImage) \
+    _(minDepth) \
+    _(maxDepth) \
+    _(nearZ) \
+    _(farZ) \
+
+#define XR_LIST_STRUCT_XrSystemSpaceWarpPropertiesFB(_) \
+    _(type) \
+    _(next) \
+    _(recommendedMotionVectorImageRectWidth) \
+    _(recommendedMotionVectorImageRectHeight) \
+
+#define XR_LIST_STRUCT_XrDigitalLensControlALMALENCE(_) \
+    _(type) \
+    _(next) \
+    _(flags) \
+
+#define XR_LIST_STRUCT_XrPassthroughKeyboardHandsIntensityFB(_) \
+    _(type) \
+    _(next) \
+    _(leftHandIntensity) \
+    _(rightHandIntensity) \
+
+#define XR_LIST_STRUCT_XrUuidEXT(_) \
+    _(data) \
+
+
+
+#define XR_LIST_STRUCTURE_TYPES_CORE(_) \
+    _(XrApiLayerProperties, XR_TYPE_API_LAYER_PROPERTIES) \
+    _(XrExtensionProperties, XR_TYPE_EXTENSION_PROPERTIES) \
+    _(XrInstanceCreateInfo, XR_TYPE_INSTANCE_CREATE_INFO) \
+    _(XrInstanceProperties, XR_TYPE_INSTANCE_PROPERTIES) \
+    _(XrEventDataBuffer, XR_TYPE_EVENT_DATA_BUFFER) \
+    _(XrSystemGetInfo, XR_TYPE_SYSTEM_GET_INFO) \
+    _(XrSystemProperties, XR_TYPE_SYSTEM_PROPERTIES) \
+    _(XrSessionCreateInfo, XR_TYPE_SESSION_CREATE_INFO) \
+    _(XrSpaceVelocity, XR_TYPE_SPACE_VELOCITY) \
+    _(XrReferenceSpaceCreateInfo, XR_TYPE_REFERENCE_SPACE_CREATE_INFO) \
+    _(XrActionSpaceCreateInfo, XR_TYPE_ACTION_SPACE_CREATE_INFO) \
+    _(XrSpaceLocation, XR_TYPE_SPACE_LOCATION) \
+    _(XrViewConfigurationProperties, XR_TYPE_VIEW_CONFIGURATION_PROPERTIES) \
+    _(XrViewConfigurationView, XR_TYPE_VIEW_CONFIGURATION_VIEW) \
+    _(XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO) \
+    _(XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO) \
+    _(XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO) \
+    _(XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO) \
+    _(XrSessionBeginInfo, XR_TYPE_SESSION_BEGIN_INFO) \
+    _(XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO) \
+    _(XrFrameState, XR_TYPE_FRAME_STATE) \
+    _(XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO) \
+    _(XrFrameEndInfo, XR_TYPE_FRAME_END_INFO) \
+    _(XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO) \
+    _(XrViewState, XR_TYPE_VIEW_STATE) \
+    _(XrView, XR_TYPE_VIEW) \
+    _(XrActionSetCreateInfo, XR_TYPE_ACTION_SET_CREATE_INFO) \
+    _(XrActionCreateInfo, XR_TYPE_ACTION_CREATE_INFO) \
+    _(XrInteractionProfileSuggestedBinding, XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING) \
+    _(XrSessionActionSetsAttachInfo, XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO) \
+    _(XrInteractionProfileState, XR_TYPE_INTERACTION_PROFILE_STATE) \
+    _(XrActionStateGetInfo, XR_TYPE_ACTION_STATE_GET_INFO) \
+    _(XrActionStateBoolean, XR_TYPE_ACTION_STATE_BOOLEAN) \
+    _(XrActionStateFloat, XR_TYPE_ACTION_STATE_FLOAT) \
+    _(XrActionStateVector2f, XR_TYPE_ACTION_STATE_VECTOR2F) \
+    _(XrActionStatePose, XR_TYPE_ACTION_STATE_POSE) \
+    _(XrActionsSyncInfo, XR_TYPE_ACTIONS_SYNC_INFO) \
+    _(XrBoundSourcesForActionEnumerateInfo, XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO) \
+    _(XrInputSourceLocalizedNameGetInfo, XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO) \
+    _(XrHapticActionInfo, XR_TYPE_HAPTIC_ACTION_INFO) \
+    _(XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW) \
+    _(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \
+    _(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \
+    _(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \
+    _(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \
+    _(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \
+    _(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \
+    _(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \
+    _(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \
+    _(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \
+    _(XrCompositionLayerDepthInfoKHR, XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR) \
+    _(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \
+    _(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \
+    _(XrVisibilityMaskKHR, XR_TYPE_VISIBILITY_MASK_KHR) \
+    _(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \
+    _(XrCompositionLayerColorScaleBiasKHR, XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR) \
+    _(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \
+    _(XrBindingModificationsKHR, XR_TYPE_BINDING_MODIFICATIONS_KHR) \
+    _(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \
+    _(XrDebugUtilsObjectNameInfoEXT, XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT) \
+    _(XrDebugUtilsLabelEXT, XR_TYPE_DEBUG_UTILS_LABEL_EXT) \
+    _(XrDebugUtilsMessengerCallbackDataEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT) \
+    _(XrDebugUtilsMessengerCreateInfoEXT, XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT) \
+    _(XrSystemEyeGazeInteractionPropertiesEXT, XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT) \
+    _(XrEyeGazeSampleTimeEXT, XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT) \
+    _(XrSessionCreateInfoOverlayEXTX, XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX) \
+    _(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \
+    _(XrSpatialAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT) \
+    _(XrSpatialAnchorSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT) \
+    _(XrCompositionLayerImageLayoutFB, XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB) \
+    _(XrCompositionLayerAlphaBlendFB, XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB) \
+    _(XrViewConfigurationDepthRangeEXT, XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT) \
+    _(XrSpatialGraphNodeSpaceCreateInfoMSFT, XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT) \
+    _(XrSystemHandTrackingPropertiesEXT, XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT) \
+    _(XrHandTrackerCreateInfoEXT, XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT) \
+    _(XrHandJointsLocateInfoEXT, XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT) \
+    _(XrHandJointLocationsEXT, XR_TYPE_HAND_JOINT_LOCATIONS_EXT) \
+    _(XrHandJointVelocitiesEXT, XR_TYPE_HAND_JOINT_VELOCITIES_EXT) \
+    _(XrSystemHandTrackingMeshPropertiesMSFT, XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT) \
+    _(XrHandMeshSpaceCreateInfoMSFT, XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT) \
+    _(XrHandMeshUpdateInfoMSFT, XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT) \
+    _(XrHandMeshMSFT, XR_TYPE_HAND_MESH_MSFT) \
+    _(XrHandPoseTypeInfoMSFT, XR_TYPE_HAND_POSE_TYPE_INFO_MSFT) \
+    _(XrSecondaryViewConfigurationSessionBeginInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT) \
+    _(XrSecondaryViewConfigurationStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT) \
+    _(XrSecondaryViewConfigurationFrameStateMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT) \
+    _(XrSecondaryViewConfigurationLayerInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT) \
+    _(XrSecondaryViewConfigurationFrameEndInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT) \
+    _(XrSecondaryViewConfigurationSwapchainCreateInfoMSFT, XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT) \
+    _(XrControllerModelKeyStateMSFT, XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT) \
+    _(XrControllerModelNodePropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT) \
+    _(XrControllerModelPropertiesMSFT, XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT) \
+    _(XrControllerModelNodeStateMSFT, XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT) \
+    _(XrControllerModelStateMSFT, XR_TYPE_CONTROLLER_MODEL_STATE_MSFT) \
+    _(XrViewConfigurationViewFovEPIC, XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC) \
+    _(XrCompositionLayerReprojectionInfoMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT) \
+    _(XrCompositionLayerReprojectionPlaneOverrideMSFT, XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT) \
+    _(XrCompositionLayerSecureContentFB, XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB) \
+    _(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \
+    _(XrHandJointsMotionRangeInfoEXT, XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT) \
+    _(XrSceneObserverCreateInfoMSFT, XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT) \
+    _(XrSceneCreateInfoMSFT, XR_TYPE_SCENE_CREATE_INFO_MSFT) \
+    _(XrNewSceneComputeInfoMSFT, XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT) \
+    _(XrVisualMeshComputeLodInfoMSFT, XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT) \
+    _(XrSceneComponentsMSFT, XR_TYPE_SCENE_COMPONENTS_MSFT) \
+    _(XrSceneComponentsGetInfoMSFT, XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT) \
+    _(XrSceneComponentLocationsMSFT, XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT) \
+    _(XrSceneComponentsLocateInfoMSFT, XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT) \
+    _(XrSceneObjectsMSFT, XR_TYPE_SCENE_OBJECTS_MSFT) \
+    _(XrSceneComponentParentFilterInfoMSFT, XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT) \
+    _(XrSceneObjectTypesFilterInfoMSFT, XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT) \
+    _(XrScenePlanesMSFT, XR_TYPE_SCENE_PLANES_MSFT) \
+    _(XrScenePlaneAlignmentFilterInfoMSFT, XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT) \
+    _(XrSceneMeshesMSFT, XR_TYPE_SCENE_MESHES_MSFT) \
+    _(XrSceneMeshBuffersGetInfoMSFT, XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT) \
+    _(XrSceneMeshBuffersMSFT, XR_TYPE_SCENE_MESH_BUFFERS_MSFT) \
+    _(XrSceneMeshVertexBufferMSFT, XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT) \
+    _(XrSceneMeshIndicesUint32MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT) \
+    _(XrSceneMeshIndicesUint16MSFT, XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT) \
+    _(XrSerializedSceneFragmentDataGetInfoMSFT, XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT) \
+    _(XrSceneDeserializeInfoMSFT, XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT) \
+    _(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \
+    _(XrViveTrackerPathsHTCX, XR_TYPE_VIVE_TRACKER_PATHS_HTCX) \
+    _(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \
+    _(XrSystemFacialTrackingPropertiesHTC, XR_TYPE_SYSTEM_FACIAL_TRACKING_PROPERTIES_HTC) \
+    _(XrFacialExpressionsHTC, XR_TYPE_FACIAL_EXPRESSIONS_HTC) \
+    _(XrFacialTrackerCreateInfoHTC, XR_TYPE_FACIAL_TRACKER_CREATE_INFO_HTC) \
+    _(XrSystemColorSpacePropertiesFB, XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB) \
+    _(XrHandTrackingMeshFB, XR_TYPE_HAND_TRACKING_MESH_FB) \
+    _(XrHandTrackingScaleFB, XR_TYPE_HAND_TRACKING_SCALE_FB) \
+    _(XrHandTrackingAimStateFB, XR_TYPE_HAND_TRACKING_AIM_STATE_FB) \
+    _(XrHandTrackingCapsulesStateFB, XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB) \
+    _(XrFoveationProfileCreateInfoFB, XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB) \
+    _(XrSwapchainCreateInfoFoveationFB, XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB) \
+    _(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \
+    _(XrFoveationLevelProfileCreateInfoFB, XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB) \
+    _(XrSystemKeyboardTrackingPropertiesFB, XR_TYPE_SYSTEM_KEYBOARD_TRACKING_PROPERTIES_FB) \
+    _(XrKeyboardSpaceCreateInfoFB, XR_TYPE_KEYBOARD_SPACE_CREATE_INFO_FB) \
+    _(XrKeyboardTrackingQueryFB, XR_TYPE_KEYBOARD_TRACKING_QUERY_FB) \
+    _(XrTriangleMeshCreateInfoFB, XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB) \
+    _(XrSystemPassthroughPropertiesFB, XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB) \
+    _(XrPassthroughCreateInfoFB, XR_TYPE_PASSTHROUGH_CREATE_INFO_FB) \
+    _(XrPassthroughLayerCreateInfoFB, XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB) \
+    _(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \
+    _(XrGeometryInstanceCreateInfoFB, XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB) \
+    _(XrGeometryInstanceTransformFB, XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB) \
+    _(XrPassthroughStyleFB, XR_TYPE_PASSTHROUGH_STYLE_FB) \
+    _(XrPassthroughColorMapMonoToRgbaFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB) \
+    _(XrPassthroughColorMapMonoToMonoFB, XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB) \
+    _(XrEventDataPassthroughStateChangedFB, XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB) \
+    _(XrRenderModelPathInfoFB, XR_TYPE_RENDER_MODEL_PATH_INFO_FB) \
+    _(XrRenderModelPropertiesFB, XR_TYPE_RENDER_MODEL_PROPERTIES_FB) \
+    _(XrRenderModelBufferFB, XR_TYPE_RENDER_MODEL_BUFFER_FB) \
+    _(XrRenderModelLoadInfoFB, XR_TYPE_RENDER_MODEL_LOAD_INFO_FB) \
+    _(XrSystemRenderModelPropertiesFB, XR_TYPE_SYSTEM_RENDER_MODEL_PROPERTIES_FB) \
+    _(XrViewLocateFoveatedRenderingVARJO, XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO) \
+    _(XrFoveatedViewConfigurationViewVARJO, XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO) \
+    _(XrSystemFoveatedRenderingPropertiesVARJO, XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO) \
+    _(XrCompositionLayerDepthTestVARJO, XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO) \
+    _(XrSystemMarkerTrackingPropertiesVARJO, XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO) \
+    _(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \
+    _(XrMarkerSpaceCreateInfoVARJO, XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO) \
+    _(XrSpatialAnchorPersistenceInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT) \
+    _(XrSpatialAnchorFromPersistedAnchorCreateInfoMSFT, XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT) \
+    _(XrCompositionLayerSpaceWarpInfoFB, XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB) \
+    _(XrSystemSpaceWarpPropertiesFB, XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB) \
+    _(XrDigitalLensControlALMALENCE, XR_TYPE_DIGITAL_LENS_CONTROL_ALMALENCE) \
+    _(XrPassthroughKeyboardHandsIntensityFB, XR_TYPE_PASSTHROUGH_KEYBOARD_HANDS_INTENSITY_FB) \
+
+
+
+
+#if defined(XR_USE_GRAPHICS_API_D3D11)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \
+    _(XrGraphicsBindingD3D11KHR, XR_TYPE_GRAPHICS_BINDING_D3D11_KHR) \
+    _(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \
+    _(XrGraphicsRequirementsD3D11KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_D3D12)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \
+    _(XrGraphicsBindingD3D12KHR, XR_TYPE_GRAPHICS_BINDING_D3D12_KHR) \
+    _(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \
+    _(XrGraphicsRequirementsD3D12KHR, XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \
+    _(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \
+    _(XrGraphicsRequirementsOpenGLKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WAYLAND)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \
+    _(XrGraphicsBindingOpenGLWaylandKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_WIN32)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \
+    _(XrGraphicsBindingOpenGLWin32KHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XCB)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \
+    _(XrGraphicsBindingOpenGLXcbKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL) && defined(XR_USE_PLATFORM_XLIB)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \
+    _(XrGraphicsBindingOpenGLXlibKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \
+    _(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \
+    _(XrGraphicsRequirementsOpenGLESKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR) \
+    _(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_OPENGL_ES) && defined(XR_USE_PLATFORM_ANDROID)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \
+    _(XrGraphicsBindingOpenGLESAndroidKHR, XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_)
+#endif
+
+#if defined(XR_USE_GRAPHICS_API_VULKAN)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \
+    _(XrVulkanSwapchainFormatListCreateInfoKHR, XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR) \
+    _(XrGraphicsBindingVulkanKHR, XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) \
+    _(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \
+    _(XrGraphicsRequirementsVulkanKHR, XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR) \
+    _(XrVulkanInstanceCreateInfoKHR, XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR) \
+    _(XrVulkanDeviceCreateInfoKHR, XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR) \
+    _(XrVulkanGraphicsDeviceGetInfoKHR, XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR) \
+    _(XrSwapchainImageFoveationVulkanFB, XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB) \
+    _(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_)
+#endif
+
+#if defined(XR_USE_PLATFORM_ANDROID)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \
+    _(XrInstanceCreateInfoAndroidKHR, XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR) \
+    _(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \
+    _(XrAndroidSurfaceSwapchainCreateInfoFB, XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB) \
+    _(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_)
+#endif
+
+#if defined(XR_USE_PLATFORM_EGL)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \
+    _(XrGraphicsBindingEGLMNDX, XR_TYPE_GRAPHICS_BINDING_EGL_MNDX) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_)
+#endif
+
+#if defined(XR_USE_PLATFORM_WIN32)
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \
+    _(XrHolographicWindowAttachmentMSFT, XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT) \
+
+
+#else
+#define XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_)
+#endif
+
+#define XR_LIST_STRUCTURE_TYPES(_) \
+    XR_LIST_STRUCTURE_TYPES_CORE(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D11(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_D3D12(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WAYLAND(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_WIN32(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XCB(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_XR_USE_PLATFORM_XLIB(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_OPENGL_ES_XR_USE_PLATFORM_ANDROID(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_GRAPHICS_API_VULKAN(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_ANDROID(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_EGL(_) \
+    XR_LIST_STRUCTURE_TYPES_XR_USE_PLATFORM_WIN32(_) \
+
+
+#define XR_LIST_EXTENSIONS(_) \
+    _(XR_KHR_android_thread_settings, 4) \
+    _(XR_KHR_android_surface_swapchain, 5) \
+    _(XR_KHR_composition_layer_cube, 7) \
+    _(XR_KHR_android_create_instance, 9) \
+    _(XR_KHR_composition_layer_depth, 11) \
+    _(XR_KHR_vulkan_swapchain_format_list, 15) \
+    _(XR_EXT_performance_settings, 16) \
+    _(XR_EXT_thermal_query, 17) \
+    _(XR_KHR_composition_layer_cylinder, 18) \
+    _(XR_KHR_composition_layer_equirect, 19) \
+    _(XR_EXT_debug_utils, 20) \
+    _(XR_KHR_opengl_enable, 24) \
+    _(XR_KHR_opengl_es_enable, 25) \
+    _(XR_KHR_vulkan_enable, 26) \
+    _(XR_KHR_D3D11_enable, 28) \
+    _(XR_KHR_D3D12_enable, 29) \
+    _(XR_EXT_eye_gaze_interaction, 31) \
+    _(XR_KHR_visibility_mask, 32) \
+    _(XR_EXTX_overlay, 34) \
+    _(XR_KHR_composition_layer_color_scale_bias, 35) \
+    _(XR_KHR_win32_convert_performance_counter_time, 36) \
+    _(XR_KHR_convert_timespec_time, 37) \
+    _(XR_VARJO_quad_views, 38) \
+    _(XR_MSFT_unbounded_reference_space, 39) \
+    _(XR_MSFT_spatial_anchor, 40) \
+    _(XR_FB_composition_layer_image_layout, 41) \
+    _(XR_FB_composition_layer_alpha_blend, 42) \
+    _(XR_MND_headless, 43) \
+    _(XR_OCULUS_android_session_state_enable, 45) \
+    _(XR_EXT_view_configuration_depth_range, 47) \
+    _(XR_EXT_conformance_automation, 48) \
+    _(XR_MNDX_egl_enable, 49) \
+    _(XR_MSFT_spatial_graph_bridge, 50) \
+    _(XR_MSFT_hand_interaction, 51) \
+    _(XR_EXT_hand_tracking, 52) \
+    _(XR_MSFT_hand_tracking_mesh, 53) \
+    _(XR_MSFT_secondary_view_configuration, 54) \
+    _(XR_MSFT_first_person_observer, 55) \
+    _(XR_MSFT_controller_model, 56) \
+    _(XR_MSFT_perception_anchor_interop, 57) \
+    _(XR_EXT_win32_appcontainer_compatible, 58) \
+    _(XR_EPIC_view_configuration_fov, 60) \
+    _(XR_MSFT_holographic_window_attachment, 64) \
+    _(XR_MSFT_composition_layer_reprojection, 67) \
+    _(XR_HUAWEI_controller_interaction, 70) \
+    _(XR_FB_android_surface_swapchain_create, 71) \
+    _(XR_FB_swapchain_update_state, 72) \
+    _(XR_FB_composition_layer_secure_content, 73) \
+    _(XR_VALVE_analog_threshold, 80) \
+    _(XR_EXT_hand_joints_motion_range, 81) \
+    _(XR_KHR_loader_init, 89) \
+    _(XR_KHR_loader_init_android, 90) \
+    _(XR_KHR_vulkan_enable2, 91) \
+    _(XR_KHR_composition_layer_equirect2, 92) \
+    _(XR_EXT_samsung_odyssey_controller, 95) \
+    _(XR_EXT_hp_mixed_reality_controller, 96) \
+    _(XR_MND_swapchain_usage_input_attachment_bit, 97) \
+    _(XR_MSFT_scene_understanding, 98) \
+    _(XR_MSFT_scene_understanding_serialization, 99) \
+    _(XR_FB_display_refresh_rate, 102) \
+    _(XR_HTC_vive_cosmos_controller_interaction, 103) \
+    _(XR_HTCX_vive_tracker_interaction, 104) \
+    _(XR_HTC_facial_tracking, 105) \
+    _(XR_HTC_vive_focus3_controller_interaction, 106) \
+    _(XR_FB_color_space, 109) \
+    _(XR_FB_hand_tracking_mesh, 111) \
+    _(XR_FB_hand_tracking_aim, 112) \
+    _(XR_FB_hand_tracking_capsules, 113) \
+    _(XR_FB_foveation, 115) \
+    _(XR_FB_foveation_configuration, 116) \
+    _(XR_FB_keyboard_tracking, 117) \
+    _(XR_FB_triangle_mesh, 118) \
+    _(XR_FB_passthrough, 119) \
+    _(XR_FB_render_model, 120) \
+    _(XR_KHR_binding_modification, 121) \
+    _(XR_VARJO_foveated_rendering, 122) \
+    _(XR_VARJO_composition_layer_depth_test, 123) \
+    _(XR_VARJO_environment_depth_estimation, 124) \
+    _(XR_VARJO_marker_tracking, 125) \
+    _(XR_MSFT_spatial_anchor_persistence, 143) \
+    _(XR_OCULUS_audio_device_guid, 160) \
+    _(XR_FB_foveation_vulkan, 161) \
+    _(XR_FB_swapchain_update_state_android_surface, 162) \
+    _(XR_FB_swapchain_update_state_opengl_es, 163) \
+    _(XR_FB_swapchain_update_state_vulkan, 164) \
+    _(XR_KHR_swapchain_usage_input_attachment_bit, 166) \
+    _(XR_FB_space_warp, 172) \
+    _(XR_ALMALENCE_digital_lens_control, 197) \
+    _(XR_FB_passthrough_keyboard_hands, 204) \
+    _(XR_EXT_uuid, 300) \
+
+
+#endif
+

+ 10 - 0
thirdparty/openxr/src/.clang-format

@@ -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
+...

+ 47 - 0
thirdparty/openxr/src/common/extra_algorithms.h

@@ -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 <[email protected]>
+//
+
+/*!
+ * @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);
+}

+ 322 - 0
thirdparty/openxr/src/common/filesystem_utils.cpp

@@ -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 <[email protected]>
+//                  Nat Brown <[email protected]>
+//
+
+#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

+ 46 - 0
thirdparty/openxr/src/common/filesystem_utils.hpp

@@ -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 <[email protected]>
+//
+
+#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);

+ 108 - 0
thirdparty/openxr/src/common/hex_and_handles.h

@@ -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 <[email protected]>
+//
+
+/*!
+ * @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);
+}

+ 114 - 0
thirdparty/openxr/src/common/loader_interfaces.h

@@ -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 <[email protected]>
+//
+
+#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

+ 276 - 0
thirdparty/openxr/src/common/object_info.cpp

@@ -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 <[email protected]>
+//                  Ryan Pavlik <[email protected]>
+//                  Dave Houlton <[email protected]>
+//
+
+#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;
+}

+ 229 - 0
thirdparty/openxr/src/common/object_info.h

@@ -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 <[email protected]>, Ryan Pavlik <[email protected]
+//
+/*!
+ * @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_;
+};

+ 345 - 0
thirdparty/openxr/src/common/platform_utils.hpp

@@ -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 <[email protected]>, Dave Houlton <[email protected]>
+//
+
+#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

+ 45 - 0
thirdparty/openxr/src/common/stdfs_conditions.h

@@ -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

+ 89 - 0
thirdparty/openxr/src/common/xr_dependencies.h

@@ -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 - 0
thirdparty/openxr/src/common/xr_linear.h

@@ -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_

+ 115 - 0
thirdparty/openxr/src/external/jsoncpp/AUTHORS

@@ -0,0 +1,115 @@
+Baptiste Lepilleur <[email protected]>
+
+Aaron Jacobs <[email protected]>
+Aaron Jacobs <[email protected]>
+Adam Boseley <[email protected]>
+Adam Boseley <[email protected]>
+Aleksandr Derbenev <[email protected]>
+Alexander Gazarov <[email protected]>
+Alexander V. Brezgin <[email protected]>
+Alexandr Brezgin <[email protected]>
+Alexey Kruchinin <[email protected]>
+Anton Indrawan <[email protected]>
+Baptiste Jonglez <[email protected]>
+Baptiste Lepilleur <[email protected]>
+Baruch Siach <[email protected]>
+Ben Boeckel <[email protected]>
+Benjamin Knecht <[email protected]>
+Bernd Kuhls <[email protected]>
+Billy Donahue <[email protected]>
+Braden McDorman <[email protected]>
+Brandon Myers <[email protected]>
+Brendan Drew <[email protected]>
+chason <[email protected]>
+chenguoping <[email protected]>
+Chris Gilling <[email protected]>
+Christopher Dawes <[email protected]>
+Christopher Dunn <[email protected]>
+Chuck Atkins <[email protected]>
+Cody P Schafer <[email protected]>
+Connor Manning <[email protected]>
+Cory Quammen <[email protected]>
+Cristóvão B da Cruz e Silva <[email protected]>
+Daniel Krügler <[email protected]>
+Dani-Hub <[email protected]>
+Dan Liu <gzliudan>
+datadiode <[email protected]>
+datadiode <[email protected]>
+David Seifert <[email protected]>
+David West <[email protected]>
+dawesc <[email protected]>
+Devin Jeanpierre <[email protected]>
+Dmitry Marakasov <[email protected]>
+dominicpezzuto <[email protected]>
+Don Milham <[email protected]>
+drgler <[email protected]>
+ds283 <[email protected]>
+Egor Tensin <[email protected]>
+eightnoteight <[email protected]>
+Evince <[email protected]>
+filipjs <[email protected]>
+findblar <[email protected]>
+Florian Meier <[email protected]>
+Gaëtan Lehmann <[email protected]>
+Gaurav <[email protected]>
+Gergely Nagy <[email protected]>
+Gida Pataki <[email protected]>
+I3ck <[email protected]>
+Iñaki Baz Castillo <[email protected]>
+Jacco <[email protected]>
+Jean-Christophe Fillion-Robin <[email protected]>
+Jonas Platte <[email protected]>
+Jordan Bayles <[email protected]>
+Jörg Krause <[email protected]>
+Keith Lea <[email protected]>
+Kevin Grant <[email protected]>
+Kirill V. Lyadvinsky <[email protected]>
+Kirill V. Lyadvinsky <[email protected]>
+Kobi Gurkan <[email protected]>
+Magnus Bjerke Vik <[email protected]>
+Malay Shah <[email protected]>
+Mara Kim <[email protected]>
+Marek Kotewicz <[email protected]>
+Mark Lakata <[email protected]>
+Mark Zeren <[email protected]>
+Martin Buck <[email protected]>
+Martyn Gigg <[email protected]>
+Mattes D <[email protected]>
+Matthias Loy <[email protected]>
+Merlyn Morgan-Graham <[email protected]>
+Michael Shields <[email protected]>
+Michał Górny <[email protected]>
+Mike Naberezny <[email protected]>
+mloy <[email protected]>
+Motti <[email protected]>
+nnkur <[email protected]>
+Omkar Wagh <[email protected]>
+paulo <[email protected]>
+pavel.pimenov <[email protected]>
+Paweł Bylica <[email protected]>
+Péricles Lopes Machado <[email protected]>
+Peter Spiess-Knafl <[email protected]>
+pffang <[email protected]>
+Rémi Verschelde <[email protected]>
+renu555 <[email protected]>
+Robert Dailey <[email protected]>
+Sam Clegg <[email protected]>
+selaselah <[email protected]>
+Sergiy80 <[email protected]>
+sergzub <[email protected]>
+Stefan Schweter <[email protected]>
+Stefano Fiorentino <[email protected]>
+Steffen Kieß <[email protected]>
+Steven Hahn <[email protected]>
+Stuart Eichert <[email protected]>
+SuperManitu <[email protected]>
+Techwolf <[email protected]>
+Tengiz Sharafiev <[email protected]>
+Tomasz Maciejewski <[email protected]>
+Vicente Olivert Riera <[email protected]>
+xiaoyur347 <[email protected]>
+ycqiu <[email protected]>
+yiqiju <[email protected]>
+Yu Xiaolei <[email protected]>
+
+Google Inc.

+ 55 - 0
thirdparty/openxr/src/external/jsoncpp/LICENSE

@@ -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.

+ 88 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/allocator.h

@@ -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

+ 61 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/assertions.h

@@ -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

+ 150 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/config.h

@@ -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

+ 43 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/forwards.h

@@ -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

+ 15 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/json.h

@@ -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

+ 61 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/json_features.h

@@ -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

+ 405 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/reader.h

@@ -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

+ 935 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/value.h

@@ -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

+ 28 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/version.h

@@ -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

+ 369 - 0
thirdparty/openxr/src/external/jsoncpp/include/json/writer.h

@@ -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

+ 1992 - 0
thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_reader.cpp

@@ -0,0 +1,1992 @@
+// Copyright 2007-2011 Baptiste Lepilleur and The JsonCpp Authors
+// Copyright (C) 2016 InfoTeCS JSC. All rights reserved.
+// 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
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "json_tool.h"
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <istream>
+#include <limits>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#include <cstdio>
+#if __cplusplus >= 201103L
+
+#if !defined(sscanf)
+#define sscanf std::sscanf
+#endif
+
+#endif //__cplusplus
+
+#if defined(_MSC_VER)
+#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
+#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
+#endif //_MSC_VER
+
+#if defined(_MSC_VER)
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+// Define JSONCPP_DEPRECATED_STACK_LIMIT as an appropriate integer at compile
+// time to change the stack limit
+#if !defined(JSONCPP_DEPRECATED_STACK_LIMIT)
+#define JSONCPP_DEPRECATED_STACK_LIMIT 1000
+#endif
+
+static size_t const stackLimit_g =
+    JSONCPP_DEPRECATED_STACK_LIMIT; // see readValue()
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+using CharReaderPtr = std::unique_ptr<CharReader>;
+#else
+using CharReaderPtr = std::auto_ptr<CharReader>;
+#endif
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features() = default;
+
+Features Features::all() { return {}; }
+
+Features Features::strictMode() {
+  Features features;
+  features.allowComments_ = false;
+  features.strictRoot_ = true;
+  features.allowDroppedNullPlaceholders_ = false;
+  features.allowNumericKeys_ = false;
+  return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+bool Reader::containsNewLine(Reader::Location begin, Reader::Location end) {
+  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader() : features_(Features::all()) {}
+
+Reader::Reader(const Features& features) : features_(features) {}
+
+bool Reader::parse(const std::string& document, Value& root,
+                   bool collectComments) {
+  document_.assign(document.begin(), document.end());
+  const char* begin = document_.c_str();
+  const char* end = begin + document_.length();
+  return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
+  // std::istream_iterator<char> begin(is);
+  // std::istream_iterator<char> end;
+  // Those would allow streamed input from a file, if parse() were a
+  // template function.
+
+  // Since String is reference-counted, this at least does not
+  // create an extra copy.
+  String doc(std::istreambuf_iterator<char>(is), {});
+  return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
+}
+
+bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,
+                   bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = nullptr;
+  lastValue_ = nullptr;
+  commentsBefore_.clear();
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  bool successful = readValue();
+  Token token;
+  skipCommentTokens(token);
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool Reader::readValue() {
+  // readValue() may call itself only if it calls readObject() or ReadArray().
+  // These methods execute nodes_.push() just before and nodes_.pop)() just
+  // after calling readValue(). parse() executes one nodes_.push(), so > instead
+  // of >=.
+  if (nodes_.size() > stackLimit_g)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
+
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_.clear();
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue: {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenFalse: {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenNull: {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // Else, fall through...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValue_ = &currentValue();
+  }
+
+  return successful;
+}
+
+void Reader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool Reader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+  case '-':
+    token.type_ = tokenNumber;
+    readNumber();
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return ok;
+}
+
+void Reader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+bool Reader::match(const Char* pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool Reader::readComment() {
+  Location commentBegin = current_ - 1;
+  Char c = getNextChar();
+  bool successful = false;
+  if (c == '*')
+    successful = readCStyleComment();
+  else if (c == '/')
+    successful = readCppStyleComment();
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+    if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+      if (c != '*' || !containsNewLine(commentBegin, current_))
+        placement = commentAfterOnSameLine;
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+String Reader::normalizeEOL(Reader::Location begin, Reader::Location end) {
+  String normalized;
+  normalized.reserve(static_cast<size_t>(end - begin));
+  Reader::Location current = begin;
+  while (current != end) {
+    char c = *current++;
+    if (c == '\r') {
+      if (current != end && *current == '\n')
+        // convert dos EOL
+        ++current;
+      // convert Mac EOL
+      normalized += '\n';
+    } else {
+      normalized += c;
+    }
+  }
+  return normalized;
+}
+
+void Reader::addComment(Location begin, Location end,
+                        CommentPlacement placement) {
+  assert(collectComments_);
+  const String& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != nullptr);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool Reader::readCStyleComment() {
+  while ((current_ + 1) < end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+  }
+  return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+void Reader::readNumber() {
+  Location p = current_;
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : '\0';
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : '\0';
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : '\0';
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+  }
+}
+
+bool Reader::readString() {
+  Char c = '\0';
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+bool Reader::readObject(Token& token) {
+  Token tokenName;
+  String name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+      return true;
+    name.clear();
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover("Missing ':' after object member name", colon,
+                                tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover("Missing ',' or '}' in object declaration",
+                                comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover("Missing '}' or object member name", tokenName,
+                            tokenObjectEnd);
+}
+
+bool Reader::readArray(Token& token) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  skipSpaces();
+  if (current_ != end_ && *current_ == ']') // empty array
+  {
+    Token endArray;
+    readToken(endArray);
+    return true;
+  }
+  int index = 0;
+  for (;;) {
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token currentToken;
+    // Accept Comment after last item in the array.
+    ok = readToken(currentToken);
+    while (currentToken.type_ == tokenComment && ok) {
+      ok = readToken(currentToken);
+    }
+    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
+                         currentToken.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover("Missing ',' or ']' in array declaration",
+                                currentToken, tokenArrayEnd);
+    }
+    if (currentToken.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  bool isNegative = *current == '-';
+  if (isNegative)
+    ++current;
+  // TODO: Help the compiler do the div and mod at compile time or get rid of
+  // them.
+  Value::LargestUInt maxIntegerValue =
+      isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1
+                 : Value::maxLargestUInt;
+  Value::LargestUInt threshold = maxIntegerValue / 10;
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+    auto digit(static_cast<Value::UInt>(c - '0'));
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, b) this is the last digit, and
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > maxIntegerValue % 10) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+  if (isNegative && value == maxIntegerValue)
+    decoded = Value::minLargestInt;
+  else if (isNegative)
+    decoded = -Value::LargestInt(value);
+  else if (value <= Value::LargestUInt(Value::maxInt))
+    decoded = Value::LargestInt(value);
+  else
+    decoded = value;
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  String buffer(token.start_, token.end_);
+  IStringStream is(buffer);
+  if (!(is >> value))
+    return addError(
+        "'" + String(token.start_, token.end_) + "' is not a number.", token);
+  decoded = value;
+  return true;
+}
+
+bool Reader::decodeString(Token& token) {
+  String decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool Reader::decodeString(Token& token, String& decoded) {
+  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                    Location end, unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token, current);
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      unsigned int surrogatePair;
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token, current);
+  }
+  return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                         Location end,
+                                         unsigned int& ret_unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.", token,
+        current);
+  int unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token, current);
+  }
+  ret_unicode = static_cast<unsigned int>(unicode);
+  return true;
+}
+
+bool Reader::addError(const String& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken) {
+  size_t const errorCount = errors_.size();
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool Reader::addErrorAndRecover(const String& message, Token& token,
+                                TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& Reader::currentValue() { return *(nodes_.top()); }
+
+Reader::Char Reader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location, int& line,
+                                      int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+String Reader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+String Reader::getFormatedErrorMessages() const {
+  return getFormattedErrorMessages();
+}
+
+String Reader::getFormattedErrorMessages() const {
+  String formattedMessage;
+  for (const auto& error : errors_) {
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+  std::vector<Reader::StructuredError> allErrors;
+  for (const auto& error : errors_) {
+    Reader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+bool Reader::pushError(const Value& value, const String& message) {
+  ptrdiff_t const length = end_ - begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = nullptr;
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::pushError(const Value& value, const String& message,
+                       const Value& extra) {
+  ptrdiff_t const length = end_ - begin_;
+  if (value.getOffsetStart() > length || value.getOffsetLimit() > length ||
+      extra.getOffsetLimit() > length)
+    return false;
+  Token token;
+  token.type_ = tokenError;
+  token.start_ = begin_ + value.getOffsetStart();
+  token.end_ = begin_ + value.getOffsetLimit();
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = begin_ + extra.getOffsetStart();
+  errors_.push_back(info);
+  return true;
+}
+
+bool Reader::good() const { return errors_.empty(); }
+
+// Originally copied from the Features class (now deprecated), used internally
+// for features implementation.
+class OurFeatures {
+public:
+  static OurFeatures all();
+  bool allowComments_;
+  bool allowTrailingCommas_;
+  bool strictRoot_;
+  bool allowDroppedNullPlaceholders_;
+  bool allowNumericKeys_;
+  bool allowSingleQuotes_;
+  bool failIfExtra_;
+  bool rejectDupKeys_;
+  bool allowSpecialFloats_;
+  bool skipBom_;
+  size_t stackLimit_;
+}; // OurFeatures
+
+OurFeatures OurFeatures::all() { return {}; }
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+// Originally copied from the Reader class (now deprecated), used internally
+// for implementing JSON reading.
+class OurReader {
+public:
+  using Char = char;
+  using Location = const Char*;
+  struct StructuredError {
+    ptrdiff_t offset_start;
+    ptrdiff_t offset_limit;
+    String message;
+  };
+
+  explicit OurReader(OurFeatures const& features);
+  bool parse(const char* beginDoc, const char* endDoc, Value& root,
+             bool collectComments = true);
+  String getFormattedErrorMessages() const;
+  std::vector<StructuredError> getStructuredErrors() const;
+
+private:
+  OurReader(OurReader const&);      // no impl
+  void operator=(OurReader const&); // no impl
+
+  enum TokenType {
+    tokenEndOfStream = 0,
+    tokenObjectBegin,
+    tokenObjectEnd,
+    tokenArrayBegin,
+    tokenArrayEnd,
+    tokenString,
+    tokenNumber,
+    tokenTrue,
+    tokenFalse,
+    tokenNull,
+    tokenNaN,
+    tokenPosInf,
+    tokenNegInf,
+    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();
+  void skipBom(bool skipBom);
+  bool match(const Char* pattern, int patternLength);
+  bool readComment();
+  bool readCStyleComment(bool* containsNewLineResult);
+  bool readCppStyleComment();
+  bool readString();
+  bool readStringSingleQuote();
+  bool readNumber(bool checkInf);
+  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 String normalizeEOL(Location begin, Location end);
+  static bool containsNewLine(Location begin, Location end);
+
+  using Nodes = std::stack<Value*>;
+
+  Nodes nodes_{};
+  Errors errors_{};
+  String document_{};
+  Location begin_ = nullptr;
+  Location end_ = nullptr;
+  Location current_ = nullptr;
+  Location lastValueEnd_ = nullptr;
+  Value* lastValue_ = nullptr;
+  bool lastValueHasAComment_ = false;
+  String commentsBefore_{};
+
+  OurFeatures const features_;
+  bool collectComments_ = false;
+}; // OurReader
+
+// complete copy of Read impl, for OurReader
+
+bool OurReader::containsNewLine(OurReader::Location begin,
+                                OurReader::Location end) {
+  return std::any_of(begin, end, [](char b) { return b == '\n' || b == '\r'; });
+}
+
+OurReader::OurReader(OurFeatures const& features) : features_(features) {}
+
+bool OurReader::parse(const char* beginDoc, const char* endDoc, Value& root,
+                      bool collectComments) {
+  if (!features_.allowComments_) {
+    collectComments = false;
+  }
+
+  begin_ = beginDoc;
+  end_ = endDoc;
+  collectComments_ = collectComments;
+  current_ = begin_;
+  lastValueEnd_ = nullptr;
+  lastValue_ = nullptr;
+  commentsBefore_.clear();
+  errors_.clear();
+  while (!nodes_.empty())
+    nodes_.pop();
+  nodes_.push(&root);
+
+  // skip byte order mark if it exists at the beginning of the UTF-8 text.
+  skipBom(features_.skipBom_);
+  bool successful = readValue();
+  nodes_.pop();
+  Token token;
+  skipCommentTokens(token);
+  if (features_.failIfExtra_ && (token.type_ != tokenEndOfStream)) {
+    addError("Extra non-whitespace after JSON value.", token);
+    return false;
+  }
+  if (collectComments_ && !commentsBefore_.empty())
+    root.setComment(commentsBefore_, commentAfter);
+  if (features_.strictRoot_) {
+    if (!root.isArray() && !root.isObject()) {
+      // Set error location to start of doc, ideally should be first token found
+      // in doc
+      token.type_ = tokenError;
+      token.start_ = beginDoc;
+      token.end_ = endDoc;
+      addError(
+          "A valid JSON document must be either an array or an object value.",
+          token);
+      return false;
+    }
+  }
+  return successful;
+}
+
+bool OurReader::readValue() {
+  //  To preserve the old behaviour we cast size_t to int.
+  if (nodes_.size() > features_.stackLimit_)
+    throwRuntimeError("Exceeded stackLimit in readValue().");
+  Token token;
+  skipCommentTokens(token);
+  bool successful = true;
+
+  if (collectComments_ && !commentsBefore_.empty()) {
+    currentValue().setComment(commentsBefore_, commentBefore);
+    commentsBefore_.clear();
+  }
+
+  switch (token.type_) {
+  case tokenObjectBegin:
+    successful = readObject(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenArrayBegin:
+    successful = readArray(token);
+    currentValue().setOffsetLimit(current_ - begin_);
+    break;
+  case tokenNumber:
+    successful = decodeNumber(token);
+    break;
+  case tokenString:
+    successful = decodeString(token);
+    break;
+  case tokenTrue: {
+    Value v(true);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenFalse: {
+    Value v(false);
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenNull: {
+    Value v;
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenNaN: {
+    Value v(std::numeric_limits<double>::quiet_NaN());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenPosInf: {
+    Value v(std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenNegInf: {
+    Value v(-std::numeric_limits<double>::infinity());
+    currentValue().swapPayload(v);
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+  } break;
+  case tokenArraySeparator:
+  case tokenObjectEnd:
+  case tokenArrayEnd:
+    if (features_.allowDroppedNullPlaceholders_) {
+      // "Un-read" the current token and mark the current value as a null
+      // token.
+      current_--;
+      Value v;
+      currentValue().swapPayload(v);
+      currentValue().setOffsetStart(current_ - begin_ - 1);
+      currentValue().setOffsetLimit(current_ - begin_);
+      break;
+    } // else, fall through ...
+  default:
+    currentValue().setOffsetStart(token.start_ - begin_);
+    currentValue().setOffsetLimit(token.end_ - begin_);
+    return addError("Syntax error: value, object or array expected.", token);
+  }
+
+  if (collectComments_) {
+    lastValueEnd_ = current_;
+    lastValueHasAComment_ = false;
+    lastValue_ = &currentValue();
+  }
+
+  return successful;
+}
+
+void OurReader::skipCommentTokens(Token& token) {
+  if (features_.allowComments_) {
+    do {
+      readToken(token);
+    } while (token.type_ == tokenComment);
+  } else {
+    readToken(token);
+  }
+}
+
+bool OurReader::readToken(Token& token) {
+  skipSpaces();
+  token.start_ = current_;
+  Char c = getNextChar();
+  bool ok = true;
+  switch (c) {
+  case '{':
+    token.type_ = tokenObjectBegin;
+    break;
+  case '}':
+    token.type_ = tokenObjectEnd;
+    break;
+  case '[':
+    token.type_ = tokenArrayBegin;
+    break;
+  case ']':
+    token.type_ = tokenArrayEnd;
+    break;
+  case '"':
+    token.type_ = tokenString;
+    ok = readString();
+    break;
+  case '\'':
+    if (features_.allowSingleQuotes_) {
+      token.type_ = tokenString;
+      ok = readStringSingleQuote();
+    } else {
+      // If we don't allow single quotes, this is a failure case.
+      ok = false;
+    }
+    break;
+  case '/':
+    token.type_ = tokenComment;
+    ok = readComment();
+    break;
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    token.type_ = tokenNumber;
+    readNumber(false);
+    break;
+  case '-':
+    if (readNumber(true)) {
+      token.type_ = tokenNumber;
+    } else {
+      token.type_ = tokenNegInf;
+      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+    }
+    break;
+  case '+':
+    if (readNumber(true)) {
+      token.type_ = tokenNumber;
+    } else {
+      token.type_ = tokenPosInf;
+      ok = features_.allowSpecialFloats_ && match("nfinity", 7);
+    }
+    break;
+  case 't':
+    token.type_ = tokenTrue;
+    ok = match("rue", 3);
+    break;
+  case 'f':
+    token.type_ = tokenFalse;
+    ok = match("alse", 4);
+    break;
+  case 'n':
+    token.type_ = tokenNull;
+    ok = match("ull", 3);
+    break;
+  case 'N':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenNaN;
+      ok = match("aN", 2);
+    } else {
+      ok = false;
+    }
+    break;
+  case 'I':
+    if (features_.allowSpecialFloats_) {
+      token.type_ = tokenPosInf;
+      ok = match("nfinity", 7);
+    } else {
+      ok = false;
+    }
+    break;
+  case ',':
+    token.type_ = tokenArraySeparator;
+    break;
+  case ':':
+    token.type_ = tokenMemberSeparator;
+    break;
+  case 0:
+    token.type_ = tokenEndOfStream;
+    break;
+  default:
+    ok = false;
+    break;
+  }
+  if (!ok)
+    token.type_ = tokenError;
+  token.end_ = current_;
+  return ok;
+}
+
+void OurReader::skipSpaces() {
+  while (current_ != end_) {
+    Char c = *current_;
+    if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+      ++current_;
+    else
+      break;
+  }
+}
+
+void OurReader::skipBom(bool skipBom) {
+  // The default behavior is to skip BOM.
+  if (skipBom) {
+    if ((end_ - begin_) >= 3 && strncmp(begin_, "\xEF\xBB\xBF", 3) == 0) {
+      begin_ += 3;
+      current_ = begin_;
+    }
+  }
+}
+
+bool OurReader::match(const Char* pattern, int patternLength) {
+  if (end_ - current_ < patternLength)
+    return false;
+  int index = patternLength;
+  while (index--)
+    if (current_[index] != pattern[index])
+      return false;
+  current_ += patternLength;
+  return true;
+}
+
+bool OurReader::readComment() {
+  const Location commentBegin = current_ - 1;
+  const Char c = getNextChar();
+  bool successful = false;
+  bool cStyleWithEmbeddedNewline = false;
+
+  const bool isCStyleComment = (c == '*');
+  const bool isCppStyleComment = (c == '/');
+  if (isCStyleComment) {
+    successful = readCStyleComment(&cStyleWithEmbeddedNewline);
+  } else if (isCppStyleComment) {
+    successful = readCppStyleComment();
+  }
+
+  if (!successful)
+    return false;
+
+  if (collectComments_) {
+    CommentPlacement placement = commentBefore;
+
+    if (!lastValueHasAComment_) {
+      if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+        if (isCppStyleComment || !cStyleWithEmbeddedNewline) {
+          placement = commentAfterOnSameLine;
+          lastValueHasAComment_ = true;
+        }
+      }
+    }
+
+    addComment(commentBegin, current_, placement);
+  }
+  return true;
+}
+
+String OurReader::normalizeEOL(OurReader::Location begin,
+                               OurReader::Location end) {
+  String normalized;
+  normalized.reserve(static_cast<size_t>(end - begin));
+  OurReader::Location current = begin;
+  while (current != end) {
+    char c = *current++;
+    if (c == '\r') {
+      if (current != end && *current == '\n')
+        // convert dos EOL
+        ++current;
+      // convert Mac EOL
+      normalized += '\n';
+    } else {
+      normalized += c;
+    }
+  }
+  return normalized;
+}
+
+void OurReader::addComment(Location begin, Location end,
+                           CommentPlacement placement) {
+  assert(collectComments_);
+  const String& normalized = normalizeEOL(begin, end);
+  if (placement == commentAfterOnSameLine) {
+    assert(lastValue_ != nullptr);
+    lastValue_->setComment(normalized, placement);
+  } else {
+    commentsBefore_ += normalized;
+  }
+}
+
+bool OurReader::readCStyleComment(bool* containsNewLineResult) {
+  *containsNewLineResult = false;
+
+  while ((current_ + 1) < end_) {
+    Char c = getNextChar();
+    if (c == '*' && *current_ == '/')
+      break;
+    if (c == '\n')
+      *containsNewLineResult = true;
+  }
+
+  return getNextChar() == '/';
+}
+
+bool OurReader::readCppStyleComment() {
+  while (current_ != end_) {
+    Char c = getNextChar();
+    if (c == '\n')
+      break;
+    if (c == '\r') {
+      // Consume DOS EOL. It will be normalized in addComment.
+      if (current_ != end_ && *current_ == '\n')
+        getNextChar();
+      // Break on Moc OS 9 EOL.
+      break;
+    }
+  }
+  return true;
+}
+
+bool OurReader::readNumber(bool checkInf) {
+  Location p = current_;
+  if (checkInf && p != end_ && *p == 'I') {
+    current_ = ++p;
+    return false;
+  }
+  char c = '0'; // stopgap for already consumed character
+  // integral part
+  while (c >= '0' && c <= '9')
+    c = (current_ = p) < end_ ? *p++ : '\0';
+  // fractional part
+  if (c == '.') {
+    c = (current_ = p) < end_ ? *p++ : '\0';
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+  }
+  // exponential part
+  if (c == 'e' || c == 'E') {
+    c = (current_ = p) < end_ ? *p++ : '\0';
+    if (c == '+' || c == '-')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+    while (c >= '0' && c <= '9')
+      c = (current_ = p) < end_ ? *p++ : '\0';
+  }
+  return true;
+}
+bool OurReader::readString() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '"')
+      break;
+  }
+  return c == '"';
+}
+
+bool OurReader::readStringSingleQuote() {
+  Char c = 0;
+  while (current_ != end_) {
+    c = getNextChar();
+    if (c == '\\')
+      getNextChar();
+    else if (c == '\'')
+      break;
+  }
+  return c == '\'';
+}
+
+bool OurReader::readObject(Token& token) {
+  Token tokenName;
+  String name;
+  Value init(objectValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  while (readToken(tokenName)) {
+    bool initialTokenOk = true;
+    while (tokenName.type_ == tokenComment && initialTokenOk)
+      initialTokenOk = readToken(tokenName);
+    if (!initialTokenOk)
+      break;
+    if (tokenName.type_ == tokenObjectEnd &&
+        (name.empty() ||
+         features_.allowTrailingCommas_)) // empty object or trailing comma
+      return true;
+    name.clear();
+    if (tokenName.type_ == tokenString) {
+      if (!decodeString(tokenName, name))
+        return recoverFromError(tokenObjectEnd);
+    } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+      Value numberName;
+      if (!decodeNumber(tokenName, numberName))
+        return recoverFromError(tokenObjectEnd);
+      name = numberName.asString();
+    } else {
+      break;
+    }
+    if (name.length() >= (1U << 30))
+      throwRuntimeError("keylength >= 2^30");
+    if (features_.rejectDupKeys_ && currentValue().isMember(name)) {
+      String msg = "Duplicate key: '" + name + "'";
+      return addErrorAndRecover(msg, tokenName, tokenObjectEnd);
+    }
+
+    Token colon;
+    if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+      return addErrorAndRecover("Missing ':' after object member name", colon,
+                                tokenObjectEnd);
+    }
+    Value& value = currentValue()[name];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenObjectEnd);
+
+    Token comma;
+    if (!readToken(comma) ||
+        (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+         comma.type_ != tokenComment)) {
+      return addErrorAndRecover("Missing ',' or '}' in object declaration",
+                                comma, tokenObjectEnd);
+    }
+    bool finalizeTokenOk = true;
+    while (comma.type_ == tokenComment && finalizeTokenOk)
+      finalizeTokenOk = readToken(comma);
+    if (comma.type_ == tokenObjectEnd)
+      return true;
+  }
+  return addErrorAndRecover("Missing '}' or object member name", tokenName,
+                            tokenObjectEnd);
+}
+
+bool OurReader::readArray(Token& token) {
+  Value init(arrayValue);
+  currentValue().swapPayload(init);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  int index = 0;
+  for (;;) {
+    skipSpaces();
+    if (current_ != end_ && *current_ == ']' &&
+        (index == 0 ||
+         (features_.allowTrailingCommas_ &&
+          !features_.allowDroppedNullPlaceholders_))) // empty array or trailing
+                                                      // comma
+    {
+      Token endArray;
+      readToken(endArray);
+      return true;
+    }
+    Value& value = currentValue()[index++];
+    nodes_.push(&value);
+    bool ok = readValue();
+    nodes_.pop();
+    if (!ok) // error already set
+      return recoverFromError(tokenArrayEnd);
+
+    Token currentToken;
+    // Accept Comment after last item in the array.
+    ok = readToken(currentToken);
+    while (currentToken.type_ == tokenComment && ok) {
+      ok = readToken(currentToken);
+    }
+    bool badTokenType = (currentToken.type_ != tokenArraySeparator &&
+                         currentToken.type_ != tokenArrayEnd);
+    if (!ok || badTokenType) {
+      return addErrorAndRecover("Missing ',' or ']' in array declaration",
+                                currentToken, tokenArrayEnd);
+    }
+    if (currentToken.type_ == tokenArrayEnd)
+      break;
+  }
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token) {
+  Value decoded;
+  if (!decodeNumber(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeNumber(Token& token, Value& decoded) {
+  // Attempts to parse the number as an integer. If the number is
+  // larger than the maximum supported value of an integer then
+  // we decode the number as a double.
+  Location current = token.start_;
+  const bool isNegative = *current == '-';
+  if (isNegative) {
+    ++current;
+  }
+
+  // We assume we can represent the largest and smallest integer types as
+  // unsigned integers with separate sign. This is only true if they can fit
+  // into an unsigned integer.
+  static_assert(Value::maxLargestInt <= Value::maxLargestUInt,
+                "Int must be smaller than UInt");
+
+  // We need to convert minLargestInt into a positive number. The easiest way
+  // to do this conversion is to assume our "threshold" value of minLargestInt
+  // divided by 10 can fit in maxLargestInt when absolute valued. This should
+  // be a safe assumption.
+  static_assert(Value::minLargestInt <= -Value::maxLargestInt,
+                "The absolute value of minLargestInt must be greater than or "
+                "equal to maxLargestInt");
+  static_assert(Value::minLargestInt / 10 >= -Value::maxLargestInt,
+                "The absolute value of minLargestInt must be only 1 magnitude "
+                "larger than maxLargest Int");
+
+  static constexpr Value::LargestUInt positive_threshold =
+      Value::maxLargestUInt / 10;
+  static constexpr Value::UInt positive_last_digit = Value::maxLargestUInt % 10;
+
+  // For the negative values, we have to be more careful. Since typically
+  // -Value::minLargestInt will cause an overflow, we first divide by 10 and
+  // then take the inverse. This assumes that minLargestInt is only a single
+  // power of 10 different in magnitude, which we check above. For the last
+  // digit, we take the modulus before negating for the same reason.
+  static constexpr auto negative_threshold =
+      Value::LargestUInt(-(Value::minLargestInt / 10));
+  static constexpr auto negative_last_digit =
+      Value::UInt(-(Value::minLargestInt % 10));
+
+  const Value::LargestUInt threshold =
+      isNegative ? negative_threshold : positive_threshold;
+  const Value::UInt max_last_digit =
+      isNegative ? negative_last_digit : positive_last_digit;
+
+  Value::LargestUInt value = 0;
+  while (current < token.end_) {
+    Char c = *current++;
+    if (c < '0' || c > '9')
+      return decodeDouble(token, decoded);
+
+    const auto digit(static_cast<Value::UInt>(c - '0'));
+    if (value >= threshold) {
+      // We've hit or exceeded the max value divided by 10 (rounded down). If
+      // a) we've only just touched the limit, meaing value == threshold,
+      // b) this is the last digit, or
+      // c) it's small enough to fit in that rounding delta, we're okay.
+      // Otherwise treat this number as a double to avoid overflow.
+      if (value > threshold || current != token.end_ ||
+          digit > max_last_digit) {
+        return decodeDouble(token, decoded);
+      }
+    }
+    value = value * 10 + digit;
+  }
+
+  if (isNegative) {
+    // We use the same magnitude assumption here, just in case.
+    const auto last_digit = static_cast<Value::UInt>(value % 10);
+    decoded = -Value::LargestInt(value / 10) * 10 - last_digit;
+  } else if (value <= Value::LargestUInt(Value::maxLargestInt)) {
+    decoded = Value::LargestInt(value);
+  } else {
+    decoded = value;
+  }
+
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token) {
+  Value decoded;
+  if (!decodeDouble(token, decoded))
+    return false;
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeDouble(Token& token, Value& decoded) {
+  double value = 0;
+  const String buffer(token.start_, token.end_);
+  IStringStream is(buffer);
+  if (!(is >> value)) {
+    return addError(
+        "'" + String(token.start_, token.end_) + "' is not a number.", token);
+  }
+  decoded = value;
+  return true;
+}
+
+bool OurReader::decodeString(Token& token) {
+  String decoded_string;
+  if (!decodeString(token, decoded_string))
+    return false;
+  Value decoded(decoded_string);
+  currentValue().swapPayload(decoded);
+  currentValue().setOffsetStart(token.start_ - begin_);
+  currentValue().setOffsetLimit(token.end_ - begin_);
+  return true;
+}
+
+bool OurReader::decodeString(Token& token, String& decoded) {
+  decoded.reserve(static_cast<size_t>(token.end_ - token.start_ - 2));
+  Location current = token.start_ + 1; // skip '"'
+  Location end = token.end_ - 1;       // do not include '"'
+  while (current != end) {
+    Char c = *current++;
+    if (c == '"')
+      break;
+    if (c == '\\') {
+      if (current == end)
+        return addError("Empty escape sequence in string", token, current);
+      Char escape = *current++;
+      switch (escape) {
+      case '"':
+        decoded += '"';
+        break;
+      case '/':
+        decoded += '/';
+        break;
+      case '\\':
+        decoded += '\\';
+        break;
+      case 'b':
+        decoded += '\b';
+        break;
+      case 'f':
+        decoded += '\f';
+        break;
+      case 'n':
+        decoded += '\n';
+        break;
+      case 'r':
+        decoded += '\r';
+        break;
+      case 't':
+        decoded += '\t';
+        break;
+      case 'u': {
+        unsigned int unicode;
+        if (!decodeUnicodeCodePoint(token, current, end, unicode))
+          return false;
+        decoded += codePointToUTF8(unicode);
+      } break;
+      default:
+        return addError("Bad escape sequence in string", token, current);
+      }
+    } else {
+      decoded += c;
+    }
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeCodePoint(Token& token, Location& current,
+                                       Location end, unsigned int& unicode) {
+
+  if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+    return false;
+  if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+    // surrogate pairs
+    if (end - current < 6)
+      return addError(
+          "additional six characters expected to parse unicode surrogate pair.",
+          token, current);
+    if (*(current++) == '\\' && *(current++) == 'u') {
+      unsigned int surrogatePair;
+      if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+        unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+      } else
+        return false;
+    } else
+      return addError("expecting another \\u token to begin the second half of "
+                      "a unicode surrogate pair",
+                      token, current);
+  }
+  return true;
+}
+
+bool OurReader::decodeUnicodeEscapeSequence(Token& token, Location& current,
+                                            Location end,
+                                            unsigned int& ret_unicode) {
+  if (end - current < 4)
+    return addError(
+        "Bad unicode escape sequence in string: four digits expected.", token,
+        current);
+  int unicode = 0;
+  for (int index = 0; index < 4; ++index) {
+    Char c = *current++;
+    unicode *= 16;
+    if (c >= '0' && c <= '9')
+      unicode += c - '0';
+    else if (c >= 'a' && c <= 'f')
+      unicode += c - 'a' + 10;
+    else if (c >= 'A' && c <= 'F')
+      unicode += c - 'A' + 10;
+    else
+      return addError(
+          "Bad unicode escape sequence in string: hexadecimal digit expected.",
+          token, current);
+  }
+  ret_unicode = static_cast<unsigned int>(unicode);
+  return true;
+}
+
+bool OurReader::addError(const String& message, Token& token, Location extra) {
+  ErrorInfo info;
+  info.token_ = token;
+  info.message_ = message;
+  info.extra_ = extra;
+  errors_.push_back(info);
+  return false;
+}
+
+bool OurReader::recoverFromError(TokenType skipUntilToken) {
+  size_t errorCount = errors_.size();
+  Token skip;
+  for (;;) {
+    if (!readToken(skip))
+      errors_.resize(errorCount); // discard errors caused by recovery
+    if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+      break;
+  }
+  errors_.resize(errorCount);
+  return false;
+}
+
+bool OurReader::addErrorAndRecover(const String& message, Token& token,
+                                   TokenType skipUntilToken) {
+  addError(message, token);
+  return recoverFromError(skipUntilToken);
+}
+
+Value& OurReader::currentValue() { return *(nodes_.top()); }
+
+OurReader::Char OurReader::getNextChar() {
+  if (current_ == end_)
+    return 0;
+  return *current_++;
+}
+
+void OurReader::getLocationLineAndColumn(Location location, int& line,
+                                         int& column) const {
+  Location current = begin_;
+  Location lastLineStart = current;
+  line = 0;
+  while (current < location && current != end_) {
+    Char c = *current++;
+    if (c == '\r') {
+      if (*current == '\n')
+        ++current;
+      lastLineStart = current;
+      ++line;
+    } else if (c == '\n') {
+      lastLineStart = current;
+      ++line;
+    }
+  }
+  // column & line start at 1
+  column = int(location - lastLineStart) + 1;
+  ++line;
+}
+
+String OurReader::getLocationLineAndColumn(Location location) const {
+  int line, column;
+  getLocationLineAndColumn(location, line, column);
+  char buffer[18 + 16 + 16 + 1];
+  jsoncpp_snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+  return buffer;
+}
+
+String OurReader::getFormattedErrorMessages() const {
+  String formattedMessage;
+  for (const auto& error : errors_) {
+    formattedMessage +=
+        "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+    formattedMessage += "  " + error.message_ + "\n";
+    if (error.extra_)
+      formattedMessage +=
+          "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+  }
+  return formattedMessage;
+}
+
+std::vector<OurReader::StructuredError> OurReader::getStructuredErrors() const {
+  std::vector<OurReader::StructuredError> allErrors;
+  for (const auto& error : errors_) {
+    OurReader::StructuredError structured;
+    structured.offset_start = error.token_.start_ - begin_;
+    structured.offset_limit = error.token_.end_ - begin_;
+    structured.message = error.message_;
+    allErrors.push_back(structured);
+  }
+  return allErrors;
+}
+
+class OurCharReader : public CharReader {
+  bool const collectComments_;
+  OurReader reader_;
+
+public:
+  OurCharReader(bool collectComments, OurFeatures const& features)
+      : collectComments_(collectComments), reader_(features) {}
+  bool parse(char const* beginDoc, char const* endDoc, Value* root,
+             String* errs) override {
+    bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_);
+    if (errs) {
+      *errs = reader_.getFormattedErrorMessages();
+    }
+    return ok;
+  }
+};
+
+CharReaderBuilder::CharReaderBuilder() { setDefaults(&settings_); }
+CharReaderBuilder::~CharReaderBuilder() = default;
+CharReader* CharReaderBuilder::newCharReader() const {
+  bool collectComments = settings_["collectComments"].asBool();
+  OurFeatures features = OurFeatures::all();
+  features.allowComments_ = settings_["allowComments"].asBool();
+  features.allowTrailingCommas_ = settings_["allowTrailingCommas"].asBool();
+  features.strictRoot_ = settings_["strictRoot"].asBool();
+  features.allowDroppedNullPlaceholders_ =
+      settings_["allowDroppedNullPlaceholders"].asBool();
+  features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool();
+  features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool();
+
+  // Stack limit is always a size_t, so we get this as an unsigned int
+  // regardless of it we have 64-bit integer support enabled.
+  features.stackLimit_ = static_cast<size_t>(settings_["stackLimit"].asUInt());
+  features.failIfExtra_ = settings_["failIfExtra"].asBool();
+  features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool();
+  features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool();
+  features.skipBom_ = settings_["skipBom"].asBool();
+  return new OurCharReader(collectComments, features);
+}
+
+bool CharReaderBuilder::validate(Json::Value* invalid) const {
+  static const auto& valid_keys = *new std::set<String>{
+      "collectComments",
+      "allowComments",
+      "allowTrailingCommas",
+      "strictRoot",
+      "allowDroppedNullPlaceholders",
+      "allowNumericKeys",
+      "allowSingleQuotes",
+      "stackLimit",
+      "failIfExtra",
+      "rejectDupKeys",
+      "allowSpecialFloats",
+      "skipBom",
+  };
+  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+    auto key = si.name();
+    if (valid_keys.count(key))
+      continue;
+    if (invalid)
+      (*invalid)[key] = *si;
+    else
+      return false;
+  }
+  return invalid ? invalid->empty() : true;
+}
+
+Value& CharReaderBuilder::operator[](const String& key) {
+  return settings_[key];
+}
+// static
+void CharReaderBuilder::strictMode(Json::Value* settings) {
+  //! [CharReaderBuilderStrictMode]
+  (*settings)["allowComments"] = false;
+  (*settings)["allowTrailingCommas"] = false;
+  (*settings)["strictRoot"] = true;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = true;
+  (*settings)["rejectDupKeys"] = true;
+  (*settings)["allowSpecialFloats"] = false;
+  (*settings)["skipBom"] = true;
+  //! [CharReaderBuilderStrictMode]
+}
+// static
+void CharReaderBuilder::setDefaults(Json::Value* settings) {
+  //! [CharReaderBuilderDefaults]
+  (*settings)["collectComments"] = true;
+  (*settings)["allowComments"] = true;
+  (*settings)["allowTrailingCommas"] = true;
+  (*settings)["strictRoot"] = false;
+  (*settings)["allowDroppedNullPlaceholders"] = false;
+  (*settings)["allowNumericKeys"] = false;
+  (*settings)["allowSingleQuotes"] = false;
+  (*settings)["stackLimit"] = 1000;
+  (*settings)["failIfExtra"] = false;
+  (*settings)["rejectDupKeys"] = false;
+  (*settings)["allowSpecialFloats"] = false;
+  (*settings)["skipBom"] = true;
+  //! [CharReaderBuilderDefaults]
+}
+
+//////////////////////////////////
+// global functions
+
+bool parseFromStream(CharReader::Factory const& fact, IStream& sin, Value* root,
+                     String* errs) {
+  OStringStream ssin;
+  ssin << sin.rdbuf();
+  String doc = ssin.str();
+  char const* begin = doc.data();
+  char const* end = begin + doc.size();
+  // Note that we do not actually need a null-terminator.
+  CharReaderPtr const reader(fact.newCharReader());
+  return reader->parse(begin, end, root, errs);
+}
+
+IStream& operator>>(IStream& sin, Value& root) {
+  CharReaderBuilder b;
+  String errs;
+  bool ok = parseFromStream(b, sin, &root, &errs);
+  if (!ok) {
+    throwRuntimeError(errs);
+  }
+  return sin;
+}
+
+} // namespace Json

+ 138 - 0
thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_tool.h

@@ -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

+ 1634 - 0
thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_value.cpp

@@ -0,0 +1,1634 @@
+// Copyright 2011 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
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <utility>
+
+// Provide implementation equivalent of std::snprintf for older _MSC compilers
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#include <stdarg.h>
+static int msvc_pre1900_c99_vsnprintf(char* outBuf, size_t size,
+                                      const char* format, va_list ap) {
+  int count = -1;
+  if (size != 0)
+    count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap);
+  if (count == -1)
+    count = _vscprintf(format, ap);
+  return count;
+}
+
+int JSON_API msvc_pre1900_c99_snprintf(char* outBuf, size_t size,
+                                       const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  const int count = msvc_pre1900_c99_vsnprintf(outBuf, size, format, ap);
+  va_end(ap);
+  return count;
+}
+#endif
+
+// Disable warning C4702 : unreachable code
+#if defined(_MSC_VER)
+#pragma warning(disable : 4702)
+#endif
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json {
+template <typename T>
+static std::unique_ptr<T> cloneUnique(const std::unique_ptr<T>& p) {
+  std::unique_ptr<T> r;
+  if (p) {
+    r = std::unique_ptr<T>(new T(*p));
+  }
+  return r;
+}
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM.  We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+
+// static
+Value const& Value::nullSingleton() {
+  static Value const nullStatic;
+  return nullStatic;
+}
+
+#if JSON_USE_NULLREF
+// for backwards compatibility, we'll leave these global references around, but
+// DO NOT use them in JSONCPP library code any more!
+// static
+Value const& Value::null = Value::nullSingleton();
+
+// static
+Value const& Value::nullRef = Value::nullSingleton();
+#endif
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  // The casts can lose precision, but we are looking only for
+  // an approximate range. Might fail on edge cases though. ~cdunn
+  return d >= static_cast<double>(min) && d <= static_cast<double>(max);
+}
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value) {
+  return static_cast<double>(Int64(value / 2)) * 2.0 +
+         static_cast<double>(Int64(value & 1));
+}
+
+template <typename T> static inline double integerToDouble(T value) {
+  return static_cast<double>(value);
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+  return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ *              length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ *               computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char* duplicateStringValue(const char* value, size_t length) {
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  if (length >= static_cast<size_t>(Value::maxInt))
+    length = Value::maxInt - 1;
+
+  auto newString = static_cast<char*>(malloc(length + 1));
+  if (newString == nullptr) {
+    throwRuntimeError("in Json::Value::duplicateStringValue(): "
+                      "Failed to allocate string value buffer");
+  }
+  memcpy(newString, value, length);
+  newString[length] = 0;
+  return newString;
+}
+
+/* Record the length as a prefix.
+ */
+static inline char* duplicateAndPrefixStringValue(const char* value,
+                                                  unsigned int length) {
+  // Avoid an integer overflow in the call to malloc below by limiting length
+  // to a sane value.
+  JSON_ASSERT_MESSAGE(length <= static_cast<unsigned>(Value::maxInt) -
+                                    sizeof(unsigned) - 1U,
+                      "in Json::Value::duplicateAndPrefixStringValue(): "
+                      "length too big for prefixing");
+  size_t actualLength = sizeof(length) + length + 1;
+  auto newString = static_cast<char*>(malloc(actualLength));
+  if (newString == nullptr) {
+    throwRuntimeError("in Json::Value::duplicateAndPrefixStringValue(): "
+                      "Failed to allocate string value buffer");
+  }
+  *reinterpret_cast<unsigned*>(newString) = length;
+  memcpy(newString + sizeof(unsigned), value, length);
+  newString[actualLength - 1U] =
+      0; // to avoid buffer over-run accidents by users later
+  return newString;
+}
+inline static void decodePrefixedString(bool isPrefixed, char const* prefixed,
+                                        unsigned* length, char const** value) {
+  if (!isPrefixed) {
+    *length = static_cast<unsigned>(strlen(prefixed));
+    *value = prefixed;
+  } else {
+    *length = *reinterpret_cast<unsigned const*>(prefixed);
+    *value = prefixed + sizeof(unsigned);
+  }
+}
+/** Free the string duplicated by
+ * duplicateStringValue()/duplicateAndPrefixStringValue().
+ */
+#if JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char* value) {
+  unsigned length = 0;
+  char const* valueDecoded;
+  decodePrefixedString(true, value, &length, &valueDecoded);
+  size_t const size = sizeof(unsigned) + length + 1U;
+  memset(value, 0, size);
+  free(value);
+}
+static inline void releaseStringValue(char* value, unsigned length) {
+  // length==0 => we allocated the strings memory
+  size_t size = (length == 0) ? strlen(value) : length;
+  memset(value, 0, size);
+  free(value);
+}
+#else  // !JSONCPP_USING_SECURE_MEMORY
+static inline void releasePrefixedStringValue(char* value) { free(value); }
+static inline void releaseStringValue(char* value, unsigned) { free(value); }
+#endif // JSONCPP_USING_SECURE_MEMORY
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+#if JSON_USE_EXCEPTION
+Exception::Exception(String msg) : msg_(std::move(msg)) {}
+Exception::~Exception() noexcept = default;
+char const* Exception::what() const noexcept { return msg_.c_str(); }
+RuntimeError::RuntimeError(String const& msg) : Exception(msg) {}
+LogicError::LogicError(String const& msg) : Exception(msg) {}
+JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
+  throw RuntimeError(msg);
+}
+JSONCPP_NORETURN void throwLogicError(String const& msg) {
+  throw LogicError(msg);
+}
+#else // !JSON_USE_EXCEPTION
+JSONCPP_NORETURN void throwRuntimeError(String const& msg) {
+  std::cerr << msg << std::endl;
+  abort();
+}
+JSONCPP_NORETURN void throwLogicError(String const& msg) {
+  std::cerr << msg << std::endl;
+  abort();
+}
+#endif
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+// Notes: policy_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(ArrayIndex index) : cstr_(nullptr), index_(index) {}
+
+Value::CZString::CZString(char const* str, unsigned length,
+                          DuplicationPolicy allocate)
+    : cstr_(str) {
+  // allocate != duplicate
+  storage_.policy_ = allocate & 0x3;
+  storage_.length_ = length & 0x3FFFFFFF;
+}
+
+Value::CZString::CZString(const CZString& other) {
+  cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != nullptr
+               ? duplicateStringValue(other.cstr_, other.storage_.length_)
+               : other.cstr_);
+  storage_.policy_ =
+      static_cast<unsigned>(
+          other.cstr_
+              ? (static_cast<DuplicationPolicy>(other.storage_.policy_) ==
+                         noDuplication
+                     ? noDuplication
+                     : duplicate)
+              : static_cast<DuplicationPolicy>(other.storage_.policy_)) &
+      3U;
+  storage_.length_ = other.storage_.length_;
+}
+
+Value::CZString::CZString(CZString&& other) noexcept
+    : cstr_(other.cstr_), index_(other.index_) {
+  other.cstr_ = nullptr;
+}
+
+Value::CZString::~CZString() {
+  if (cstr_ && storage_.policy_ == duplicate) {
+    releaseStringValue(const_cast<char*>(cstr_),
+                       storage_.length_ + 1U); // +1 for null terminating
+                                               // character for sake of
+                                               // completeness but not actually
+                                               // necessary
+  }
+}
+
+void Value::CZString::swap(CZString& other) {
+  std::swap(cstr_, other.cstr_);
+  std::swap(index_, other.index_);
+}
+
+Value::CZString& Value::CZString::operator=(const CZString& other) {
+  cstr_ = other.cstr_;
+  index_ = other.index_;
+  return *this;
+}
+
+Value::CZString& Value::CZString::operator=(CZString&& other) noexcept {
+  cstr_ = other.cstr_;
+  index_ = other.index_;
+  other.cstr_ = nullptr;
+  return *this;
+}
+
+bool Value::CZString::operator<(const CZString& other) const {
+  if (!cstr_)
+    return index_ < other.index_;
+  // return strcmp(cstr_, other.cstr_) < 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  unsigned min_len = std::min<unsigned>(this_len, other_len);
+  JSON_ASSERT(this->cstr_ && other.cstr_);
+  int comp = memcmp(this->cstr_, other.cstr_, min_len);
+  if (comp < 0)
+    return true;
+  if (comp > 0)
+    return false;
+  return (this_len < other_len);
+}
+
+bool Value::CZString::operator==(const CZString& other) const {
+  if (!cstr_)
+    return index_ == other.index_;
+  // return strcmp(cstr_, other.cstr_) == 0;
+  // Assume both are strings.
+  unsigned this_len = this->storage_.length_;
+  unsigned other_len = other.storage_.length_;
+  if (this_len != other_len)
+    return false;
+  JSON_ASSERT(this->cstr_ && other.cstr_);
+  int comp = memcmp(this->cstr_, other.cstr_, this_len);
+  return comp == 0;
+}
+
+ArrayIndex Value::CZString::index() const { return index_; }
+
+// const char* Value::CZString::c_str() const { return cstr_; }
+const char* Value::CZString::data() const { return cstr_; }
+unsigned Value::CZString::length() const { return storage_.length_; }
+bool Value::CZString::isStaticString() const {
+  return storage_.policy_ == noDuplication;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType type) {
+  static char const emptyString[] = "";
+  initBasic(type);
+  switch (type) {
+  case nullValue:
+    break;
+  case intValue:
+  case uintValue:
+    value_.int_ = 0;
+    break;
+  case realValue:
+    value_.real_ = 0.0;
+    break;
+  case stringValue:
+    // allocated_ == false, so this is safe.
+    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues();
+    break;
+  case booleanValue:
+    value_.bool_ = false;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+Value::Value(Int value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+
+Value::Value(UInt value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value) {
+  initBasic(intValue);
+  value_.int_ = value;
+}
+Value::Value(UInt64 value) {
+  initBasic(uintValue);
+  value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value) {
+  initBasic(realValue);
+  value_.real_ = value;
+}
+
+Value::Value(const char* value) {
+  initBasic(stringValue, true);
+  JSON_ASSERT_MESSAGE(value != nullptr,
+                      "Null Value Passed to Value Constructor");
+  value_.string_ = duplicateAndPrefixStringValue(
+      value, static_cast<unsigned>(strlen(value)));
+}
+
+Value::Value(const char* begin, const char* end) {
+  initBasic(stringValue, true);
+  value_.string_ =
+      duplicateAndPrefixStringValue(begin, static_cast<unsigned>(end - begin));
+}
+
+Value::Value(const String& value) {
+  initBasic(stringValue, true);
+  value_.string_ = duplicateAndPrefixStringValue(
+      value.data(), static_cast<unsigned>(value.length()));
+}
+
+Value::Value(const StaticString& value) {
+  initBasic(stringValue);
+  value_.string_ = const_cast<char*>(value.c_str());
+}
+
+Value::Value(bool value) {
+  initBasic(booleanValue);
+  value_.bool_ = value;
+}
+
+Value::Value(const Value& other) {
+  dupPayload(other);
+  dupMeta(other);
+}
+
+Value::Value(Value&& other) noexcept {
+  initBasic(nullValue);
+  swap(other);
+}
+
+Value::~Value() {
+  releasePayload();
+  value_.uint_ = 0;
+}
+
+Value& Value::operator=(const Value& other) {
+  Value(other).swap(*this);
+  return *this;
+}
+
+Value& Value::operator=(Value&& other) noexcept {
+  other.swap(*this);
+  return *this;
+}
+
+void Value::swapPayload(Value& other) {
+  std::swap(bits_, other.bits_);
+  std::swap(value_, other.value_);
+}
+
+void Value::copyPayload(const Value& other) {
+  releasePayload();
+  dupPayload(other);
+}
+
+void Value::swap(Value& other) {
+  swapPayload(other);
+  std::swap(comments_, other.comments_);
+  std::swap(start_, other.start_);
+  std::swap(limit_, other.limit_);
+}
+
+void Value::copy(const Value& other) {
+  copyPayload(other);
+  dupMeta(other);
+}
+
+ValueType Value::type() const {
+  return static_cast<ValueType>(bits_.value_type_);
+}
+
+int Value::compare(const Value& other) const {
+  if (*this < other)
+    return -1;
+  if (*this > other)
+    return 1;
+  return 0;
+}
+
+bool Value::operator<(const Value& other) const {
+  int typeDelta = type() - other.type();
+  if (typeDelta)
+    return typeDelta < 0;
+  switch (type()) {
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ < other.value_.int_;
+  case uintValue:
+    return value_.uint_ < other.value_.uint_;
+  case realValue:
+    return value_.real_ < other.value_.real_;
+  case booleanValue:
+    return value_.bool_ < other.value_.bool_;
+  case stringValue: {
+    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
+      return other.value_.string_ != nullptr;
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
+                         &other_str);
+    unsigned min_len = std::min<unsigned>(this_len, other_len);
+    JSON_ASSERT(this_str && other_str);
+    int comp = memcmp(this_str, other_str, min_len);
+    if (comp < 0)
+      return true;
+    if (comp > 0)
+      return false;
+    return (this_len < other_len);
+  }
+  case arrayValue:
+  case objectValue: {
+    auto thisSize = value_.map_->size();
+    auto otherSize = other.value_.map_->size();
+    if (thisSize != otherSize)
+      return thisSize < otherSize;
+    return (*value_.map_) < (*other.value_.map_);
+  }
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator<=(const Value& other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value& other) const { return !(*this < other); }
+
+bool Value::operator>(const Value& other) const { return other < *this; }
+
+bool Value::operator==(const Value& other) const {
+  if (type() != other.type())
+    return false;
+  switch (type()) {
+  case nullValue:
+    return true;
+  case intValue:
+    return value_.int_ == other.value_.int_;
+  case uintValue:
+    return value_.uint_ == other.value_.uint_;
+  case realValue:
+    return value_.real_ == other.value_.real_;
+  case booleanValue:
+    return value_.bool_ == other.value_.bool_;
+  case stringValue: {
+    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
+      return (value_.string_ == other.value_.string_);
+    }
+    unsigned this_len;
+    unsigned other_len;
+    char const* this_str;
+    char const* other_str;
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
+                         &other_str);
+    if (this_len != other_len)
+      return false;
+    JSON_ASSERT(this_str && other_str);
+    int comp = memcmp(this_str, other_str, this_len);
+    return comp == 0;
+  }
+  case arrayValue:
+  case objectValue:
+    return value_.map_->size() == other.value_.map_->size() &&
+           (*value_.map_) == (*other.value_.map_);
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+  return false; // unreachable
+}
+
+bool Value::operator!=(const Value& other) const { return !(*this == other); }
+
+const char* Value::asCString() const {
+  JSON_ASSERT_MESSAGE(type() == stringValue,
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == nullptr)
+    return nullptr;
+  unsigned this_len;
+  char const* this_str;
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                       &this_str);
+  return this_str;
+}
+
+#if JSONCPP_USING_SECURE_MEMORY
+unsigned Value::getCStringLength() const {
+  JSON_ASSERT_MESSAGE(type() == stringValue,
+                      "in Json::Value::asCString(): requires stringValue");
+  if (value_.string_ == 0)
+    return 0;
+  unsigned this_len;
+  char const* this_str;
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                       &this_str);
+  return this_len;
+}
+#endif
+
+bool Value::getString(char const** begin, char const** end) const {
+  if (type() != stringValue)
+    return false;
+  if (value_.string_ == nullptr)
+    return false;
+  unsigned length;
+  decodePrefixedString(this->isAllocated(), this->value_.string_, &length,
+                       begin);
+  *end = *begin + length;
+  return true;
+}
+
+String Value::asString() const {
+  switch (type()) {
+  case nullValue:
+    return "";
+  case stringValue: {
+    if (value_.string_ == nullptr)
+      return "";
+    unsigned this_len;
+    char const* this_str;
+    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
+                         &this_str);
+    return String(this_str, this_len);
+  }
+  case booleanValue:
+    return value_.bool_ ? "true" : "false";
+  case intValue:
+    return valueToString(value_.int_);
+  case uintValue:
+    return valueToString(value_.uint_);
+  case realValue:
+    return valueToString(value_.real_);
+  default:
+    JSON_FAIL_MESSAGE("Type is not convertible to string");
+  }
+}
+
+Value::Int Value::asInt() const {
+  switch (type()) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+    return Int(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+    return Int(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+                        "double out of Int range");
+    return Int(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const {
+  switch (type()) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+    return UInt(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+    return UInt(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+                        "double out of UInt range");
+    return UInt(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const {
+  switch (type()) {
+  case intValue:
+    return Int64(value_.int_);
+  case uintValue:
+    JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+    return Int64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+                        "double out of Int64 range");
+    return Int64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const {
+  switch (type()) {
+  case intValue:
+    JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+    return UInt64(value_.int_);
+  case uintValue:
+    return UInt64(value_.uint_);
+  case realValue:
+    JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+                        "double out of UInt64 range");
+    return UInt64(value_.real_);
+  case nullValue:
+    return 0;
+  case booleanValue:
+    return value_.bool_ ? 1 : 0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const {
+#if defined(JSON_NO_INT64)
+  return asInt();
+#else
+  return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const {
+#if defined(JSON_NO_INT64)
+  return asUInt();
+#else
+  return asUInt64();
+#endif
+}
+
+double Value::asDouble() const {
+  switch (type()) {
+  case intValue:
+    return static_cast<double>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<double>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return value_.real_;
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0 : 0.0;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const {
+  switch (type()) {
+  case intValue:
+    return static_cast<float>(value_.int_);
+  case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    return static_cast<float>(value_.uint_);
+#else  // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+    // This can fail (silently?) if the value is bigger than MAX_FLOAT.
+    return static_cast<float>(integerToDouble(value_.uint_));
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+  case realValue:
+    return static_cast<float>(value_.real_);
+  case nullValue:
+    return 0.0;
+  case booleanValue:
+    return value_.bool_ ? 1.0F : 0.0F;
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const {
+  switch (type()) {
+  case booleanValue:
+    return value_.bool_;
+  case nullValue:
+    return false;
+  case intValue:
+    return value_.int_ != 0;
+  case uintValue:
+    return value_.uint_ != 0;
+  case realValue: {
+    // According to JavaScript language zero or NaN is regarded as false
+    const auto value_classification = std::fpclassify(value_.real_);
+    return value_classification != FP_ZERO && value_classification != FP_NAN;
+  }
+  default:
+    break;
+  }
+  JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+  switch (other) {
+  case nullValue:
+    return (isNumeric() && asDouble() == 0.0) ||
+           (type() == booleanValue && !value_.bool_) ||
+           (type() == stringValue && asString().empty()) ||
+           (type() == arrayValue && value_.map_->empty()) ||
+           (type() == objectValue && value_.map_->empty()) ||
+           type() == nullValue;
+  case intValue:
+    return isInt() ||
+           (type() == realValue && InRange(value_.real_, minInt, maxInt)) ||
+           type() == booleanValue || type() == nullValue;
+  case uintValue:
+    return isUInt() ||
+           (type() == realValue && InRange(value_.real_, 0, maxUInt)) ||
+           type() == booleanValue || type() == nullValue;
+  case realValue:
+    return isNumeric() || type() == booleanValue || type() == nullValue;
+  case booleanValue:
+    return isNumeric() || type() == booleanValue || type() == nullValue;
+  case stringValue:
+    return isNumeric() || type() == booleanValue || type() == stringValue ||
+           type() == nullValue;
+  case arrayValue:
+    return type() == arrayValue || type() == nullValue;
+  case objectValue:
+    return type() == objectValue || type() == nullValue;
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return false;
+}
+
+/// Number of values in array or object
+ArrayIndex Value::size() const {
+  switch (type()) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+  case stringValue:
+    return 0;
+  case arrayValue: // size of the array is highest index + 1
+    if (!value_.map_->empty()) {
+      ObjectValues::const_iterator itLast = value_.map_->end();
+      --itLast;
+      return (*itLast).first.index() + 1;
+    }
+    return 0;
+  case objectValue:
+    return ArrayIndex(value_.map_->size());
+  }
+  JSON_ASSERT_UNREACHABLE;
+  return 0; // unreachable;
+}
+
+bool Value::empty() const {
+  if (isNull() || isArray() || isObject())
+    return size() == 0U;
+  return false;
+}
+
+Value::operator bool() const { return !isNull(); }
+
+void Value::clear() {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue ||
+                          type() == objectValue,
+                      "in Json::Value::clear(): requires complex value");
+  start_ = 0;
+  limit_ = 0;
+  switch (type()) {
+  case arrayValue:
+  case objectValue:
+    value_.map_->clear();
+    break;
+  default:
+    break;
+  }
+}
+
+void Value::resize(ArrayIndex newSize) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
+                      "in Json::Value::resize(): requires arrayValue");
+  if (type() == nullValue)
+    *this = Value(arrayValue);
+  ArrayIndex oldSize = size();
+  if (newSize == 0)
+    clear();
+  else if (newSize > oldSize)
+    for (ArrayIndex i = oldSize; i < newSize; ++i)
+      (*this)[i];
+  else {
+    for (ArrayIndex index = newSize; index < oldSize; ++index) {
+      value_.map_->erase(index);
+    }
+    JSON_ASSERT(size() == newSize);
+  }
+}
+
+Value& Value::operator[](ArrayIndex index) {
+  JSON_ASSERT_MESSAGE(
+      type() == nullValue || type() == arrayValue,
+      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+  if (type() == nullValue)
+    *this = Value(arrayValue);
+  CZString key(index);
+  auto it = value_.map_->lower_bound(key);
+  if (it != value_.map_->end() && (*it).first == key)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(key, nullSingleton());
+  it = value_.map_->insert(it, defaultValue);
+  return (*it).second;
+}
+
+Value& Value::operator[](int index) {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index): index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+const Value& Value::operator[](ArrayIndex index) const {
+  JSON_ASSERT_MESSAGE(
+      type() == nullValue || type() == arrayValue,
+      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+  if (type() == nullValue)
+    return nullSingleton();
+  CZString key(index);
+  ObjectValues::const_iterator it = value_.map_->find(key);
+  if (it == value_.map_->end())
+    return nullSingleton();
+  return (*it).second;
+}
+
+const Value& Value::operator[](int index) const {
+  JSON_ASSERT_MESSAGE(
+      index >= 0,
+      "in Json::Value::operator[](int index) const: index cannot be negative");
+  return (*this)[ArrayIndex(index)];
+}
+
+void Value::initBasic(ValueType type, bool allocated) {
+  setType(type);
+  setIsAllocated(allocated);
+  comments_ = Comments{};
+  start_ = 0;
+  limit_ = 0;
+}
+
+void Value::dupPayload(const Value& other) {
+  setType(other.type());
+  setIsAllocated(false);
+  switch (type()) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    value_ = other.value_;
+    break;
+  case stringValue:
+    if (other.value_.string_ && other.isAllocated()) {
+      unsigned len;
+      char const* str;
+      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
+                           &str);
+      value_.string_ = duplicateAndPrefixStringValue(str, len);
+      setIsAllocated(true);
+    } else {
+      value_.string_ = other.value_.string_;
+    }
+    break;
+  case arrayValue:
+  case objectValue:
+    value_.map_ = new ObjectValues(*other.value_.map_);
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+void Value::releasePayload() {
+  switch (type()) {
+  case nullValue:
+  case intValue:
+  case uintValue:
+  case realValue:
+  case booleanValue:
+    break;
+  case stringValue:
+    if (isAllocated())
+      releasePrefixedStringValue(value_.string_);
+    break;
+  case arrayValue:
+  case objectValue:
+    delete value_.map_;
+    break;
+  default:
+    JSON_ASSERT_UNREACHABLE;
+  }
+}
+
+void Value::dupMeta(const Value& other) {
+  comments_ = other.comments_;
+  start_ = other.start_;
+  limit_ = other.limit_;
+}
+
+// Access an object value by name, create a null member if it does not exist.
+// @pre Type of '*this' is object or null.
+// @param key is null-terminated.
+Value& Value::resolveReference(const char* key) {
+  JSON_ASSERT_MESSAGE(
+      type() == nullValue || type() == objectValue,
+      "in Json::Value::resolveReference(): requires objectValue");
+  if (type() == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(key, static_cast<unsigned>(strlen(key)),
+                     CZString::noDuplication); // NOTE!
+  auto it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+// @param key is not null-terminated.
+Value& Value::resolveReference(char const* key, char const* end) {
+  JSON_ASSERT_MESSAGE(
+      type() == nullValue || type() == objectValue,
+      "in Json::Value::resolveReference(key, end): requires objectValue");
+  if (type() == nullValue)
+    *this = Value(objectValue);
+  CZString actualKey(key, static_cast<unsigned>(end - key),
+                     CZString::duplicateOnCopy);
+  auto it = value_.map_->lower_bound(actualKey);
+  if (it != value_.map_->end() && (*it).first == actualKey)
+    return (*it).second;
+
+  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
+  it = value_.map_->insert(it, defaultValue);
+  Value& value = (*it).second;
+  return value;
+}
+
+Value Value::get(ArrayIndex index, const Value& defaultValue) const {
+  const Value* value = &((*this)[index]);
+  return value == &nullSingleton() ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+Value const* Value::find(char const* begin, char const* end) const {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
+                      "in Json::Value::find(begin, end): requires "
+                      "objectValue or nullValue");
+  if (type() == nullValue)
+    return nullptr;
+  CZString actualKey(begin, static_cast<unsigned>(end - begin),
+                     CZString::noDuplication);
+  ObjectValues::const_iterator it = value_.map_->find(actualKey);
+  if (it == value_.map_->end())
+    return nullptr;
+  return &(*it).second;
+}
+Value* Value::demand(char const* begin, char const* end) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
+                      "in Json::Value::demand(begin, end): requires "
+                      "objectValue or nullValue");
+  return &resolveReference(begin, end);
+}
+const Value& Value::operator[](const char* key) const {
+  Value const* found = find(key, key + strlen(key));
+  if (!found)
+    return nullSingleton();
+  return *found;
+}
+Value const& Value::operator[](const String& key) const {
+  Value const* found = find(key.data(), key.data() + key.length());
+  if (!found)
+    return nullSingleton();
+  return *found;
+}
+
+Value& Value::operator[](const char* key) {
+  return resolveReference(key, key + strlen(key));
+}
+
+Value& Value::operator[](const String& key) {
+  return resolveReference(key.data(), key.data() + key.length());
+}
+
+Value& Value::operator[](const StaticString& key) {
+  return resolveReference(key.c_str());
+}
+
+Value& Value::append(const Value& value) { return append(Value(value)); }
+
+Value& Value::append(Value&& value) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
+                      "in Json::Value::append: requires arrayValue");
+  if (type() == nullValue) {
+    *this = Value(arrayValue);
+  }
+  return this->value_.map_->emplace(size(), std::move(value)).first->second;
+}
+
+bool Value::insert(ArrayIndex index, const Value& newValue) {
+  return insert(index, Value(newValue));
+}
+
+bool Value::insert(ArrayIndex index, Value&& newValue) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == arrayValue,
+                      "in Json::Value::insert: requires arrayValue");
+  ArrayIndex length = size();
+  if (index > length) {
+    return false;
+  }
+  for (ArrayIndex i = length; i > index; i--) {
+    (*this)[i] = std::move((*this)[i - 1]);
+  }
+  (*this)[index] = std::move(newValue);
+  return true;
+}
+
+Value Value::get(char const* begin, char const* end,
+                 Value const& defaultValue) const {
+  Value const* found = find(begin, end);
+  return !found ? defaultValue : *found;
+}
+Value Value::get(char const* key, Value const& defaultValue) const {
+  return get(key, key + strlen(key), defaultValue);
+}
+Value Value::get(String const& key, Value const& defaultValue) const {
+  return get(key.data(), key.data() + key.length(), defaultValue);
+}
+
+bool Value::removeMember(const char* begin, const char* end, Value* removed) {
+  if (type() != objectValue) {
+    return false;
+  }
+  CZString actualKey(begin, static_cast<unsigned>(end - begin),
+                     CZString::noDuplication);
+  auto it = value_.map_->find(actualKey);
+  if (it == value_.map_->end())
+    return false;
+  if (removed)
+    *removed = std::move(it->second);
+  value_.map_->erase(it);
+  return true;
+}
+bool Value::removeMember(const char* key, Value* removed) {
+  return removeMember(key, key + strlen(key), removed);
+}
+bool Value::removeMember(String const& key, Value* removed) {
+  return removeMember(key.data(), key.data() + key.length(), removed);
+}
+void Value::removeMember(const char* key) {
+  JSON_ASSERT_MESSAGE(type() == nullValue || type() == objectValue,
+                      "in Json::Value::removeMember(): requires objectValue");
+  if (type() == nullValue)
+    return;
+
+  CZString actualKey(key, unsigned(strlen(key)), CZString::noDuplication);
+  value_.map_->erase(actualKey);
+}
+void Value::removeMember(const String& key) { removeMember(key.c_str()); }
+
+bool Value::removeIndex(ArrayIndex index, Value* removed) {
+  if (type() != arrayValue) {
+    return false;
+  }
+  CZString key(index);
+  auto it = value_.map_->find(key);
+  if (it == value_.map_->end()) {
+    return false;
+  }
+  if (removed)
+    *removed = it->second;
+  ArrayIndex oldSize = size();
+  // shift left all items left, into the place of the "removed"
+  for (ArrayIndex i = index; i < (oldSize - 1); ++i) {
+    CZString keey(i);
+    (*value_.map_)[keey] = (*this)[i + 1];
+  }
+  // erase the last one ("leftover")
+  CZString keyLast(oldSize - 1);
+  auto itLast = value_.map_->find(keyLast);
+  value_.map_->erase(itLast);
+  return true;
+}
+
+bool Value::isMember(char const* begin, char const* end) const {
+  Value const* value = find(begin, end);
+  return nullptr != value;
+}
+bool Value::isMember(char const* key) const {
+  return isMember(key, key + strlen(key));
+}
+bool Value::isMember(String const& key) const {
+  return isMember(key.data(), key.data() + key.length());
+}
+
+Value::Members Value::getMemberNames() const {
+  JSON_ASSERT_MESSAGE(
+      type() == nullValue || type() == objectValue,
+      "in Json::Value::getMemberNames(), value must be objectValue");
+  if (type() == nullValue)
+    return Value::Members();
+  Members members;
+  members.reserve(value_.map_->size());
+  ObjectValues::const_iterator it = value_.map_->begin();
+  ObjectValues::const_iterator itEnd = value_.map_->end();
+  for (; it != itEnd; ++it) {
+    members.push_back(String((*it).first.data(), (*it).first.length()));
+  }
+  return members;
+}
+
+static bool IsIntegral(double d) {
+  double integral_part;
+  return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type() == nullValue; }
+
+bool Value::isBool() const { return type() == booleanValue; }
+
+bool Value::isInt() const {
+  switch (type()) {
+  case intValue:
+#if defined(JSON_HAS_INT64)
+    return value_.int_ >= minInt && value_.int_ <= maxInt;
+#else
+    return true;
+#endif
+  case uintValue:
+    return value_.uint_ <= UInt(maxInt);
+  case realValue:
+    return value_.real_ >= minInt && value_.real_ <= maxInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isUInt() const {
+  switch (type()) {
+  case intValue:
+#if defined(JSON_HAS_INT64)
+    return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+#else
+    return value_.int_ >= 0;
+#endif
+  case uintValue:
+#if defined(JSON_HAS_INT64)
+    return value_.uint_ <= maxUInt;
+#else
+    return true;
+#endif
+  case realValue:
+    return value_.real_ >= 0 && value_.real_ <= maxUInt &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type()) {
+  case intValue:
+    return true;
+  case uintValue:
+    return value_.uint_ <= UInt64(maxInt64);
+  case realValue:
+    // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+    // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= double(minInt64) &&
+           value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isUInt64() const {
+#if defined(JSON_HAS_INT64)
+  switch (type()) {
+  case intValue:
+    return value_.int_ >= 0;
+  case uintValue:
+    return true;
+  case realValue:
+    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
+           IsIntegral(value_.real_);
+  default:
+    break;
+  }
+#endif // JSON_HAS_INT64
+  return false;
+}
+
+bool Value::isIntegral() const {
+  switch (type()) {
+  case intValue:
+  case uintValue:
+    return true;
+  case realValue:
+#if defined(JSON_HAS_INT64)
+    // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+    // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+    // require the value to be strictly less than the limit.
+    return value_.real_ >= double(minInt64) &&
+           value_.real_ < maxUInt64AsDouble && IsIntegral(value_.real_);
+#else
+    return value_.real_ >= minInt && value_.real_ <= maxUInt &&
+           IsIntegral(value_.real_);
+#endif // JSON_HAS_INT64
+  default:
+    break;
+  }
+  return false;
+}
+
+bool Value::isDouble() const {
+  return type() == intValue || type() == uintValue || type() == realValue;
+}
+
+bool Value::isNumeric() const { return isDouble(); }
+
+bool Value::isString() const { return type() == stringValue; }
+
+bool Value::isArray() const { return type() == arrayValue; }
+
+bool Value::isObject() const { return type() == objectValue; }
+
+Value::Comments::Comments(const Comments& that)
+    : ptr_{cloneUnique(that.ptr_)} {}
+
+Value::Comments::Comments(Comments&& that) noexcept
+    : ptr_{std::move(that.ptr_)} {}
+
+Value::Comments& Value::Comments::operator=(const Comments& that) {
+  ptr_ = cloneUnique(that.ptr_);
+  return *this;
+}
+
+Value::Comments& Value::Comments::operator=(Comments&& that) noexcept {
+  ptr_ = std::move(that.ptr_);
+  return *this;
+}
+
+bool Value::Comments::has(CommentPlacement slot) const {
+  return ptr_ && !(*ptr_)[slot].empty();
+}
+
+String Value::Comments::get(CommentPlacement slot) const {
+  if (!ptr_)
+    return {};
+  return (*ptr_)[slot];
+}
+
+void Value::Comments::set(CommentPlacement slot, String comment) {
+  if (slot >= CommentPlacement::numberOfCommentPlacement)
+    return;
+  if (!ptr_)
+    ptr_ = std::unique_ptr<Array>(new Array());
+  (*ptr_)[slot] = std::move(comment);
+}
+
+void Value::setComment(String comment, CommentPlacement placement) {
+  if (!comment.empty() && (comment.back() == '\n')) {
+    // Always discard trailing newline, to aid indentation.
+    comment.pop_back();
+  }
+  JSON_ASSERT(!comment.empty());
+  JSON_ASSERT_MESSAGE(
+      comment[0] == '\0' || comment[0] == '/',
+      "in Json::Value::setComment(): Comments must start with /");
+  comments_.set(placement, std::move(comment));
+}
+
+bool Value::hasComment(CommentPlacement placement) const {
+  return comments_.has(placement);
+}
+
+String Value::getComment(CommentPlacement placement) const {
+  return comments_.get(placement);
+}
+
+void Value::setOffsetStart(ptrdiff_t start) { start_ = start; }
+
+void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; }
+
+ptrdiff_t Value::getOffsetStart() const { return start_; }
+
+ptrdiff_t Value::getOffsetLimit() const { return limit_; }
+
+String Value::toStyledString() const {
+  StreamWriterBuilder builder;
+
+  String out = this->hasComment(commentBefore) ? "\n" : "";
+  out += Json::writeString(builder, *this);
+  out += '\n';
+
+  return out;
+}
+
+Value::const_iterator Value::begin() const {
+  switch (type()) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return {};
+}
+
+Value::const_iterator Value::end() const {
+  switch (type()) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return const_iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return {};
+}
+
+Value::iterator Value::begin() {
+  switch (type()) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->begin());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+Value::iterator Value::end() {
+  switch (type()) {
+  case arrayValue:
+  case objectValue:
+    if (value_.map_)
+      return iterator(value_.map_->end());
+    break;
+  default:
+    break;
+  }
+  return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() = default;
+
+PathArgument::PathArgument(ArrayIndex index)
+    : index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char* key) : key_(key), kind_(kindKey) {}
+
+PathArgument::PathArgument(String key) : key_(std::move(key)), kind_(kindKey) {}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const String& path, const PathArgument& a1, const PathArgument& a2,
+           const PathArgument& a3, const PathArgument& a4,
+           const PathArgument& a5) {
+  InArgs in;
+  in.reserve(5);
+  in.push_back(&a1);
+  in.push_back(&a2);
+  in.push_back(&a3);
+  in.push_back(&a4);
+  in.push_back(&a5);
+  makePath(path, in);
+}
+
+void Path::makePath(const String& path, const InArgs& in) {
+  const char* current = path.c_str();
+  const char* end = current + path.length();
+  auto itInArg = in.begin();
+  while (current != end) {
+    if (*current == '[') {
+      ++current;
+      if (*current == '%')
+        addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+      else {
+        ArrayIndex index = 0;
+        for (; current != end && *current >= '0' && *current <= '9'; ++current)
+          index = index * 10 + ArrayIndex(*current - '0');
+        args_.push_back(index);
+      }
+      if (current == end || *++current != ']')
+        invalidPath(path, int(current - path.c_str()));
+    } else if (*current == '%') {
+      addPathInArg(path, in, itInArg, PathArgument::kindKey);
+      ++current;
+    } else if (*current == '.' || *current == ']') {
+      ++current;
+    } else {
+      const char* beginName = current;
+      while (current != end && !strchr("[.", *current))
+        ++current;
+      args_.push_back(String(beginName, current));
+    }
+  }
+}
+
+void Path::addPathInArg(const String& /*path*/, const InArgs& in,
+                        InArgs::const_iterator& itInArg,
+                        PathArgument::Kind kind) {
+  if (itInArg == in.end()) {
+    // Error: missing argument %d
+  } else if ((*itInArg)->kind_ != kind) {
+    // Error: bad argument type
+  } else {
+    args_.push_back(**itInArg++);
+  }
+}
+
+void Path::invalidPath(const String& /*path*/, int /*location*/) {
+  // Error: invalid path.
+}
+
+const Value& Path::resolve(const Value& root) const {
+  const Value* node = &root;
+  for (const auto& arg : args_) {
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_)) {
+        // Error: unable to resolve path (array value expected at position... )
+        return Value::nullSingleton();
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: unable to resolve path (object value expected at position...)
+        return Value::nullSingleton();
+      }
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullSingleton()) {
+        // Error: unable to resolve path (object has no member named '' at
+        // position...)
+        return Value::nullSingleton();
+      }
+    }
+  }
+  return *node;
+}
+
+Value Path::resolve(const Value& root, const Value& defaultValue) const {
+  const Value* node = &root;
+  for (const auto& arg : args_) {
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray() || !node->isValidIndex(arg.index_))
+        return defaultValue;
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject())
+        return defaultValue;
+      node = &((*node)[arg.key_]);
+      if (node == &Value::nullSingleton())
+        return defaultValue;
+    }
+  }
+  return *node;
+}
+
+Value& Path::make(Value& root) const {
+  Value* node = &root;
+  for (const auto& arg : args_) {
+    if (arg.kind_ == PathArgument::kindIndex) {
+      if (!node->isArray()) {
+        // Error: node is not an array at position ...
+      }
+      node = &((*node)[arg.index_]);
+    } else if (arg.kind_ == PathArgument::kindKey) {
+      if (!node->isObject()) {
+        // Error: node is not an object at position...
+      }
+      node = &((*node)[arg.key_]);
+    }
+  }
+  return *node;
+}
+
+} // namespace Json

+ 156 - 0
thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_valueiterator.inl

@@ -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

+ 1259 - 0
thirdparty/openxr/src/external/jsoncpp/src/lib_json/json_writer.cpp

@@ -0,0 +1,1259 @@
+// Copyright 2011 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
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "json_tool.h"
+#include <json/writer.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstring>
+#include <iomanip>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <utility>
+
+#if __cplusplus >= 201103L
+#include <cmath>
+#include <cstdio>
+
+#if !defined(isnan)
+#define isnan std::isnan
+#endif
+
+#if !defined(isfinite)
+#define isfinite std::isfinite
+#endif
+
+#else
+#include <cmath>
+#include <cstdio>
+
+#if defined(_MSC_VER)
+#if !defined(isnan)
+#include <float.h>
+#define isnan _isnan
+#endif
+
+#if !defined(isfinite)
+#include <float.h>
+#define isfinite _finite
+#endif
+
+#if !defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
+#endif //_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
+
+#endif //_MSC_VER
+
+#if defined(__sun) && defined(__SVR4) // Solaris
+#if !defined(isfinite)
+#include <ieeefp.h>
+#define isfinite finite
+#endif
+#endif
+
+#if defined(__hpux)
+#if !defined(isfinite)
+#if defined(__ia64) && !defined(finite)
+#define isfinite(x)                                                            \
+  ((sizeof(x) == sizeof(float) ? _Isfinitef(x) : _IsFinite(x)))
+#endif
+#endif
+#endif
+
+#if !defined(isnan)
+// IEEE standard states that NaN values will not compare to themselves
+#define isnan(x) ((x) != (x))
+#endif
+
+#if !defined(__APPLE__)
+#if !defined(isfinite)
+#define isfinite finite
+#endif
+#endif
+#endif
+
+#if defined(_MSC_VER)
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520)
+using StreamWriterPtr = std::unique_ptr<StreamWriter>;
+#else
+using StreamWriterPtr = std::auto_ptr<StreamWriter>;
+#endif
+
+String valueToString(LargestInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  if (value == Value::minLargestInt) {
+    uintToString(LargestUInt(Value::maxLargestInt) + 1, current);
+    *--current = '-';
+  } else if (value < 0) {
+    uintToString(LargestUInt(-value), current);
+    *--current = '-';
+  } else {
+    uintToString(LargestUInt(value), current);
+  }
+  assert(current >= buffer);
+  return current;
+}
+
+String valueToString(LargestUInt value) {
+  UIntToStringBuffer buffer;
+  char* current = buffer + sizeof(buffer);
+  uintToString(value, current);
+  assert(current >= buffer);
+  return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+String valueToString(Int value) { return valueToString(LargestInt(value)); }
+
+String valueToString(UInt value) { return valueToString(LargestUInt(value)); }
+
+#endif // # if defined(JSON_HAS_INT64)
+
+namespace {
+String valueToString(double value, bool useSpecialFloats,
+                     unsigned int precision, PrecisionType precisionType) {
+  // Print into the buffer. We need not request the alternative representation
+  // that always has a decimal point because JSON doesn't distinguish the
+  // concepts of reals and integers.
+  if (!isfinite(value)) {
+    static const char* const reps[2][3] = {{"NaN", "-Infinity", "Infinity"},
+                                           {"null", "-1e+9999", "1e+9999"}};
+    return reps[useSpecialFloats ? 0 : 1]
+               [isnan(value) ? 0 : (value < 0) ? 1 : 2];
+  }
+
+  String buffer(size_t(36), '\0');
+  while (true) {
+    int len = jsoncpp_snprintf(
+        &*buffer.begin(), buffer.size(),
+        (precisionType == PrecisionType::significantDigits) ? "%.*g" : "%.*f",
+        precision, value);
+    assert(len >= 0);
+    auto wouldPrint = static_cast<size_t>(len);
+    if (wouldPrint >= buffer.size()) {
+      buffer.resize(wouldPrint + 1);
+      continue;
+    }
+    buffer.resize(wouldPrint);
+    break;
+  }
+
+  buffer.erase(fixNumericLocale(buffer.begin(), buffer.end()), buffer.end());
+
+  // try to ensure we preserve the fact that this was given to us as a double on
+  // input
+  if (buffer.find('.') == buffer.npos && buffer.find('e') == buffer.npos) {
+    buffer += ".0";
+  }
+
+  // strip the zero padding from the right
+  if (precisionType == PrecisionType::decimalPlaces) {
+    buffer.erase(fixZerosInTheEnd(buffer.begin(), buffer.end(), precision),
+                 buffer.end());
+  }
+
+  return buffer;
+}
+} // namespace
+
+String valueToString(double value, unsigned int precision,
+                     PrecisionType precisionType) {
+  return valueToString(value, false, precision, precisionType);
+}
+
+String valueToString(bool value) { return value ? "true" : "false"; }
+
+static bool doesAnyCharRequireEscaping(char const* s, size_t n) {
+  assert(s || !n);
+
+  return std::any_of(s, s + n, [](unsigned char c) {
+    return c == '\\' || c == '"' || c < 0x20 || c > 0x7F;
+  });
+}
+
+static unsigned int utf8ToCodepoint(const char*& s, const char* e) {
+  const unsigned int REPLACEMENT_CHARACTER = 0xFFFD;
+
+  unsigned int firstByte = static_cast<unsigned char>(*s);
+
+  if (firstByte < 0x80)
+    return firstByte;
+
+  if (firstByte < 0xE0) {
+    if (e - s < 2)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated =
+        ((firstByte & 0x1F) << 6) | (static_cast<unsigned int>(s[1]) & 0x3F);
+    s += 1;
+    // oversized encoded characters are invalid
+    return calculated < 0x80 ? REPLACEMENT_CHARACTER : calculated;
+  }
+
+  if (firstByte < 0xF0) {
+    if (e - s < 3)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated = ((firstByte & 0x0F) << 12) |
+                              ((static_cast<unsigned int>(s[1]) & 0x3F) << 6) |
+                              (static_cast<unsigned int>(s[2]) & 0x3F);
+    s += 2;
+    // surrogates aren't valid codepoints itself
+    // shouldn't be UTF-8 encoded
+    if (calculated >= 0xD800 && calculated <= 0xDFFF)
+      return REPLACEMENT_CHARACTER;
+    // oversized encoded characters are invalid
+    return calculated < 0x800 ? REPLACEMENT_CHARACTER : calculated;
+  }
+
+  if (firstByte < 0xF8) {
+    if (e - s < 4)
+      return REPLACEMENT_CHARACTER;
+
+    unsigned int calculated = ((firstByte & 0x07) << 18) |
+                              ((static_cast<unsigned int>(s[1]) & 0x3F) << 12) |
+                              ((static_cast<unsigned int>(s[2]) & 0x3F) << 6) |
+                              (static_cast<unsigned int>(s[3]) & 0x3F);
+    s += 3;
+    // oversized encoded characters are invalid
+    return calculated < 0x10000 ? REPLACEMENT_CHARACTER : calculated;
+  }
+
+  return REPLACEMENT_CHARACTER;
+}
+
+static const char hex2[] = "000102030405060708090a0b0c0d0e0f"
+                           "101112131415161718191a1b1c1d1e1f"
+                           "202122232425262728292a2b2c2d2e2f"
+                           "303132333435363738393a3b3c3d3e3f"
+                           "404142434445464748494a4b4c4d4e4f"
+                           "505152535455565758595a5b5c5d5e5f"
+                           "606162636465666768696a6b6c6d6e6f"
+                           "707172737475767778797a7b7c7d7e7f"
+                           "808182838485868788898a8b8c8d8e8f"
+                           "909192939495969798999a9b9c9d9e9f"
+                           "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
+                           "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+                           "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
+                           "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+                           "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
+                           "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+
+static String toHex16Bit(unsigned int x) {
+  const unsigned int hi = (x >> 8) & 0xff;
+  const unsigned int lo = x & 0xff;
+  String result(4, ' ');
+  result[0] = hex2[2 * hi];
+  result[1] = hex2[2 * hi + 1];
+  result[2] = hex2[2 * lo];
+  result[3] = hex2[2 * lo + 1];
+  return result;
+}
+
+static void appendRaw(String& result, unsigned ch) {
+  result += static_cast<char>(ch);
+}
+
+static void appendHex(String& result, unsigned ch) {
+  result.append("\\u").append(toHex16Bit(ch));
+}
+
+static String valueToQuotedStringN(const char* value, size_t length,
+                                   bool emitUTF8 = false) {
+  if (value == nullptr)
+    return "";
+
+  if (!doesAnyCharRequireEscaping(value, length))
+    return String("\"") + value + "\"";
+  // We have to walk value and escape any special characters.
+  // Appending to String is not efficient, but this should be rare.
+  // (Note: forward slashes are *not* rare, but I am not escaping them.)
+  String::size_type maxsize = length * 2 + 3; // allescaped+quotes+NULL
+  String result;
+  result.reserve(maxsize); // to avoid lots of mallocs
+  result += "\"";
+  char const* end = value + length;
+  for (const char* c = value; c != end; ++c) {
+    switch (*c) {
+    case '\"':
+      result += "\\\"";
+      break;
+    case '\\':
+      result += "\\\\";
+      break;
+    case '\b':
+      result += "\\b";
+      break;
+    case '\f':
+      result += "\\f";
+      break;
+    case '\n':
+      result += "\\n";
+      break;
+    case '\r':
+      result += "\\r";
+      break;
+    case '\t':
+      result += "\\t";
+      break;
+    // case '/':
+    // Even though \/ is considered a legal escape in JSON, a bare
+    // slash is also legal, so I see no reason to escape it.
+    // (I hope I am not misunderstanding something.)
+    // blep notes: actually escaping \/ may be useful in javascript to avoid </
+    // sequence.
+    // Should add a flag to allow this compatibility mode and prevent this
+    // sequence from occurring.
+    default: {
+      if (emitUTF8) {
+        unsigned codepoint = static_cast<unsigned char>(*c);
+        if (codepoint < 0x20) {
+          appendHex(result, codepoint);
+        } else {
+          appendRaw(result, codepoint);
+        }
+      } else {
+        unsigned codepoint = utf8ToCodepoint(c, end); // modifies `c`
+        if (codepoint < 0x20) {
+          appendHex(result, codepoint);
+        } else if (codepoint < 0x80) {
+          appendRaw(result, codepoint);
+        } else if (codepoint < 0x10000) {
+          // Basic Multilingual Plane
+          appendHex(result, codepoint);
+        } else {
+          // Extended Unicode. Encode 20 bits as a surrogate pair.
+          codepoint -= 0x10000;
+          appendHex(result, 0xd800 + ((codepoint >> 10) & 0x3ff));
+          appendHex(result, 0xdc00 + (codepoint & 0x3ff));
+        }
+      }
+    } break;
+    }
+  }
+  result += "\"";
+  return result;
+}
+
+String valueToQuotedString(const char* value) {
+  return valueToQuotedStringN(value, strlen(value));
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() = default;
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+
+    = default;
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatibilityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+String FastWriter::write(const Value& root) {
+  document_.clear();
+  writeValue(root);
+  if (!omitEndingLineFeed_)
+    document_ += '\n';
+  return document_;
+}
+
+void FastWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    if (!dropNullPlaceholders_)
+      document_ += "null";
+    break;
+  case intValue:
+    document_ += valueToString(value.asLargestInt());
+    break;
+  case uintValue:
+    document_ += valueToString(value.asLargestUInt());
+    break;
+  case realValue:
+    document_ += valueToString(value.asDouble());
+    break;
+  case stringValue: {
+    // Is NULL possible for value.string_? No.
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok)
+      document_ += valueToQuotedStringN(str, static_cast<size_t>(end - str));
+    break;
+  }
+  case booleanValue:
+    document_ += valueToString(value.asBool());
+    break;
+  case arrayValue: {
+    document_ += '[';
+    ArrayIndex size = value.size();
+    for (ArrayIndex index = 0; index < size; ++index) {
+      if (index > 0)
+        document_ += ',';
+      writeValue(value[index]);
+    }
+    document_ += ']';
+  } break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    document_ += '{';
+    for (auto it = members.begin(); it != members.end(); ++it) {
+      const String& name = *it;
+      if (it != members.begin())
+        document_ += ',';
+      document_ += valueToQuotedStringN(name.data(), name.length());
+      document_ += yamlCompatibilityEnabled_ ? ": " : ":";
+      writeValue(value[name]);
+    }
+    document_ += '}';
+  } break;
+  }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter() = default;
+
+String StyledWriter::write(const Value& root) {
+  document_.clear();
+  addChildValues_ = false;
+  indentString_.clear();
+  writeCommentBeforeValue(root);
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  document_ += '\n';
+  return document_;
+}
+
+void StyledWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue: {
+    // Is NULL possible for value.string_? No.
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok)
+      pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
+    else
+      pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      auto it = members.begin();
+      for (;;) {
+        const String& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        document_ += " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledWriter::writeArrayValue(const Value& value) {
+  size_t size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultilineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      ArrayIndex index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          writeIndent();
+          writeValue(childValue);
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        document_ += ',';
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      document_ += "[ ";
+      for (size_t index = 0; index < size; ++index) {
+        if (index > 0)
+          document_ += ", ";
+        document_ += childValues_[index];
+      }
+      document_ += " ]";
+    }
+  }
+}
+
+bool StyledWriter::isMultilineArray(const Value& value) {
+  ArrayIndex const size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                   !childValue.empty());
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (ArrayIndex index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledWriter::pushValue(const String& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    document_ += value;
+}
+
+void StyledWriter::writeIndent() {
+  if (!document_.empty()) {
+    char last = document_[document_.length() - 1];
+    if (last == ' ') // already indented
+      return;
+    if (last != '\n') // Comments may add new-line
+      document_ += '\n';
+  }
+  document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const String& value) {
+  writeIndent();
+  document_ += value;
+}
+
+void StyledWriter::indent() { indentString_ += String(indentSize_, ' '); }
+
+void StyledWriter::unindent() {
+  assert(indentString_.size() >= indentSize_);
+  indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  document_ += '\n';
+  writeIndent();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    document_ += *iter;
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
+      writeIndent();
+    ++iter;
+  }
+
+  // Comments are stripped of trailing newlines, so add one here
+  document_ += '\n';
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    document_ += " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    document_ += '\n';
+    document_ += root.getComment(commentAfter);
+    document_ += '\n';
+  }
+}
+
+bool StyledWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(String indentation)
+    : document_(nullptr), indentation_(std::move(indentation)),
+      addChildValues_(), indented_(false) {}
+
+void StyledStreamWriter::write(OStream& out, const Value& root) {
+  document_ = &out;
+  addChildValues_ = false;
+  indentString_.clear();
+  indented_ = true;
+  writeCommentBeforeValue(root);
+  if (!indented_)
+    writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *document_ << "\n";
+  document_ = nullptr; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue("null");
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble()));
+    break;
+  case stringValue: {
+    // Is NULL possible for value.string_? No.
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok)
+      pushValue(valueToQuotedStringN(str, static_cast<size_t>(end - str)));
+    else
+      pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      auto it = members.begin();
+      for (;;) {
+        const String& name = *it;
+        const Value& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(valueToQuotedString(name.c_str()));
+        *document_ << " : ";
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isArrayMultiLine = isMultilineArray(value);
+    if (isArrayMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        const Value& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_)
+            writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *document_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *document_ << "[ ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *document_ << ", ";
+        *document_ << childValues_[index];
+      }
+      *document_ << " ]";
+    }
+  }
+}
+
+bool StyledStreamWriter::isMultilineArray(const Value& value) {
+  ArrayIndex const size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
+    const Value& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                   !childValue.empty());
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (ArrayIndex index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const String& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+  *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const String& value) {
+  if (!indented_)
+    writeIndent();
+  *document_ << value;
+  indented_ = false;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_)
+    writeIndent();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *document_ << *iter;
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would include newline
+      *document_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+  if (root.hasComment(commentAfterOnSameLine))
+    *document_ << ' ' << root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *document_ << root.getComment(commentAfter);
+  }
+  indented_ = false;
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+//////////////////////////
+// BuiltStyledStreamWriter
+
+/// Scoped enums are not available until C++11.
+struct CommentStyle {
+  /// Decide whether to write comments.
+  enum Enum {
+    None, ///< Drop all comments.
+    Most, ///< Recover odd behavior of previous versions (not implemented yet).
+    All   ///< Keep all comments.
+  };
+};
+
+struct BuiltStyledStreamWriter : public StreamWriter {
+  BuiltStyledStreamWriter(String indentation, CommentStyle::Enum cs,
+                          String colonSymbol, String nullSymbol,
+                          String endingLineFeedSymbol, bool useSpecialFloats,
+                          bool emitUTF8, unsigned int precision,
+                          PrecisionType precisionType);
+  int write(Value const& root, OStream* sout) override;
+
+private:
+  void writeValue(Value const& value);
+  void writeArrayValue(Value const& value);
+  bool isMultilineArray(Value const& value);
+  void pushValue(String const& value);
+  void writeIndent();
+  void writeWithIndent(String const& value);
+  void indent();
+  void unindent();
+  void writeCommentBeforeValue(Value const& root);
+  void writeCommentAfterValueOnSameLine(Value const& root);
+  static bool hasCommentForValue(const Value& value);
+
+  using ChildValues = std::vector<String>;
+
+  ChildValues childValues_;
+  String indentString_;
+  unsigned int rightMargin_;
+  String indentation_;
+  CommentStyle::Enum cs_;
+  String colonSymbol_;
+  String nullSymbol_;
+  String endingLineFeedSymbol_;
+  bool addChildValues_ : 1;
+  bool indented_ : 1;
+  bool useSpecialFloats_ : 1;
+  bool emitUTF8_ : 1;
+  unsigned int precision_;
+  PrecisionType precisionType_;
+};
+BuiltStyledStreamWriter::BuiltStyledStreamWriter(
+    String indentation, CommentStyle::Enum cs, String colonSymbol,
+    String nullSymbol, String endingLineFeedSymbol, bool useSpecialFloats,
+    bool emitUTF8, unsigned int precision, PrecisionType precisionType)
+    : rightMargin_(74), indentation_(std::move(indentation)), cs_(cs),
+      colonSymbol_(std::move(colonSymbol)), nullSymbol_(std::move(nullSymbol)),
+      endingLineFeedSymbol_(std::move(endingLineFeedSymbol)),
+      addChildValues_(false), indented_(false),
+      useSpecialFloats_(useSpecialFloats), emitUTF8_(emitUTF8),
+      precision_(precision), precisionType_(precisionType) {}
+int BuiltStyledStreamWriter::write(Value const& root, OStream* sout) {
+  sout_ = sout;
+  addChildValues_ = false;
+  indented_ = true;
+  indentString_.clear();
+  writeCommentBeforeValue(root);
+  if (!indented_)
+    writeIndent();
+  indented_ = true;
+  writeValue(root);
+  writeCommentAfterValueOnSameLine(root);
+  *sout_ << endingLineFeedSymbol_;
+  sout_ = nullptr;
+  return 0;
+}
+void BuiltStyledStreamWriter::writeValue(Value const& value) {
+  switch (value.type()) {
+  case nullValue:
+    pushValue(nullSymbol_);
+    break;
+  case intValue:
+    pushValue(valueToString(value.asLargestInt()));
+    break;
+  case uintValue:
+    pushValue(valueToString(value.asLargestUInt()));
+    break;
+  case realValue:
+    pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_,
+                            precisionType_));
+    break;
+  case stringValue: {
+    // Is NULL is possible for value.string_? No.
+    char const* str;
+    char const* end;
+    bool ok = value.getString(&str, &end);
+    if (ok)
+      pushValue(
+          valueToQuotedStringN(str, static_cast<size_t>(end - str), emitUTF8_));
+    else
+      pushValue("");
+    break;
+  }
+  case booleanValue:
+    pushValue(valueToString(value.asBool()));
+    break;
+  case arrayValue:
+    writeArrayValue(value);
+    break;
+  case objectValue: {
+    Value::Members members(value.getMemberNames());
+    if (members.empty())
+      pushValue("{}");
+    else {
+      writeWithIndent("{");
+      indent();
+      auto it = members.begin();
+      for (;;) {
+        String const& name = *it;
+        Value const& childValue = value[name];
+        writeCommentBeforeValue(childValue);
+        writeWithIndent(
+            valueToQuotedStringN(name.data(), name.length(), emitUTF8_));
+        *sout_ << colonSymbol_;
+        writeValue(childValue);
+        if (++it == members.end()) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("}");
+    }
+  } break;
+  }
+}
+
+void BuiltStyledStreamWriter::writeArrayValue(Value const& value) {
+  unsigned size = value.size();
+  if (size == 0)
+    pushValue("[]");
+  else {
+    bool isMultiLine = (cs_ == CommentStyle::All) || isMultilineArray(value);
+    if (isMultiLine) {
+      writeWithIndent("[");
+      indent();
+      bool hasChildValue = !childValues_.empty();
+      unsigned index = 0;
+      for (;;) {
+        Value const& childValue = value[index];
+        writeCommentBeforeValue(childValue);
+        if (hasChildValue)
+          writeWithIndent(childValues_[index]);
+        else {
+          if (!indented_)
+            writeIndent();
+          indented_ = true;
+          writeValue(childValue);
+          indented_ = false;
+        }
+        if (++index == size) {
+          writeCommentAfterValueOnSameLine(childValue);
+          break;
+        }
+        *sout_ << ",";
+        writeCommentAfterValueOnSameLine(childValue);
+      }
+      unindent();
+      writeWithIndent("]");
+    } else // output on a single line
+    {
+      assert(childValues_.size() == size);
+      *sout_ << "[";
+      if (!indentation_.empty())
+        *sout_ << " ";
+      for (unsigned index = 0; index < size; ++index) {
+        if (index > 0)
+          *sout_ << ((!indentation_.empty()) ? ", " : ",");
+        *sout_ << childValues_[index];
+      }
+      if (!indentation_.empty())
+        *sout_ << " ";
+      *sout_ << "]";
+    }
+  }
+}
+
+bool BuiltStyledStreamWriter::isMultilineArray(Value const& value) {
+  ArrayIndex const size = value.size();
+  bool isMultiLine = size * 3 >= rightMargin_;
+  childValues_.clear();
+  for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) {
+    Value const& childValue = value[index];
+    isMultiLine = ((childValue.isArray() || childValue.isObject()) &&
+                   !childValue.empty());
+  }
+  if (!isMultiLine) // check if line length > max line length
+  {
+    childValues_.reserve(size);
+    addChildValues_ = true;
+    ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+    for (ArrayIndex index = 0; index < size; ++index) {
+      if (hasCommentForValue(value[index])) {
+        isMultiLine = true;
+      }
+      writeValue(value[index]);
+      lineLength += static_cast<ArrayIndex>(childValues_[index].length());
+    }
+    addChildValues_ = false;
+    isMultiLine = isMultiLine || lineLength >= rightMargin_;
+  }
+  return isMultiLine;
+}
+
+void BuiltStyledStreamWriter::pushValue(String const& value) {
+  if (addChildValues_)
+    childValues_.push_back(value);
+  else
+    *sout_ << value;
+}
+
+void BuiltStyledStreamWriter::writeIndent() {
+  // blep intended this to look at the so-far-written string
+  // to determine whether we are already indented, but
+  // with a stream we cannot do that. So we rely on some saved state.
+  // The caller checks indented_.
+
+  if (!indentation_.empty()) {
+    // In this case, drop newlines too.
+    *sout_ << '\n' << indentString_;
+  }
+}
+
+void BuiltStyledStreamWriter::writeWithIndent(String const& value) {
+  if (!indented_)
+    writeIndent();
+  *sout_ << value;
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void BuiltStyledStreamWriter::unindent() {
+  assert(indentString_.size() >= indentation_.size());
+  indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) {
+  if (cs_ == CommentStyle::None)
+    return;
+  if (!root.hasComment(commentBefore))
+    return;
+
+  if (!indented_)
+    writeIndent();
+  const String& comment = root.getComment(commentBefore);
+  String::const_iterator iter = comment.begin();
+  while (iter != comment.end()) {
+    *sout_ << *iter;
+    if (*iter == '\n' && ((iter + 1) != comment.end() && *(iter + 1) == '/'))
+      // writeIndent();  // would write extra newline
+      *sout_ << indentString_;
+    ++iter;
+  }
+  indented_ = false;
+}
+
+void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(
+    Value const& root) {
+  if (cs_ == CommentStyle::None)
+    return;
+  if (root.hasComment(commentAfterOnSameLine))
+    *sout_ << " " + root.getComment(commentAfterOnSameLine);
+
+  if (root.hasComment(commentAfter)) {
+    writeIndent();
+    *sout_ << root.getComment(commentAfter);
+  }
+}
+
+// static
+bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
+  return value.hasComment(commentBefore) ||
+         value.hasComment(commentAfterOnSameLine) ||
+         value.hasComment(commentAfter);
+}
+
+///////////////
+// StreamWriter
+
+StreamWriter::StreamWriter() : sout_(nullptr) {}
+StreamWriter::~StreamWriter() = default;
+StreamWriter::Factory::~Factory() = default;
+StreamWriterBuilder::StreamWriterBuilder() { setDefaults(&settings_); }
+StreamWriterBuilder::~StreamWriterBuilder() = default;
+StreamWriter* StreamWriterBuilder::newStreamWriter() const {
+  const String indentation = settings_["indentation"].asString();
+  const String cs_str = settings_["commentStyle"].asString();
+  const String pt_str = settings_["precisionType"].asString();
+  const bool eyc = settings_["enableYAMLCompatibility"].asBool();
+  const bool dnp = settings_["dropNullPlaceholders"].asBool();
+  const bool usf = settings_["useSpecialFloats"].asBool();
+  const bool emitUTF8 = settings_["emitUTF8"].asBool();
+  unsigned int pre = settings_["precision"].asUInt();
+  CommentStyle::Enum cs = CommentStyle::All;
+  if (cs_str == "All") {
+    cs = CommentStyle::All;
+  } else if (cs_str == "None") {
+    cs = CommentStyle::None;
+  } else {
+    throwRuntimeError("commentStyle must be 'All' or 'None'");
+  }
+  PrecisionType precisionType(significantDigits);
+  if (pt_str == "significant") {
+    precisionType = PrecisionType::significantDigits;
+  } else if (pt_str == "decimal") {
+    precisionType = PrecisionType::decimalPlaces;
+  } else {
+    throwRuntimeError("precisionType must be 'significant' or 'decimal'");
+  }
+  String colonSymbol = " : ";
+  if (eyc) {
+    colonSymbol = ": ";
+  } else if (indentation.empty()) {
+    colonSymbol = ":";
+  }
+  String nullSymbol = "null";
+  if (dnp) {
+    nullSymbol.clear();
+  }
+  if (pre > 17)
+    pre = 17;
+  String endingLineFeedSymbol;
+  return new BuiltStyledStreamWriter(indentation, cs, colonSymbol, nullSymbol,
+                                     endingLineFeedSymbol, usf, emitUTF8, pre,
+                                     precisionType);
+}
+
+bool StreamWriterBuilder::validate(Json::Value* invalid) const {
+  static const auto& valid_keys = *new std::set<String>{
+      "indentation",
+      "commentStyle",
+      "enableYAMLCompatibility",
+      "dropNullPlaceholders",
+      "useSpecialFloats",
+      "emitUTF8",
+      "precision",
+      "precisionType",
+  };
+  for (auto si = settings_.begin(); si != settings_.end(); ++si) {
+    auto key = si.name();
+    if (valid_keys.count(key))
+      continue;
+    if (invalid)
+      (*invalid)[key] = *si;
+    else
+      return false;
+  }
+  return invalid ? invalid->empty() : true;
+}
+
+Value& StreamWriterBuilder::operator[](const String& key) {
+  return settings_[key];
+}
+// static
+void StreamWriterBuilder::setDefaults(Json::Value* settings) {
+  //! [StreamWriterBuilderDefaults]
+  (*settings)["commentStyle"] = "All";
+  (*settings)["indentation"] = "\t";
+  (*settings)["enableYAMLCompatibility"] = false;
+  (*settings)["dropNullPlaceholders"] = false;
+  (*settings)["useSpecialFloats"] = false;
+  (*settings)["emitUTF8"] = false;
+  (*settings)["precision"] = 17;
+  (*settings)["precisionType"] = "significant";
+  //! [StreamWriterBuilderDefaults]
+}
+
+String writeString(StreamWriter::Factory const& factory, Value const& root) {
+  OStringStream sout;
+  StreamWriterPtr const writer(factory.newStreamWriter());
+  writer->write(root, &sout);
+  return sout.str();
+}
+
+OStream& operator<<(OStream& sout, Value const& root) {
+  StreamWriterBuilder builder;
+  StreamWriterPtr const writer(builder.newStreamWriter());
+  writer->write(root, &sout);
+  return sout;
+}
+
+} // namespace Json

+ 5 - 0
thirdparty/openxr/src/loader/.gitignore

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

+ 319 - 0
thirdparty/openxr/src/loader/android_utilities.cpp

@@ -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 <[email protected]>
+
+#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__

+ 32 - 0
thirdparty/openxr/src/loader/android_utilities.h

@@ -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 <[email protected]>
+
+#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__

+ 399 - 0
thirdparty/openxr/src/loader/api_layer_interface.cpp

@@ -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 <[email protected]>
+//
+
+#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;
+}

+ 54 - 0
thirdparty/openxr/src/loader/api_layer_interface.hpp

@@ -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 <[email protected]>
+//
+
+#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;
+};

+ 40 - 0
thirdparty/openxr/src/loader/exception_handling.hpp

@@ -0,0 +1,40 @@
+// Copyright (c) 2019-2022, The Khronos Group Inc.
+//
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+//
+// Initial Author: Ryan Pavlik <[email protected]>
+//
+// 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

+ 847 - 0
thirdparty/openxr/src/loader/loader_core.cpp

@@ -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 <[email protected]>, Dave Houlton <[email protected]>
+//
+
+#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

+ 303 - 0
thirdparty/openxr/src/loader/loader_instance.cpp

@@ -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 <[email protected]>
+//
+
+#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;
+}

+ 77 - 0
thirdparty/openxr/src/loader/loader_instance.hpp

@@ -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 <[email protected]>
+//
+
+#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};
+};

+ 239 - 0
thirdparty/openxr/src/loader/loader_logger.cpp

@@ -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 <[email protected]>
+//
+
+#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); }

+ 194 - 0
thirdparty/openxr/src/loader/loader_logger.hpp

@@ -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 <[email protected]>
+//
+
+#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);

+ 291 - 0
thirdparty/openxr/src/loader/loader_logger_recorders.cpp

@@ -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 <[email protected]>
+//
+
+#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

+ 40 - 0
thirdparty/openxr/src/loader/loader_logger_recorders.hpp

@@ -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 <[email protected]>
+//
+
+#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

+ 204 - 0
thirdparty/openxr/src/loader/loader_platform.hpp

@@ -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 <[email protected]>, Dave Houlton <[email protected]>
+//
+
+#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

+ 845 - 0
thirdparty/openxr/src/loader/manifest_file.cpp

@@ -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 <[email protected]>, Dave Houlton <[email protected]>
+//
+
+#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;
+}

+ 103 - 0
thirdparty/openxr/src/loader/manifest_file.hpp

@@ -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 <[email protected]>
+//
+
+#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;
+};

+ 493 - 0
thirdparty/openxr/src/loader/runtime_interface.cpp

@@ -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 <[email protected]>
+//
+
+#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;
+}

+ 84 - 0
thirdparty/openxr/src/loader/runtime_interface.hpp

@@ -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 <[email protected]>
+//
+
+#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;
+};

+ 700 - 0
thirdparty/openxr/src/loader/xr_generated_loader.cpp

@@ -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 <[email protected]>
+//
+
+#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
+
+

+ 252 - 0
thirdparty/openxr/src/loader/xr_generated_loader.hpp

@@ -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 <[email protected]>
+//
+
+#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
+

+ 347 - 0
thirdparty/openxr/src/xr_generated_dispatch_table.c

@@ -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 <[email protected]>
+//
+
+#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
+

+ 355 - 0
thirdparty/openxr/src/xr_generated_dispatch_table.h

@@ -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 <[email protected]>
+//
+
+#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
+