From 15a97422ba17aa9d8a78cf66bc9f449211a4437d Mon Sep 17 00:00:00 2001
From: Jakob Bornecrantz <jakob@collabora.com>
Date: Mon, 18 Mar 2019 05:52:32 +0000
Subject: [PATCH] xrt: Add all of Monado

---
 .gitignore                                    |   15 +
 CMakeLists.txt                                |   58 +
 CONTRIBUTING.md                               |   82 +
 README.md                                     |  206 +
 cmake/FindHIDAPI.cmake                        |   46 +
 cmake/FindWayland.cmake                       |   66 +
 cmake/SPIR-V.cmake                            |   38 +
 doc/CMakeLists.txt                            |   36 +
 doc/Doxyfile.in                               | 2541 ++++++++++++
 doc/roadmap.md                                |   35 +
 scripts/format-project.sh                     |   28 +
 src/CMakeLists.txt                            |    4 +
 src/external/glad/gl.c                        | 1654 ++++++++
 src/external/glad/gl.h                        | 3692 +++++++++++++++++
 .../openxr_includes/loader_interfaces.h       |  122 +
 src/external/openxr_includes/openxr.h         | 1479 +++++++
 .../openxr_includes/openxr_platform.h         |  415 ++
 .../openxr_includes/openxr_platform_defines.h |  120 +
 src/xrt/.clang-format                         |   48 +
 src/xrt/CMakeLists.txt                        |    8 +
 src/xrt/auxiliary/CMakeLists.txt              |   42 +
 src/xrt/auxiliary/math/m_api.h                |  250 ++
 src/xrt/auxiliary/math/m_base.cpp             |  430 ++
 src/xrt/auxiliary/math/m_eigen_interop.h      |  111 +
 src/xrt/auxiliary/math/m_optics.c             |  167 +
 src/xrt/auxiliary/math/m_quatexpmap.cpp       |  148 +
 src/xrt/auxiliary/util/u_debug.c              |  139 +
 src/xrt/auxiliary/util/u_debug.h              |   81 +
 src/xrt/auxiliary/util/u_device.c             |  126 +
 src/xrt/auxiliary/util/u_device.h             |   35 +
 src/xrt/auxiliary/util/u_misc.c               |   16 +
 src/xrt/auxiliary/util/u_misc.h               |   19 +
 src/xrt/auxiliary/util/u_time.cpp             |  135 +
 src/xrt/auxiliary/util/u_time.h               |  106 +
 src/xrt/compositor/CMakeLists.txt             |   62 +
 src/xrt/compositor/client/comp_gl_api.c       |   10 +
 src/xrt/compositor/client/comp_gl_api.h       |   12 +
 src/xrt/compositor/client/comp_gl_client.c    |  242 ++
 src/xrt/compositor/client/comp_gl_client.h    |   91 +
 src/xrt/compositor/client/comp_vk_client.c    |  276 ++
 src/xrt/compositor/client/comp_vk_client.h    |  103 +
 src/xrt/compositor/client/comp_xlib_client.c  |   51 +
 src/xrt/compositor/client/comp_xlib_client.h  |   58 +
 src/xrt/compositor/common/comp_vk.c           | 1003 +++++
 src/xrt/compositor/common/comp_vk.h           |  339 ++
 src/xrt/compositor/common/comp_vk_swapchain.c |  389 ++
 src/xrt/compositor/common/comp_vk_swapchain.h |  133 +
 .../compositor/main/comp_client_interface.h   |   30 +
 src/xrt/compositor/main/comp_compositor.c     |  505 +++
 src/xrt/compositor/main/comp_compositor.h     |  234 ++
 src/xrt/compositor/main/comp_distortion.c     |  719 ++++
 src/xrt/compositor/main/comp_distortion.h     |  135 +
 src/xrt/compositor/main/comp_glue_gl.c        |   22 +
 src/xrt/compositor/main/comp_glue_vk.c        |   65 +
 src/xrt/compositor/main/comp_glue_xlib.c      |   36 +
 src/xrt/compositor/main/comp_renderer.c       |  997 +++++
 src/xrt/compositor/main/comp_renderer.h       |   53 +
 src/xrt/compositor/main/comp_settings.c       |   51 +
 src/xrt/compositor/main/comp_settings.h       |   83 +
 src/xrt/compositor/main/comp_swapchain.c      |  303 ++
 src/xrt/compositor/main/comp_window.h         |   92 +
 .../main/comp_window_direct_mode.cpp          |  648 +++
 .../compositor/main/comp_window_wayland.cpp   |  629 +++
 src/xrt/compositor/main/comp_window_xcb.cpp   |  408 ++
 src/xrt/compositor/shaders/CMakeLists.txt     |    5 +
 src/xrt/compositor/shaders/distortion.vert    |   34 +
 src/xrt/compositor/shaders/none.frag          |   17 +
 src/xrt/compositor/shaders/panotools.frag     |   77 +
 src/xrt/compositor/shaders/vive.frag          |   84 +
 src/xrt/drivers/CMakeLists.txt                |   37 +
 src/xrt/drivers/hdk/hdk_device.cpp            |  276 ++
 src/xrt/drivers/hdk/hdk_device.h              |   76 +
 src/xrt/drivers/hdk/hdk_interface.h           |   23 +
 src/xrt/drivers/hdk/hdk_prober.c              |  107 +
 src/xrt/drivers/ohmd/oh_device.c              |  379 ++
 src/xrt/drivers/ohmd/oh_device.h              |   69 +
 src/xrt/drivers/ohmd/oh_interface.h           |   22 +
 src/xrt/drivers/ohmd/oh_prober.c              |  112 +
 src/xrt/include/xrt/xrt_compiler.h            |   44 +
 src/xrt/include/xrt/xrt_compositor.h          |  341 ++
 src/xrt/include/xrt/xrt_config.h              |   30 +
 src/xrt/include/xrt/xrt_defines.h             |  196 +
 src/xrt/include/xrt/xrt_device.h              |  174 +
 src/xrt/include/xrt/xrt_documentation.h       |   22 +
 src/xrt/include/xrt/xrt_gfx_gl.h              |   28 +
 src/xrt/include/xrt/xrt_gfx_vk.h              |   53 +
 src/xrt/include/xrt/xrt_gfx_xlib.h            |   39 +
 src/xrt/include/xrt/xrt_openxr_includes.h     |   31 +
 src/xrt/include/xrt/xrt_prober.h              |   42 +
 src/xrt/include/xrt/xrt_vulkan_includes.h     |   13 +
 src/xrt/state_trackers/CMakeLists.txt         |   47 +
 src/xrt/state_trackers/dev/README.md          |    6 +
 src/xrt/state_trackers/oxr/oxr_api_action.c   |  305 ++
 src/xrt/state_trackers/oxr/oxr_api_debug.c    |  106 +
 src/xrt/state_trackers/oxr/oxr_api_funcs.h    |  534 +++
 src/xrt/state_trackers/oxr/oxr_api_instance.c |  219 +
 .../state_trackers/oxr/oxr_api_negotiate.c    |  269 ++
 src/xrt/state_trackers/oxr/oxr_api_session.c  |  228 +
 src/xrt/state_trackers/oxr/oxr_api_space.c    |  125 +
 .../state_trackers/oxr/oxr_api_swapchain.c    |  146 +
 src/xrt/state_trackers/oxr/oxr_api_system.c   |  297 ++
 src/xrt/state_trackers/oxr/oxr_api_verify.h   |  157 +
 src/xrt/state_trackers/oxr/oxr_event.cpp      |  148 +
 src/xrt/state_trackers/oxr/oxr_instance.c     |  155 +
 src/xrt/state_trackers/oxr/oxr_logger.cpp     |  158 +
 src/xrt/state_trackers/oxr/oxr_logger.h       |   69 +
 src/xrt/state_trackers/oxr/oxr_objects.h      |  585 +++
 src/xrt/state_trackers/oxr/oxr_session.c      |  498 +++
 src/xrt/state_trackers/oxr/oxr_session_gl.c   |   46 +
 src/xrt/state_trackers/oxr/oxr_session_vk.c   |   49 +
 src/xrt/state_trackers/oxr/oxr_space.c        |  260 ++
 src/xrt/state_trackers/oxr/oxr_swapchain.c    |  115 +
 src/xrt/state_trackers/oxr/oxr_swapchain_gl.c |   72 +
 src/xrt/state_trackers/oxr/oxr_swapchain_vk.c |   75 +
 src/xrt/state_trackers/oxr/oxr_system.c       |  192 +
 src/xrt/state_trackers/oxr/oxr_two_call.h     |   40 +
 src/xrt/state_trackers/oxr/oxr_verify.cpp     |  145 +
 src/xrt/state_trackers/oxr/oxr_vulkan.c       |  129 +
 src/xrt/targets/CMakeLists.txt                |    8 +
 src/xrt/targets/openxr/CMakeLists.txt         |   98 +
 src/xrt/targets/openxr/libopenxr.version      |    4 +
 src/xrt/targets/openxr/target.c               |  102 +
 122 files changed, 27995 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 CMakeLists.txt
 create mode 100644 CONTRIBUTING.md
 create mode 100644 cmake/FindHIDAPI.cmake
 create mode 100644 cmake/FindWayland.cmake
 create mode 100644 cmake/SPIR-V.cmake
 create mode 100644 doc/CMakeLists.txt
 create mode 100644 doc/Doxyfile.in
 create mode 100644 doc/roadmap.md
 create mode 100755 scripts/format-project.sh
 create mode 100644 src/CMakeLists.txt
 create mode 100644 src/external/glad/gl.c
 create mode 100644 src/external/glad/gl.h
 create mode 100644 src/external/openxr_includes/loader_interfaces.h
 create mode 100644 src/external/openxr_includes/openxr.h
 create mode 100644 src/external/openxr_includes/openxr_platform.h
 create mode 100644 src/external/openxr_includes/openxr_platform_defines.h
 create mode 100644 src/xrt/.clang-format
 create mode 100644 src/xrt/CMakeLists.txt
 create mode 100644 src/xrt/auxiliary/CMakeLists.txt
 create mode 100644 src/xrt/auxiliary/math/m_api.h
 create mode 100644 src/xrt/auxiliary/math/m_base.cpp
 create mode 100644 src/xrt/auxiliary/math/m_eigen_interop.h
 create mode 100644 src/xrt/auxiliary/math/m_optics.c
 create mode 100644 src/xrt/auxiliary/math/m_quatexpmap.cpp
 create mode 100644 src/xrt/auxiliary/util/u_debug.c
 create mode 100644 src/xrt/auxiliary/util/u_debug.h
 create mode 100644 src/xrt/auxiliary/util/u_device.c
 create mode 100644 src/xrt/auxiliary/util/u_device.h
 create mode 100644 src/xrt/auxiliary/util/u_misc.c
 create mode 100644 src/xrt/auxiliary/util/u_misc.h
 create mode 100644 src/xrt/auxiliary/util/u_time.cpp
 create mode 100644 src/xrt/auxiliary/util/u_time.h
 create mode 100644 src/xrt/compositor/CMakeLists.txt
 create mode 100644 src/xrt/compositor/client/comp_gl_api.c
 create mode 100644 src/xrt/compositor/client/comp_gl_api.h
 create mode 100644 src/xrt/compositor/client/comp_gl_client.c
 create mode 100644 src/xrt/compositor/client/comp_gl_client.h
 create mode 100644 src/xrt/compositor/client/comp_vk_client.c
 create mode 100644 src/xrt/compositor/client/comp_vk_client.h
 create mode 100644 src/xrt/compositor/client/comp_xlib_client.c
 create mode 100644 src/xrt/compositor/client/comp_xlib_client.h
 create mode 100644 src/xrt/compositor/common/comp_vk.c
 create mode 100644 src/xrt/compositor/common/comp_vk.h
 create mode 100644 src/xrt/compositor/common/comp_vk_swapchain.c
 create mode 100644 src/xrt/compositor/common/comp_vk_swapchain.h
 create mode 100644 src/xrt/compositor/main/comp_client_interface.h
 create mode 100644 src/xrt/compositor/main/comp_compositor.c
 create mode 100644 src/xrt/compositor/main/comp_compositor.h
 create mode 100644 src/xrt/compositor/main/comp_distortion.c
 create mode 100644 src/xrt/compositor/main/comp_distortion.h
 create mode 100644 src/xrt/compositor/main/comp_glue_gl.c
 create mode 100644 src/xrt/compositor/main/comp_glue_vk.c
 create mode 100644 src/xrt/compositor/main/comp_glue_xlib.c
 create mode 100644 src/xrt/compositor/main/comp_renderer.c
 create mode 100644 src/xrt/compositor/main/comp_renderer.h
 create mode 100644 src/xrt/compositor/main/comp_settings.c
 create mode 100644 src/xrt/compositor/main/comp_settings.h
 create mode 100644 src/xrt/compositor/main/comp_swapchain.c
 create mode 100644 src/xrt/compositor/main/comp_window.h
 create mode 100644 src/xrt/compositor/main/comp_window_direct_mode.cpp
 create mode 100644 src/xrt/compositor/main/comp_window_wayland.cpp
 create mode 100644 src/xrt/compositor/main/comp_window_xcb.cpp
 create mode 100644 src/xrt/compositor/shaders/CMakeLists.txt
 create mode 100644 src/xrt/compositor/shaders/distortion.vert
 create mode 100644 src/xrt/compositor/shaders/none.frag
 create mode 100644 src/xrt/compositor/shaders/panotools.frag
 create mode 100644 src/xrt/compositor/shaders/vive.frag
 create mode 100644 src/xrt/drivers/CMakeLists.txt
 create mode 100644 src/xrt/drivers/hdk/hdk_device.cpp
 create mode 100644 src/xrt/drivers/hdk/hdk_device.h
 create mode 100644 src/xrt/drivers/hdk/hdk_interface.h
 create mode 100644 src/xrt/drivers/hdk/hdk_prober.c
 create mode 100644 src/xrt/drivers/ohmd/oh_device.c
 create mode 100644 src/xrt/drivers/ohmd/oh_device.h
 create mode 100644 src/xrt/drivers/ohmd/oh_interface.h
 create mode 100644 src/xrt/drivers/ohmd/oh_prober.c
 create mode 100644 src/xrt/include/xrt/xrt_compiler.h
 create mode 100644 src/xrt/include/xrt/xrt_compositor.h
 create mode 100644 src/xrt/include/xrt/xrt_config.h
 create mode 100644 src/xrt/include/xrt/xrt_defines.h
 create mode 100644 src/xrt/include/xrt/xrt_device.h
 create mode 100644 src/xrt/include/xrt/xrt_documentation.h
 create mode 100644 src/xrt/include/xrt/xrt_gfx_gl.h
 create mode 100644 src/xrt/include/xrt/xrt_gfx_vk.h
 create mode 100644 src/xrt/include/xrt/xrt_gfx_xlib.h
 create mode 100644 src/xrt/include/xrt/xrt_openxr_includes.h
 create mode 100644 src/xrt/include/xrt/xrt_prober.h
 create mode 100644 src/xrt/include/xrt/xrt_vulkan_includes.h
 create mode 100644 src/xrt/state_trackers/CMakeLists.txt
 create mode 100644 src/xrt/state_trackers/dev/README.md
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_action.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_debug.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_funcs.h
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_instance.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_negotiate.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_session.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_space.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_swapchain.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_system.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_api_verify.h
 create mode 100644 src/xrt/state_trackers/oxr/oxr_event.cpp
 create mode 100644 src/xrt/state_trackers/oxr/oxr_instance.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_logger.cpp
 create mode 100644 src/xrt/state_trackers/oxr/oxr_logger.h
 create mode 100644 src/xrt/state_trackers/oxr/oxr_objects.h
 create mode 100644 src/xrt/state_trackers/oxr/oxr_session.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_session_gl.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_session_vk.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_space.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_swapchain.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_swapchain_gl.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_swapchain_vk.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_system.c
 create mode 100644 src/xrt/state_trackers/oxr/oxr_two_call.h
 create mode 100644 src/xrt/state_trackers/oxr/oxr_verify.cpp
 create mode 100644 src/xrt/state_trackers/oxr/oxr_vulkan.c
 create mode 100644 src/xrt/targets/CMakeLists.txt
 create mode 100644 src/xrt/targets/openxr/CMakeLists.txt
 create mode 100644 src/xrt/targets/openxr/libopenxr.version
 create mode 100644 src/xrt/targets/openxr/target.c

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 000000000..18df7d33b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+CMakeCache.txt
+CMakeLists.txt.user
+*CMakeFiles/
+*Makefile
+*cmake_install.cmake
+*libopenxr_monado.so
+CMakeDoxyfile.in
+CMakeDoxygenDefaults.cmake
+doc/Doxyfile
+doc/html/
+doc/latex/
+openxr_monado-dev.json
+openxr_monado.json
+src/xrt/compositor/shaders/*.vert.h
+src/xrt/compositor/shaders/*.frag.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..7ce1d41a3
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright 2018-2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+cmake_minimum_required(VERSION 3.10.0)
+project(XRT VERSION 0.1.0)
+
+# CMake 3.11 introduced CMP0072 - Prefer GLVND
+if(POLICY CMP0072)
+    cmake_policy(SET CMP0072 NEW)
+endif()
+
+option(BUILD_TESTS "Build compile and runtime tests" ON)
+option(OPENXR_USE_LOADER "Application uses loader" ON)
+
+
+###
+# Dependencies
+###
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+include(CMakeDependentOption)
+include(SPIR-V)
+
+find_package(Eigen3 REQUIRED)
+find_package(Vulkan REQUIRED)
+find_package(OpenGL)
+find_package(HIDAPI)
+
+# Push into a FindOpenHMD.cmake file.
+find_package(PkgConfig)
+pkg_check_modules(OPENHMD openhmd)
+
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    find_package(X11)
+    find_package(Wayland)
+    pkg_check_modules(XCB xcb xcb-randr)
+endif()
+
+cmake_dependent_option(BUILD_WITH_OPENHMD "Enable OpenHMD driver" ON "OPENHMD_FOUND" OFF)
+cmake_dependent_option(BUILD_WITH_WAYLAND "Enable Wayland support" ON "WAYLAND_FOUND" OFF)
+cmake_dependent_option(BUILD_WITH_XLIB "Enable xlib support" ON "X11_FOUND" OFF)
+cmake_dependent_option(BUILD_WITH_OPENGL "Enable OpenGL Graphics API support?" ON "OPENGL_FOUND" OFF)
+
+
+###
+# Flags
+###
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wall -Wextra -Wno-unused-parameter")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-unused-parameter")
+
+
+###
+# Decend into madness.
+###
+
+add_subdirectory(src)
+add_subdirectory(doc)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..d9e2c543a
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,82 @@
+# Contribution Guidelines
+
+There are plenty of valid reasons why someone might not be able
+to follow all of the guidelines in this section, and that's OK,
+especially for new contributors or those new to open source entirely.
+Just let us know and we'll figure out a way to help you get involved successfully.
+
+> Important note: Unlike the guidelines here, the Code of Conduct,
+> available at <https://www.freedesktop.org/wiki/CodeOfConduct/>,
+> is **not** optional,
+> and applies in its entirety to anyone involved in the project,
+> for the safety and comfort of all.
+> See the README for associated contacts.
+
+## Pull/Merge Requests
+
+- If you're considering starting work on a large change that you'd like to contribute,
+  it is recommended to first open an issue before you start,
+  to begin a discussion and help smooth the acceptance of your contribution.
+
+- If you are able, please make sure to run clang-format
+  (ideally version 7 or newer) before each commit,
+  so that you only commit things that are cleanly styled.
+  Consistent, machine-performed formatting improves readability and makes it easier for others to contribute.
+  It also makes it easier to review changes.
+  If you can't run clang-format, just mention this fact in your request and we'd be happy to help,
+  either in a single "Clean up formatting." commit on top of your work,
+  or by "re-writing history" (with your permission and leaving your commit authorship intact),
+  revising each commit to apply formatting.
+
+- Avoid including whitespace or other formatting changes to unrelated code when committing.
+  The `git add -p` command or the "stage selected lines/hunks" feature of various Git GUIs are
+  great ways of making sure you only stage and commit the changes that you mean to.
+  Relatedly, `git commit -v` (if you commit from the command line) can be a great help
+  in making sure you aren't committing things you don't mean to,
+  by showing the diff you're committing in your commit message editor.
+  (This can even be set system-wide in `git config --global commit.verbose true`
+  if you find it as life-changing as many others have - thanks
+  [@emilyst](https://twitter.com/emilyst/status/1039205453010362368).)
+
+- If you can, before submitting a pull/merge request, try building with clang-tidy enabled,
+  and if you touched any code that has or should have documentation,
+  build and check the documentation and see if it looks OK.
+
+- We work to keep the code free of warnings -
+  please help by making sure your changes build cleanly (and pass all tests).
+  When on compilers that take warning flags like gcc and clang do,
+  the build system automatically turns on quite a few of them.
+  If a warning stumps you, just mention it in the request so we can figure it out together.
+
+### Issues
+
+Constructive issues are a valued form of contribution.
+Please try to include any relevant information
+(whether it is a request for improvement or a bug report).
+We'll try to respond promptly,
+but there is no guarantee or warranty (as noted in the license),
+absent any externally-arranged consulting or support contract.
+
+Since this is a runtime/implementation of an API used by other applications,
+bug reports should include:
+
+- details about your build environment
+  - architecture
+  - compiler
+  - compiler version
+  - build flags (defines, configuration/feature flags)
+- associated application code
+  - for logic/execution errors, a new (failing) test case is ideal,
+    otherwise a description of expected and actual behavior
+  - if you cannot disclose your code, or even if you can,
+    an "artificial", minimally-sized example can be very valuable.
+
+---
+
+## Copyright and License for this CONTRIBUTING.md file
+
+For this file only:
+
+> Copyright 2018-2019 Collabora, Ltd.
+>
+> SPDX-License-Identifier: CC-BY-4.0
diff --git a/README.md b/README.md
index 1ba75d55c..6bac7aabd 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,208 @@
 
 # Monado - XR Runtime (XRT)
+
+Monado is an open source XR runtime delivering immersive experiences such as VR
+and AR on on mobile, PC/desktop, and any other device
+(because gosh darn people
+come up with a lot of weird hardware).
+Monado aims to be a complete and conforming implementation
+of the OpenXR API made by Khronos.
+The project currently is being developed for GNU/Linux
+and aims to support other operating systems in the near future.
+"Monado" has no specific meaning and is just a name.
+
+## Monado source tree
+
+* `src/xrt/include` - headers that define the internal interfaces of Monado.
+* `src/xrt/compositor` - code for doing distortion and driving the display hardware of a device.
+* `src/xrt/auxiliary` - utilies and other larger components.
+* `src/xrt/drivers` - hardware drivers.
+* `src/xrt/state_trackers/oxr` - OpenXR API implementation.
+* `src/xrt/targets` - glue code and build logic to produce final binaries.
+* `src/external` - a small collection of external code and headers.
+
+## Getting Started
+
+Dependencies include:
+
+* [CMake][] 3.10 or newer
+* [OpenHMD](https://openhmd.net) (found using pkg-config)
+* Vulkan headers
+* Eigen3
+* glslang
+
+Optional (but recommended) dependencies:
+
+* OpenGL headers for OpenGL graphics support
+* libxcb and xcb-xrandr development packages
+
+Truly optional dependencies:
+
+* Doxygen
+* Wayland development packages
+* Xlib development pages
+* libhidapi (for the HDK driver)
+
+Tested distributions that are fully compatible,
+on Intel and AMD graphics:
+
+* Ubuntu 18.10 (18.04 does not work)
+* Debian 10 `buster`
+  (currently the "testing" release -
+  current stable Stretch does not have new enough packages)
+
+These distributions include recent-enough versions of all the
+software to use direct mode,
+without using any external, third-party, or backported
+package sources.
+
+See also [Status of DRM leases](https://haagch.frickel.club/#!drmlease.md)
+for more details on specific packages, versions, and commits.
+
+Build process is similar to other CMake builds,
+so something like the following will build it.
+
+Go into the source directory, create a build directory,
+and change into it.
+
+    mkdir build
+    cd build
+
+Then, invoke [CMake to generate a project][cmake-generate].
+Feel free to change the build type or generator ("Ninja" is fast and parallel) as you see fit.
+
+    cmake .. -DCMAKE_BUILD_TYPE=Debug -G "Unix Makefiles"
+
+If you plan to install the runtime,
+append something like `-DCMAKE_INSTALL_PREFIX=~/.local`
+to specify the root of the install directory.
+(The default install prefix is `/usr/local`.)
+
+To build, [the generic CMake build commands][cmake-build] below will work on all systems,
+though you can manually invoke your build tool (`make`, `ninja`, etc.) if you prefer.
+The first command builds the runtime and docs,
+and the second, which is optional, installs the runtime under `${CMAKE_INSTALL_PREFIX}`.
+
+    cmake --build .
+    cmake --build . --target install
+
+Alternately, if using Make, the following will build the runtime and docs, then install.
+Replace `make` with `ninja` if you used the Ninja generator.
+
+    make
+    make install
+
+Documentation can be browsed by opening `docs/html/index.html` in the build directory in a web browser.
+
+## Getting started using OpenXR with Monado
+
+This implements the [OpenXR](https://khronos.org/openxr) API,
+so to do anything with it, you'll need an application
+that uses OpenXR, along with the OpenXR loader.
+The OpenXR loader is a glue library that connects OpenXR applications to OpenXR runtimes such as Monado
+It determines which runtime to use by reading config file default `/usr/local/share/openxr/0/active_runtime.json`
+and processes environment variables such as `XR_RUNTIME_JSON=/usr/share/openxr/0/openxr_monado.json`.
+It can also insert OpenXR API Layers without the application or the runtime having to do it.
+
+You can use the `hello_xr` sample provided with the
+OpenXR loader and API layers.
+
+The OpenXR loader can be pointed to a runtime json file in a nonstandard location with the environment variable `XR_RUNTIME_JSON`. Example:
+
+    XR_RUNTIME_JSON=~/monado/build/xrt_oopenxr_monado_dev.json ./openxr-example
+
+For this reason this runtime creates two manifest files within the build directory:
+
+* `openxr_monado.json` uses a relative path to the runtime, and is intended to be installed with `make install`.
+* `openxr_monado_dev.json` uses an absolute path to the runtime in its build directory,
+  and is intended to be used for development without installing the runtime.
+
+If Monado has been installed through a distribution package
+and provides the "active runtime" file /usr/local/share/openxr/0/active_runtime.json,
+then the loader will automatically use Monado when starting any OpenXR application.
+
+If Monado has been compiled in a custom directory like ~/monado/build,
+the OpenXR loader can be pointed to the runtime when starting an OpenXR application
+by setting the environment variable XR_RUNTIME_JSON to the `openxr_monado_dev.json` manifest
+that was generated by the build: see above.
+
+Note that the loader can always find and load the runtime
+if the path to the runtime library given in the json manifest is an absolute path,
+but if a relative path like `libopenxr_monado.so.0` is given,
+then `LD_LIBRARY_PATH` must include the directory that contains `libopenxr_monado.so.0`.
+The absolute path in `openxr_monado_dev.json` takes care of this for you.
+
+## Direct mode
+
+Our direct mode code requires a connected HMD to have the `non-desktop` xrandr
+property set to 1.
+Only the most common HMDs have the needed quirks added to the linux kernel.
+Just keep on reading for more info on how to work around that.
+
+If you know that your HMD lacks the quirk you can run this command **before** or
+after connecting the HMD and it will have it. Where `HDMI-A-0` is the xrandr
+output name where you plug the HMD in.
+
+```bash
+xrandr --output HDMI-A-0 --prop --set non-desktop 1
+```
+
+You can verify that it stuck with the command.
+
+```bash
+xrand --prop
+```
+
+## Coding style and formatting
+
+[clang-format][] is used,
+and a `.clang-format` config file is present in the repo
+to allow your editor to use them.
+
+To manually apply clang-format to every non-external source file in the tree,
+run this command in the source dir with a `sh`-compatible shell
+(Git for Windows git-bash should be OK):
+
+    scripts/format-project.sh
+
+You can optionally put something like `CLANG_FORMAT=clang-format-7` before that command
+if your clang-format binary isn't named `clang-format`.
+Note that you'll typically prefer to use something like `git clang-format`
+to just re-format your changes, in case version differences in tools result in overall format changes.
+
+[clang-format]: https://releases.llvm.org/7.0.0/tools/clang/docs/ClangFormat.html
+[cmake-build]: https://cmake.org/cmake/help/v3.12/manual/cmake.1.html#build-tool-mode
+[cmake-generate]: https://cmake.org/cmake/help/v3.12/manual/cmake.1.html
+[CMake]: https://cmake.org
+
+## Contributing, Code of Conduct
+
+See `CONTRIBUTING.md` for details of contribution guidelines.
+
+Please note that this project is released with a Contributor Code of Conduct.
+By participating in this project you agree to abide by its terms.
+
+We follow the standard freedesktop.org code of conduct,
+available at <https://www.freedesktop.org/wiki/CodeOfConduct/>,
+which is based on the [Contributor Covenant](https://www.contributor-covenant.org).
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting:
+
+* First-line project contacts:
+  * Jakob Bornecrantz <jakob@collabora.com>
+  * Ryan Pavlik <ryan.pavlik@collabora.com>
+* freedesktop.org contacts: see most recent list at <https://www.freedesktop.org/wiki/CodeOfConduct/>
+
+## Copyright and License for this README.md file
+
+For this file only:
+
+> Copyright 2018-2019 Collabora, Ltd.
+> Code of Conduct section: excerpt adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4.1,
+> available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>,
+> and from the freedesktop.org-specific version of that code,
+> available at <https://www.freedesktop.org/wiki/CodeOfConduct/>
+>
+>
+> SPDX-License-Identifier: CC-BY-4.0
diff --git a/cmake/FindHIDAPI.cmake b/cmake/FindHIDAPI.cmake
new file mode 100644
index 000000000..646f90026
--- /dev/null
+++ b/cmake/FindHIDAPI.cmake
@@ -0,0 +1,46 @@
+# - try to find HIDAPI library
+# from http://www.signal11.us/oss/hidapi/
+#
+# Cache Variables: (probably not for direct use in your scripts)
+#  HIDAPI_INCLUDE_DIR
+#  HIDAPI_LIBRARY
+#
+# Non-cache variables you might use in your CMakeLists.txt:
+#  HIDAPI_FOUND
+#  HIDAPI_INCLUDE_DIRS
+#  HIDAPI_LIBRARIES
+#
+# Requires these CMake modules:
+#  FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+find_library(HIDAPI_LIBRARY
+	NAMES hidapi hidapi-libusb)
+
+find_path(HIDAPI_INCLUDE_DIR
+	NAMES hidapi.h
+	PATH_SUFFIXES
+	hidapi)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(HIDAPI
+	DEFAULT_MSG
+	HIDAPI_LIBRARY
+	HIDAPI_INCLUDE_DIR)
+
+if(HIDAPI_FOUND)
+	set(HIDAPI_LIBRARIES "${HIDAPI_LIBRARY}")
+
+	set(HIDAPI_INCLUDE_DIRS "${HIDAPI_INCLUDE_DIR}")
+endif()
+
+mark_as_advanced(HIDAPI_INCLUDE_DIR HIDAPI_LIBRARY)
diff --git a/cmake/FindWayland.cmake b/cmake/FindWayland.cmake
new file mode 100644
index 000000000..f93218b87
--- /dev/null
+++ b/cmake/FindWayland.cmake
@@ -0,0 +1,66 @@
+# Try to find Wayland on a Unix system
+#
+# This will define:
+#
+#   WAYLAND_FOUND       - True if Wayland is found
+#   WAYLAND_LIBRARIES   - Link these to use Wayland
+#   WAYLAND_INCLUDE_DIR - Include directory for Wayland
+#   WAYLAND_DEFINITIONS - Compiler flags for using Wayland
+#
+# In addition the following more fine grained variables will be defined:
+#
+#   WAYLAND_CLIENT_FOUND  WAYLAND_CLIENT_INCLUDE_DIR  WAYLAND_CLIENT_LIBRARIES
+#   WAYLAND_SERVER_FOUND  WAYLAND_SERVER_INCLUDE_DIR  WAYLAND_SERVER_LIBRARIES
+#   WAYLAND_EGL_FOUND     WAYLAND_EGL_INCLUDE_DIR     WAYLAND_EGL_LIBRARIES
+#
+# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+IF (NOT WIN32)
+  IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
+    # In the cache already
+    SET(WAYLAND_FIND_QUIETLY TRUE)
+  ENDIF ()
+
+  # Use pkg-config to get the directories and then use these values
+  # in the FIND_PATH() and FIND_LIBRARY() calls
+  FIND_PACKAGE(PkgConfig)
+  PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
+
+  SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
+
+  FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR  NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+  FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR  NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+  FIND_PATH(WAYLAND_EGL_INCLUDE_DIR     NAMES wayland-egl.h    HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+  FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR  NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
+
+  FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client   HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+  FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server   HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+  FIND_LIBRARY(WAYLAND_EGL_LIBRARIES    NAMES wayland-egl      HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+  FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor   HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
+
+  set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR})
+
+  set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
+
+  list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR)
+
+  include(FindPackageHandleStandardArgs)
+
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT  DEFAULT_MSG  WAYLAND_CLIENT_LIBRARIES  WAYLAND_CLIENT_INCLUDE_DIR)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER  DEFAULT_MSG  WAYLAND_SERVER_LIBRARIES  WAYLAND_SERVER_INCLUDE_DIR)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL     DEFAULT_MSG  WAYLAND_EGL_LIBRARIES     WAYLAND_EGL_INCLUDE_DIR)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR  DEFAULT_MSG  WAYLAND_CURSOR_LIBRARIES  WAYLAND_CURSOR_INCLUDE_DIR)
+  FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND         DEFAULT_MSG  WAYLAND_LIBRARIES         WAYLAND_INCLUDE_DIR)
+
+  MARK_AS_ADVANCED(
+        WAYLAND_INCLUDE_DIR         WAYLAND_LIBRARIES
+        WAYLAND_CLIENT_INCLUDE_DIR  WAYLAND_CLIENT_LIBRARIES
+        WAYLAND_SERVER_INCLUDE_DIR  WAYLAND_SERVER_LIBRARIES
+        WAYLAND_EGL_INCLUDE_DIR     WAYLAND_EGL_LIBRARIES
+        WAYLAND_CURSOR_INCLUDE_DIR  WAYLAND_CURSOR_LIBRARIES
+  )
+
+ENDIF ()
diff --git a/cmake/SPIR-V.cmake b/cmake/SPIR-V.cmake
new file mode 100644
index 000000000..13218725e
--- /dev/null
+++ b/cmake/SPIR-V.cmake
@@ -0,0 +1,38 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+find_program(GLSLANGVALIDATOR_COMMAND
+	glslangValidator)
+if(NOT GLSLANGVALIDATOR_COMMAND)
+	message(FATAL_ERROR "glslangValidator required - source maintained at https://github.com/KhronosGroup/glslang")
+endif()
+
+#
+# Generate a SPIR-V header file, with the given var name. Returns the header.
+#
+function(spirv_shader ret GLSL VAR)
+	set(HEADER "${CMAKE_CURRENT_BINARY_DIR}/${GLSL}.h")
+	set(GLSL "${CMAKE_CURRENT_SOURCE_DIR}/${GLSL}")
+
+	add_custom_command(
+		OUTPUT ${HEADER}
+		COMMAND ${GLSLANGVALIDATOR_COMMAND} -V ${GLSL} --vn ${VAR} -o ${HEADER}
+		DEPENDS ${GLSL})
+
+
+	set(${ret} "${HEADER}" PARENT_SCOPE)
+endfunction(spirv_shader)
+
+#
+# Generate SPIR-V header files from the arguments. Returns a list of headers.
+#
+function(spirv_shaders ret)
+
+	foreach(GLSL ${ARGN})
+		string(MAKE_C_IDENTIFIER ${GLSL} IDENTIFIER)
+		spirv_shader(HEADER ${GLSL} ${IDENTIFIER})
+		list(APPEND HEADERS ${HEADER})
+	endforeach()
+
+	set(${ret} "${HEADERS}" PARENT_SCOPE)
+endfunction(spirv_shaders)
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 000000000..d0e87f707
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright 2018-2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+# check if Doxygen is installed
+find_package(Doxygen)
+cmake_dependent_option(BUILD_DOC "Build documentation" ON "DOXYGEN_FOUND" OFF)
+cmake_dependent_option(BUILD_DOC_WARN_UNDOCUMENTED "Warn on undocumented entities when building documentation" OFF "DOXYGEN_FOUND" OFF)
+cmake_dependent_option(BUILD_DOC_EXTRACT_ALL "Extract all entities for documentation, not just documented ones (conflicts with BUILD_DOCS_WARN_UNDOCUMENTED)" ON "DOXYGEN_FOUND; NOT BUILD_DOCS_WARN_UNDOCUMENTED" OFF)
+
+if(BUILD_DOC)
+    if(BUILD_DOC_WARN_UNDOCUMENTED)
+        set(DOXYGEN_WARN_UNDOCUMENTED YES)
+    else()
+        set(DOXYGEN_WARN_UNDOCUMENTED NO)
+    endif()
+    if(BUILD_DOC_EXTRACT_ALL)
+        set(DOXYGEN_EXTRACT_ALL YES)
+    else()
+        set(DOXYGEN_EXTRACT_ALL NO)
+    endif()
+
+    # set input and output files
+    set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+    set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+    # request to configure the file
+    configure_file(${DOXYGEN_IN} ${DOXYGEN_OUT} @ONLY)
+
+    # note the option ALL which allows to build the docs together with the application
+    add_custom_target(doc_doxygen ALL
+        COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+        COMMENT "Generating API documentation with Doxygen"
+        VERBATIM
+        )
+endif()
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 000000000..dae08661d
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,2541 @@
+## Changed properties goes on the top.
+
+QUIET                  = YES
+PROJECT_NAME           = "OpenXR Runtime"
+OUTPUT_DIRECTORY       = @CMAKE_CURRENT_BINARY_DIR@/
+INPUT                  = \
+     @CMAKE_CURRENT_SOURCE_DIR@/../README.md \
+     @CMAKE_CURRENT_SOURCE_DIR@/../src/xrt \
+     @CMAKE_CURRENT_SOURCE_DIR@
+
+USE_MDFILE_AS_MAINPAGE = @CMAKE_CURRENT_SOURCE_DIR@/../README.md
+
+RECURSIVE              = YES
+EXCLUDE                = @CMAKE_CURRENT_SOURCE_DIR@/../src/xrt/generated
+STRIP_FROM_PATH        = @CMAKE_SOURCE_DIR@/src/xrt \
+                         @CMAKE_CURRENT_SOURCE_DIR@
+
+
+PREDEFINED             = VK_USE_PLATFORM_XCB_KHR \
+                         VK_USE_PLATFORM_WAYLAND_KHR \
+                         VK_USE_PLATFORM_XLIB_XRANDR_EXT \
+                         XR_EXT_debug_utils \
+                         XR_USE_GRAPHICS_API_OPENGL \
+                         XR_USE_GRAPHICS_API_VULKAN \
+                         XR_USE_PLATFORM_XLIB \
+                         XR_USE_TIMESPEC \
+                         XRT_DOXYGEN
+
+ALIASES                += TODO=todo
+ALIASES                += ep{1}="<b>\1</b>. \xrefitem entrypoints \"OpenXR Entry Point\" \"OpenXR Entry Points\" \1"
+ALIASES                += obj{1}="\xrefitem objects \"OpenXR Object\" \"OpenXR Objects\" \1"
+
+SHOW_GROUPED_MEMB_INC  = YES
+STRIP_CODE_COMMENTS    = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+ALWAYS_DETAILED_SEC    = YES
+
+
+WARN_IF_UNDOCUMENTED   = @DOXYGEN_WARN_UNDOCUMENTED@
+EXTRACT_ALL            = @DOXYGEN_EXTRACT_ALL@
+
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+#PROJECT_NAME           = "My Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+#OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+#ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+#STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    = src/xrt/auxiliary \
+                         src/xrt/compositor \
+                         src/xrt/drivers \
+                         src/xrt/include \
+                         src/xrt/state_trackers \
+                         src/xrt/targets
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is yogur file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+#ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+#SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+#FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+#QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+# WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+#INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS          = *.c \
+                         *.cc \
+                         *.cxx \
+                         *.cpp \
+                         *.c++ \
+                         *.java \
+                         *.ii \
+                         *.ixx \
+                         *.ipp \
+                         *.i++ \
+                         *.inl \
+                         *.idl \
+                         *.ddl \
+                         *.odl \
+                         *.h \
+                         *.hh \
+                         *.hxx \
+                         *.hpp \
+                         *.h++ \
+                         *.cs \
+                         *.d \
+                         *.php \
+                         *.php4 \
+                         *.php5 \
+                         *.phtml \
+                         *.inc \
+                         *.m \
+                         *.markdown \
+                         *.md \
+                         *.mm \
+                         *.dox \
+                         *.py \
+                         *.pyw \
+                         *.f90 \
+                         *.f95 \
+                         *.f03 \
+                         *.f08 \
+                         *.f \
+                         *.for \
+                         *.tcl \
+                         *.vhd \
+                         *.vhdl \
+                         *.ucf \
+                         *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+# RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+# EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+# USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+#STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+#REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+#REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE        = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+#PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/doc/roadmap.md b/doc/roadmap.md
new file mode 100644
index 000000000..009b451de
--- /dev/null
+++ b/doc/roadmap.md
@@ -0,0 +1,35 @@
+# Roadmap
+
+## Short term
+
+ * **aux/util**: Add mutex and threading wrappers.
+ * **aux/math**: Add kalman filter math black box.
+ * **aux/log**: Add a common logging framework that can be used to pipe messages
+                up into **st/oxr** from things like drivers and the compositor.
+ * **aux/log**: Make it possible to batch up longer messages into a single call,
+                useful for printing the entire mode list in a single go.
+ * **cmake**: Make a proper FindXCB.cmake file.
+ * **comp**: Do timing based of the display refresh-rate and display time.
+ * **comp**: Extend to support rotated views/displays. Should we just rotate the
+             display for the 3Glasses or make it a per-view thing?
+ * **comp**: See-through support for Vive headset.
+ * **st/oxr**: Locking, maybe we just have a single lock for the session.
+               We will need to figure out how to do wait properly.
+ * **st/oxr**: Make wait frame actually wait for the display time.
+ * **st/oxr**: Improve space functions.
+ * **st/oxr**: Add path functions.
+ * **st/oxr**: Add just enough of the action functions to not return errors.
+
+## Long term
+
+ * **aux/beacon**: Complete and integrate Lighthouse tracking code.
+ * **comp**: Moving the compositor into it's own process.
+ * **comp**: Support quads layers.
+ * **comp**: Support other extensions layers.
+ * **doc**: Group Related code.
+ * **doc**: Lots of documentation for runtime.
+ * **drivers**: Port rest of OpenHMD drivers to our runtime.
+ * **st/oxr**: Complete action functions.
+ * **progs**: Settings and management daemon.
+ * **progs**: Systray status indicator for user to interact with daemon.
+ * **progs**: Room-scale setup program.
diff --git a/scripts/format-project.sh b/scripts/format-project.sh
new file mode 100755
index 000000000..878197a15
--- /dev/null
+++ b/scripts/format-project.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright 2018-2019, Collabora, Ltd.
+# Copyright 2016, Sensics, Inc.
+# SPDX-License-Identifier: Apache-2.0
+
+if [ ! "$CLANG_FORMAT" ]; then
+        for exe in clang-format-8 clang-format-7 clang-format-6.0 clang-format; do
+                if which $exe >/dev/null 2>&1; then
+                        CLANG_FORMAT=$exe
+                        break
+                fi
+        done
+fi
+if [ ! "$CLANG_FORMAT" ]; then
+        echo "Can't find clang-format - please set CLANG_FORMAT to a command or path" >&2
+        exit 1
+fi
+
+runClangFormatOnDir() {
+    find "$1" \( -name "*.c" -o -name "*.cpp" -o -name "*.h" \)| \
+        grep -v "\.boilerplate" | \
+        xargs ${CLANG_FORMAT} -style=file -i
+}
+
+(
+cd $(dirname $0)/../src/xrt
+runClangFormatOnDir .
+)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 000000000..7524309df
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,4 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+add_subdirectory(xrt)
diff --git a/src/external/glad/gl.c b/src/external/glad/gl.c
new file mode 100644
index 000000000..bb8437b4b
--- /dev/null
+++ b/src/external/glad/gl.c
@@ -0,0 +1,1654 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glad/gl.h>
+
+#ifndef GLAD_IMPL_UTIL_C_
+#define GLAD_IMPL_UTIL_C_
+
+#ifdef _MSC_VER
+#define GLAD_IMPL_UTIL_SSCANF sscanf_s
+#else
+#define GLAD_IMPL_UTIL_SSCANF sscanf
+#endif
+
+#endif /* GLAD_IMPL_UTIL_C_ */
+
+
+int GLAD_GL_VERSION_1_0 = 0;
+int GLAD_GL_VERSION_1_1 = 0;
+int GLAD_GL_VERSION_1_2 = 0;
+int GLAD_GL_VERSION_1_3 = 0;
+int GLAD_GL_VERSION_1_4 = 0;
+int GLAD_GL_VERSION_1_5 = 0;
+int GLAD_GL_VERSION_2_0 = 0;
+int GLAD_GL_VERSION_2_1 = 0;
+int GLAD_GL_VERSION_3_0 = 0;
+int GLAD_GL_VERSION_3_1 = 0;
+int GLAD_GL_VERSION_3_2 = 0;
+int GLAD_GL_VERSION_3_3 = 0;
+int GLAD_GL_VERSION_4_0 = 0;
+int GLAD_GL_VERSION_4_1 = 0;
+int GLAD_GL_VERSION_4_2 = 0;
+int GLAD_GL_VERSION_4_3 = 0;
+int GLAD_GL_VERSION_4_4 = 0;
+int GLAD_GL_VERSION_4_5 = 0;
+int GLAD_GL_EXT_memory_object = 0;
+int GLAD_GL_EXT_memory_object_fd = 0;
+
+
+
+PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
+PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;
+PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
+PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL;
+PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL;
+PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL;
+PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL;
+PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL;
+PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
+PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL;
+PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL;
+PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL;
+PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL;
+PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL;
+PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL;
+PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL;
+PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
+PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL;
+PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
+PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL;
+PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL;
+PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL;
+PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
+PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL;
+PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL;
+PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
+PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;
+PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
+PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL;
+PFNGLBLENDCOLORPROC glad_glBlendColor = NULL;
+PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL;
+PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL;
+PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;
+PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;
+PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;
+PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL;
+PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;
+PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;
+PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL;
+PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL;
+PFNGLBUFFERDATAPROC glad_glBufferData = NULL;
+PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
+PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT = NULL;
+PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL;
+PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL;
+PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL;
+PFNGLCLAMPCOLORPROC glad_glClampColor = NULL;
+PFNGLCLEARPROC glad_glClear = NULL;
+PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL;
+PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL;
+PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL;
+PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL;
+PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL;
+PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL;
+PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
+PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL;
+PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
+PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL;
+PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL;
+PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL;
+PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL;
+PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL;
+PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL;
+PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL;
+PFNGLCLIPCONTROLPROC glad_glClipControl = NULL;
+PFNGLCOLORMASKPROC glad_glColorMask = NULL;
+PFNGLCOLORMASKIPROC glad_glColorMaski = NULL;
+PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
+PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL;
+PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL;
+PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL;
+PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL;
+PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
+PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL;
+PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL;
+PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL;
+PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL;
+PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL;
+PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL;
+PFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL;
+PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL;
+PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT = NULL;
+PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
+PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL;
+PFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL;
+PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL;
+PFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL;
+PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
+PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
+PFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL;
+PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL;
+PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL;
+PFNGLCULLFACEPROC glad_glCullFace = NULL;
+PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
+PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
+PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
+PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
+PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL;
+PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT = NULL;
+PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
+PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
+PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL;
+PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL;
+PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL;
+PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
+PFNGLDELETESYNCPROC glad_glDeleteSync = NULL;
+PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
+PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
+PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
+PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL;
+PFNGLDEPTHMASKPROC glad_glDepthMask = NULL;
+PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL;
+PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL;
+PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL;
+PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
+PFNGLDETACHSHADERPROC glad_glDetachShader = NULL;
+PFNGLDISABLEPROC glad_glDisable = NULL;
+PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;
+PFNGLDISABLEIPROC glad_glDisablei = NULL;
+PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
+PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
+PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
+PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
+PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL;
+PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL;
+PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL;
+PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL;
+PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;
+PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL;
+PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
+PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL;
+PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL;
+PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL;
+PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL;
+PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL;
+PFNGLENABLEPROC glad_glEnable = NULL;
+PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
+PFNGLENABLEIPROC glad_glEnablei = NULL;
+PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL;
+PFNGLENDQUERYPROC glad_glEndQuery = NULL;
+PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL;
+PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL;
+PFNGLFENCESYNCPROC glad_glFenceSync = NULL;
+PFNGLFINISHPROC glad_glFinish = NULL;
+PFNGLFLUSHPROC glad_glFlush = NULL;
+PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL;
+PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL;
+PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
+PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL;
+PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL;
+PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL;
+PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL;
+PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL;
+PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL;
+PFNGLFRONTFACEPROC glad_glFrontFace = NULL;
+PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
+PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL;
+PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
+PFNGLGENQUERIESPROC glad_glGenQueries = NULL;
+PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL;
+PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL;
+PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
+PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
+PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
+PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL;
+PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL;
+PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL;
+PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL;
+PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL;
+PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL;
+PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL;
+PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL;
+PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL;
+PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL;
+PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL;
+PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL;
+PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL;
+PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL;
+PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL;
+PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL;
+PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL;
+PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL;
+PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL;
+PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
+PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL;
+PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL;
+PFNGLGETERRORPROC glad_glGetError = NULL;
+PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL;
+PFNGLGETFLOATVPROC glad_glGetFloatv = NULL;
+PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL;
+PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL;
+PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL;
+PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
+PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus = NULL;
+PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL;
+PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL;
+PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL;
+PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
+PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL;
+PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
+PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT = NULL;
+PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL;
+PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL;
+PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL;
+PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL;
+PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL;
+PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL;
+PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL;
+PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
+PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
+PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL;
+PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL;
+PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;
+PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
+PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
+PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
+PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
+PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
+PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL;
+PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
+PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
+PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL;
+PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
+PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL;
+PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL;
+PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL;
+PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL;
+PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL;
+PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL;
+PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL;
+PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL;
+PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL;
+PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL;
+PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL;
+PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;
+PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
+PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL;
+PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
+PFNGLGETSTRINGPROC glad_glGetString = NULL;
+PFNGLGETSTRINGIPROC glad_glGetStringi = NULL;
+PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL;
+PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL;
+PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL;
+PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL;
+PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL;
+PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL;
+PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL;
+PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL;
+PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL;
+PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL;
+PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL;
+PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL;
+PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL;
+PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL;
+PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL;
+PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL;
+PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL;
+PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL;
+PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL;
+PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL;
+PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL;
+PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL;
+PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL;
+PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
+PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL;
+PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL;
+PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL;
+PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL;
+PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL;
+PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT = NULL;
+PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT = NULL;
+PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL;
+PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL;
+PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL;
+PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL;
+PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL;
+PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL;
+PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL;
+PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL;
+PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL;
+PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL;
+PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage = NULL;
+PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage = NULL;
+PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv = NULL;
+PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL;
+PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL;
+PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL;
+PFNGLHINTPROC glad_glHint = NULL;
+PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT = NULL;
+PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL;
+PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL;
+PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL;
+PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL;
+PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
+PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL;
+PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL;
+PFNGLISBUFFERPROC glad_glIsBuffer = NULL;
+PFNGLISENABLEDPROC glad_glIsEnabled = NULL;
+PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL;
+PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL;
+PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT = NULL;
+PFNGLISPROGRAMPROC glad_glIsProgram = NULL;
+PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
+PFNGLISQUERYPROC glad_glIsQuery = NULL;
+PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL;
+PFNGLISSAMPLERPROC glad_glIsSampler = NULL;
+PFNGLISSHADERPROC glad_glIsShader = NULL;
+PFNGLISSYNCPROC glad_glIsSync = NULL;
+PFNGLISTEXTUREPROC glad_glIsTexture = NULL;
+PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
+PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL;
+PFNGLLINEWIDTHPROC glad_glLineWidth = NULL;
+PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
+PFNGLLOGICOPPROC glad_glLogicOp = NULL;
+PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL;
+PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL;
+PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL;
+PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL;
+PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
+PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;
+PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT = NULL;
+PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;
+PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL;
+PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL;
+PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL;
+PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL;
+PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL;
+PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL;
+PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL;
+PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT = NULL;
+PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL;
+PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL;
+PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL;
+PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL;
+PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL;
+PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
+PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
+PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL;
+PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
+PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
+PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL;
+PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL;
+PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL;
+PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL;
+PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL;
+PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL;
+PFNGLPOINTSIZEPROC glad_glPointSize = NULL;
+PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL;
+PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL;
+PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
+PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL;
+PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL;
+PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL;
+PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL;
+PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL;
+PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
+PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
+PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
+PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
+PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
+PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
+PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL;
+PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL;
+PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
+PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
+PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
+PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
+PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
+PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
+PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL;
+PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL;
+PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
+PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
+PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
+PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
+PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
+PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
+PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL;
+PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL;
+PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
+PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
+PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
+PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
+PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
+PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
+PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL;
+PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
+PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL;
+PFNGLREADBUFFERPROC glad_glReadBuffer = NULL;
+PFNGLREADPIXELSPROC glad_glReadPixels = NULL;
+PFNGLREADNPIXELSPROC glad_glReadnPixels = NULL;
+PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
+PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL;
+PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL;
+PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
+PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL;
+PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL;
+PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL;
+PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL;
+PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL;
+PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL;
+PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL;
+PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL;
+PFNGLSCISSORPROC glad_glScissor = NULL;
+PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL;
+PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL;
+PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL;
+PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
+PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
+PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL;
+PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL;
+PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL;
+PFNGLSTENCILMASKPROC glad_glStencilMask = NULL;
+PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL;
+PFNGLSTENCILOPPROC glad_glStencilOp = NULL;
+PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL;
+PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL;
+PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
+PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL;
+PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
+PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL;
+PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL;
+PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL;
+PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL;
+PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL;
+PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL;
+PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL;
+PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
+PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL;
+PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL;
+PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
+PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
+PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
+PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
+PFNGLTEXSTORAGEMEM1DEXTPROC glad_glTexStorageMem1DEXT = NULL;
+PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT = NULL;
+PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT = NULL;
+PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT = NULL;
+PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT = NULL;
+PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL;
+PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL;
+PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL;
+PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL;
+PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL;
+PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL;
+PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL;
+PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL;
+PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL;
+PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL;
+PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL;
+PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL;
+PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL;
+PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL;
+PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL;
+PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL;
+PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL;
+PFNGLTEXTURESTORAGEMEM1DEXTPROC glad_glTextureStorageMem1DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT = NULL;
+PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT = NULL;
+PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT = NULL;
+PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL;
+PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL;
+PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL;
+PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL;
+PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL;
+PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL;
+PFNGLUNIFORM1DPROC glad_glUniform1d = NULL;
+PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL;
+PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
+PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL;
+PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
+PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL;
+PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL;
+PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL;
+PFNGLUNIFORM2DPROC glad_glUniform2d = NULL;
+PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL;
+PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
+PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL;
+PFNGLUNIFORM2IPROC glad_glUniform2i = NULL;
+PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL;
+PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL;
+PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL;
+PFNGLUNIFORM3DPROC glad_glUniform3d = NULL;
+PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL;
+PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
+PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL;
+PFNGLUNIFORM3IPROC glad_glUniform3i = NULL;
+PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL;
+PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL;
+PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL;
+PFNGLUNIFORM4DPROC glad_glUniform4d = NULL;
+PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL;
+PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
+PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL;
+PFNGLUNIFORM4IPROC glad_glUniform4i = NULL;
+PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL;
+PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL;
+PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL;
+PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL;
+PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL;
+PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL;
+PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL;
+PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL;
+PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL;
+PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL;
+PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL;
+PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL;
+PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL;
+PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL;
+PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL;
+PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL;
+PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;
+PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL;
+PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL;
+PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL;
+PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL;
+PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL;
+PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL;
+PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL;
+PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
+PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
+PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL;
+PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
+PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL;
+PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL;
+PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL;
+PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL;
+PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL;
+PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL;
+PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = NULL;
+PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL;
+PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL;
+PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL;
+PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL;
+PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL;
+PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL;
+PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL;
+PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL;
+PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL;
+PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL;
+PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL;
+PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL;
+PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL;
+PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL;
+PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL;
+PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL;
+PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL;
+PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL;
+PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL;
+PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL;
+PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL;
+PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL;
+PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL;
+PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL;
+PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL;
+PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL;
+PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL;
+PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL;
+PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL;
+PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL;
+PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL;
+PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL;
+PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL;
+PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL;
+PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL;
+PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL;
+PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
+PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL;
+PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
+PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL;
+PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL;
+PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL;
+PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL;
+PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL;
+PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL;
+PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL;
+PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL;
+PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL;
+PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL;
+PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL;
+PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL;
+PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL;
+PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL;
+PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL;
+PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL;
+PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL;
+PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL;
+PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL;
+PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL;
+PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
+PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL;
+PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL;
+PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL;
+PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL;
+PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL;
+PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL;
+PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL;
+PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL;
+PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL;
+PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL;
+PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL;
+PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL;
+PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL;
+PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL;
+PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL;
+PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL;
+PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL;
+PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL;
+PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL;
+PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
+PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
+PFNGLVIEWPORTPROC glad_glViewport = NULL;
+PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL;
+PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL;
+PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL;
+PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
+
+
+static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_0) return;
+    glBlendFunc = (PFNGLBLENDFUNCPROC) load("glBlendFunc", userptr);
+    glClear = (PFNGLCLEARPROC) load("glClear", userptr);
+    glClearColor = (PFNGLCLEARCOLORPROC) load("glClearColor", userptr);
+    glClearDepth = (PFNGLCLEARDEPTHPROC) load("glClearDepth", userptr);
+    glClearStencil = (PFNGLCLEARSTENCILPROC) load("glClearStencil", userptr);
+    glColorMask = (PFNGLCOLORMASKPROC) load("glColorMask", userptr);
+    glCullFace = (PFNGLCULLFACEPROC) load("glCullFace", userptr);
+    glDepthFunc = (PFNGLDEPTHFUNCPROC) load("glDepthFunc", userptr);
+    glDepthMask = (PFNGLDEPTHMASKPROC) load("glDepthMask", userptr);
+    glDepthRange = (PFNGLDEPTHRANGEPROC) load("glDepthRange", userptr);
+    glDisable = (PFNGLDISABLEPROC) load("glDisable", userptr);
+    glDrawBuffer = (PFNGLDRAWBUFFERPROC) load("glDrawBuffer", userptr);
+    glEnable = (PFNGLENABLEPROC) load("glEnable", userptr);
+    glFinish = (PFNGLFINISHPROC) load("glFinish", userptr);
+    glFlush = (PFNGLFLUSHPROC) load("glFlush", userptr);
+    glFrontFace = (PFNGLFRONTFACEPROC) load("glFrontFace", userptr);
+    glGetBooleanv = (PFNGLGETBOOLEANVPROC) load("glGetBooleanv", userptr);
+    glGetDoublev = (PFNGLGETDOUBLEVPROC) load("glGetDoublev", userptr);
+    glGetError = (PFNGLGETERRORPROC) load("glGetError", userptr);
+    glGetFloatv = (PFNGLGETFLOATVPROC) load("glGetFloatv", userptr);
+    glGetIntegerv = (PFNGLGETINTEGERVPROC) load("glGetIntegerv", userptr);
+    glGetString = (PFNGLGETSTRINGPROC) load("glGetString", userptr);
+    glGetTexImage = (PFNGLGETTEXIMAGEPROC) load("glGetTexImage", userptr);
+    glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load("glGetTexLevelParameterfv", userptr);
+    glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load("glGetTexLevelParameteriv", userptr);
+    glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load("glGetTexParameterfv", userptr);
+    glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load("glGetTexParameteriv", userptr);
+    glHint = (PFNGLHINTPROC) load("glHint", userptr);
+    glIsEnabled = (PFNGLISENABLEDPROC) load("glIsEnabled", userptr);
+    glLineWidth = (PFNGLLINEWIDTHPROC) load("glLineWidth", userptr);
+    glLogicOp = (PFNGLLOGICOPPROC) load("glLogicOp", userptr);
+    glPixelStoref = (PFNGLPIXELSTOREFPROC) load("glPixelStoref", userptr);
+    glPixelStorei = (PFNGLPIXELSTOREIPROC) load("glPixelStorei", userptr);
+    glPointSize = (PFNGLPOINTSIZEPROC) load("glPointSize", userptr);
+    glPolygonMode = (PFNGLPOLYGONMODEPROC) load("glPolygonMode", userptr);
+    glReadBuffer = (PFNGLREADBUFFERPROC) load("glReadBuffer", userptr);
+    glReadPixels = (PFNGLREADPIXELSPROC) load("glReadPixels", userptr);
+    glScissor = (PFNGLSCISSORPROC) load("glScissor", userptr);
+    glStencilFunc = (PFNGLSTENCILFUNCPROC) load("glStencilFunc", userptr);
+    glStencilMask = (PFNGLSTENCILMASKPROC) load("glStencilMask", userptr);
+    glStencilOp = (PFNGLSTENCILOPPROC) load("glStencilOp", userptr);
+    glTexImage1D = (PFNGLTEXIMAGE1DPROC) load("glTexImage1D", userptr);
+    glTexImage2D = (PFNGLTEXIMAGE2DPROC) load("glTexImage2D", userptr);
+    glTexParameterf = (PFNGLTEXPARAMETERFPROC) load("glTexParameterf", userptr);
+    glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load("glTexParameterfv", userptr);
+    glTexParameteri = (PFNGLTEXPARAMETERIPROC) load("glTexParameteri", userptr);
+    glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load("glTexParameteriv", userptr);
+    glViewport = (PFNGLVIEWPORTPROC) load("glViewport", userptr);
+}
+static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_1) return;
+    glBindTexture = (PFNGLBINDTEXTUREPROC) load("glBindTexture", userptr);
+    glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load("glCopyTexImage1D", userptr);
+    glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load("glCopyTexImage2D", userptr);
+    glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load("glCopyTexSubImage1D", userptr);
+    glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load("glCopyTexSubImage2D", userptr);
+    glDeleteTextures = (PFNGLDELETETEXTURESPROC) load("glDeleteTextures", userptr);
+    glDrawArrays = (PFNGLDRAWARRAYSPROC) load("glDrawArrays", userptr);
+    glDrawElements = (PFNGLDRAWELEMENTSPROC) load("glDrawElements", userptr);
+    glGenTextures = (PFNGLGENTEXTURESPROC) load("glGenTextures", userptr);
+    glGetPointerv = (PFNGLGETPOINTERVPROC) load("glGetPointerv", userptr);
+    glIsTexture = (PFNGLISTEXTUREPROC) load("glIsTexture", userptr);
+    glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load("glPolygonOffset", userptr);
+    glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load("glTexSubImage1D", userptr);
+    glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load("glTexSubImage2D", userptr);
+}
+static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_2) return;
+    glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load("glCopyTexSubImage3D", userptr);
+    glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load("glDrawRangeElements", userptr);
+    glTexImage3D = (PFNGLTEXIMAGE3DPROC) load("glTexImage3D", userptr);
+    glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load("glTexSubImage3D", userptr);
+}
+static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_3) return;
+    glActiveTexture = (PFNGLACTIVETEXTUREPROC) load("glActiveTexture", userptr);
+    glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load("glCompressedTexImage1D", userptr);
+    glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load("glCompressedTexImage2D", userptr);
+    glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load("glCompressedTexImage3D", userptr);
+    glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load("glCompressedTexSubImage1D", userptr);
+    glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load("glCompressedTexSubImage2D", userptr);
+    glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load("glCompressedTexSubImage3D", userptr);
+    glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load("glGetCompressedTexImage", userptr);
+    glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load("glSampleCoverage", userptr);
+}
+static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_4) return;
+    glBlendColor = (PFNGLBLENDCOLORPROC) load("glBlendColor", userptr);
+    glBlendEquation = (PFNGLBLENDEQUATIONPROC) load("glBlendEquation", userptr);
+    glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load("glBlendFuncSeparate", userptr);
+    glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load("glMultiDrawArrays", userptr);
+    glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load("glMultiDrawElements", userptr);
+    glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load("glPointParameterf", userptr);
+    glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load("glPointParameterfv", userptr);
+    glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load("glPointParameteri", userptr);
+    glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load("glPointParameteriv", userptr);
+}
+static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_1_5) return;
+    glBeginQuery = (PFNGLBEGINQUERYPROC) load("glBeginQuery", userptr);
+    glBindBuffer = (PFNGLBINDBUFFERPROC) load("glBindBuffer", userptr);
+    glBufferData = (PFNGLBUFFERDATAPROC) load("glBufferData", userptr);
+    glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load("glBufferSubData", userptr);
+    glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load("glDeleteBuffers", userptr);
+    glDeleteQueries = (PFNGLDELETEQUERIESPROC) load("glDeleteQueries", userptr);
+    glEndQuery = (PFNGLENDQUERYPROC) load("glEndQuery", userptr);
+    glGenBuffers = (PFNGLGENBUFFERSPROC) load("glGenBuffers", userptr);
+    glGenQueries = (PFNGLGENQUERIESPROC) load("glGenQueries", userptr);
+    glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load("glGetBufferParameteriv", userptr);
+    glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load("glGetBufferPointerv", userptr);
+    glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load("glGetBufferSubData", userptr);
+    glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load("glGetQueryObjectiv", userptr);
+    glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load("glGetQueryObjectuiv", userptr);
+    glGetQueryiv = (PFNGLGETQUERYIVPROC) load("glGetQueryiv", userptr);
+    glIsBuffer = (PFNGLISBUFFERPROC) load("glIsBuffer", userptr);
+    glIsQuery = (PFNGLISQUERYPROC) load("glIsQuery", userptr);
+    glMapBuffer = (PFNGLMAPBUFFERPROC) load("glMapBuffer", userptr);
+    glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load("glUnmapBuffer", userptr);
+}
+static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_2_0) return;
+    glAttachShader = (PFNGLATTACHSHADERPROC) load("glAttachShader", userptr);
+    glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load("glBindAttribLocation", userptr);
+    glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load("glBlendEquationSeparate", userptr);
+    glCompileShader = (PFNGLCOMPILESHADERPROC) load("glCompileShader", userptr);
+    glCreateProgram = (PFNGLCREATEPROGRAMPROC) load("glCreateProgram", userptr);
+    glCreateShader = (PFNGLCREATESHADERPROC) load("glCreateShader", userptr);
+    glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load("glDeleteProgram", userptr);
+    glDeleteShader = (PFNGLDELETESHADERPROC) load("glDeleteShader", userptr);
+    glDetachShader = (PFNGLDETACHSHADERPROC) load("glDetachShader", userptr);
+    glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load("glDisableVertexAttribArray", userptr);
+    glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load("glDrawBuffers", userptr);
+    glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load("glEnableVertexAttribArray", userptr);
+    glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load("glGetActiveAttrib", userptr);
+    glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load("glGetActiveUniform", userptr);
+    glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load("glGetAttachedShaders", userptr);
+    glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load("glGetAttribLocation", userptr);
+    glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load("glGetProgramInfoLog", userptr);
+    glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load("glGetProgramiv", userptr);
+    glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load("glGetShaderInfoLog", userptr);
+    glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load("glGetShaderSource", userptr);
+    glGetShaderiv = (PFNGLGETSHADERIVPROC) load("glGetShaderiv", userptr);
+    glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load("glGetUniformLocation", userptr);
+    glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load("glGetUniformfv", userptr);
+    glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load("glGetUniformiv", userptr);
+    glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load("glGetVertexAttribPointerv", userptr);
+    glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load("glGetVertexAttribdv", userptr);
+    glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load("glGetVertexAttribfv", userptr);
+    glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load("glGetVertexAttribiv", userptr);
+    glIsProgram = (PFNGLISPROGRAMPROC) load("glIsProgram", userptr);
+    glIsShader = (PFNGLISSHADERPROC) load("glIsShader", userptr);
+    glLinkProgram = (PFNGLLINKPROGRAMPROC) load("glLinkProgram", userptr);
+    glShaderSource = (PFNGLSHADERSOURCEPROC) load("glShaderSource", userptr);
+    glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load("glStencilFuncSeparate", userptr);
+    glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load("glStencilMaskSeparate", userptr);
+    glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load("glStencilOpSeparate", userptr);
+    glUniform1f = (PFNGLUNIFORM1FPROC) load("glUniform1f", userptr);
+    glUniform1fv = (PFNGLUNIFORM1FVPROC) load("glUniform1fv", userptr);
+    glUniform1i = (PFNGLUNIFORM1IPROC) load("glUniform1i", userptr);
+    glUniform1iv = (PFNGLUNIFORM1IVPROC) load("glUniform1iv", userptr);
+    glUniform2f = (PFNGLUNIFORM2FPROC) load("glUniform2f", userptr);
+    glUniform2fv = (PFNGLUNIFORM2FVPROC) load("glUniform2fv", userptr);
+    glUniform2i = (PFNGLUNIFORM2IPROC) load("glUniform2i", userptr);
+    glUniform2iv = (PFNGLUNIFORM2IVPROC) load("glUniform2iv", userptr);
+    glUniform3f = (PFNGLUNIFORM3FPROC) load("glUniform3f", userptr);
+    glUniform3fv = (PFNGLUNIFORM3FVPROC) load("glUniform3fv", userptr);
+    glUniform3i = (PFNGLUNIFORM3IPROC) load("glUniform3i", userptr);
+    glUniform3iv = (PFNGLUNIFORM3IVPROC) load("glUniform3iv", userptr);
+    glUniform4f = (PFNGLUNIFORM4FPROC) load("glUniform4f", userptr);
+    glUniform4fv = (PFNGLUNIFORM4FVPROC) load("glUniform4fv", userptr);
+    glUniform4i = (PFNGLUNIFORM4IPROC) load("glUniform4i", userptr);
+    glUniform4iv = (PFNGLUNIFORM4IVPROC) load("glUniform4iv", userptr);
+    glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load("glUniformMatrix2fv", userptr);
+    glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load("glUniformMatrix3fv", userptr);
+    glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load("glUniformMatrix4fv", userptr);
+    glUseProgram = (PFNGLUSEPROGRAMPROC) load("glUseProgram", userptr);
+    glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load("glValidateProgram", userptr);
+    glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load("glVertexAttrib1d", userptr);
+    glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load("glVertexAttrib1dv", userptr);
+    glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load("glVertexAttrib1f", userptr);
+    glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load("glVertexAttrib1fv", userptr);
+    glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load("glVertexAttrib1s", userptr);
+    glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load("glVertexAttrib1sv", userptr);
+    glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load("glVertexAttrib2d", userptr);
+    glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load("glVertexAttrib2dv", userptr);
+    glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load("glVertexAttrib2f", userptr);
+    glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load("glVertexAttrib2fv", userptr);
+    glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load("glVertexAttrib2s", userptr);
+    glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load("glVertexAttrib2sv", userptr);
+    glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load("glVertexAttrib3d", userptr);
+    glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load("glVertexAttrib3dv", userptr);
+    glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load("glVertexAttrib3f", userptr);
+    glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load("glVertexAttrib3fv", userptr);
+    glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load("glVertexAttrib3s", userptr);
+    glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load("glVertexAttrib3sv", userptr);
+    glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load("glVertexAttrib4Nbv", userptr);
+    glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load("glVertexAttrib4Niv", userptr);
+    glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load("glVertexAttrib4Nsv", userptr);
+    glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load("glVertexAttrib4Nub", userptr);
+    glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load("glVertexAttrib4Nubv", userptr);
+    glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load("glVertexAttrib4Nuiv", userptr);
+    glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load("glVertexAttrib4Nusv", userptr);
+    glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load("glVertexAttrib4bv", userptr);
+    glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load("glVertexAttrib4d", userptr);
+    glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load("glVertexAttrib4dv", userptr);
+    glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load("glVertexAttrib4f", userptr);
+    glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load("glVertexAttrib4fv", userptr);
+    glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load("glVertexAttrib4iv", userptr);
+    glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load("glVertexAttrib4s", userptr);
+    glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load("glVertexAttrib4sv", userptr);
+    glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load("glVertexAttrib4ubv", userptr);
+    glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load("glVertexAttrib4uiv", userptr);
+    glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load("glVertexAttrib4usv", userptr);
+    glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load("glVertexAttribPointer", userptr);
+}
+static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_2_1) return;
+    glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load("glUniformMatrix2x3fv", userptr);
+    glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load("glUniformMatrix2x4fv", userptr);
+    glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load("glUniformMatrix3x2fv", userptr);
+    glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load("glUniformMatrix3x4fv", userptr);
+    glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load("glUniformMatrix4x2fv", userptr);
+    glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load("glUniformMatrix4x3fv", userptr);
+}
+static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_0) return;
+    glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load("glBeginConditionalRender", userptr);
+    glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load("glBeginTransformFeedback", userptr);
+    glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load("glBindBufferBase", userptr);
+    glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load("glBindBufferRange", userptr);
+    glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load("glBindFragDataLocation", userptr);
+    glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load("glBindFramebuffer", userptr);
+    glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load("glBindRenderbuffer", userptr);
+    glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load("glBindVertexArray", userptr);
+    glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load("glBlitFramebuffer", userptr);
+    glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load("glCheckFramebufferStatus", userptr);
+    glClampColor = (PFNGLCLAMPCOLORPROC) load("glClampColor", userptr);
+    glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load("glClearBufferfi", userptr);
+    glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load("glClearBufferfv", userptr);
+    glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load("glClearBufferiv", userptr);
+    glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load("glClearBufferuiv", userptr);
+    glColorMaski = (PFNGLCOLORMASKIPROC) load("glColorMaski", userptr);
+    glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load("glDeleteFramebuffers", userptr);
+    glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load("glDeleteRenderbuffers", userptr);
+    glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load("glDeleteVertexArrays", userptr);
+    glDisablei = (PFNGLDISABLEIPROC) load("glDisablei", userptr);
+    glEnablei = (PFNGLENABLEIPROC) load("glEnablei", userptr);
+    glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load("glEndConditionalRender", userptr);
+    glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load("glEndTransformFeedback", userptr);
+    glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load("glFlushMappedBufferRange", userptr);
+    glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load("glFramebufferRenderbuffer", userptr);
+    glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load("glFramebufferTexture1D", userptr);
+    glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load("glFramebufferTexture2D", userptr);
+    glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load("glFramebufferTexture3D", userptr);
+    glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load("glFramebufferTextureLayer", userptr);
+    glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load("glGenFramebuffers", userptr);
+    glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load("glGenRenderbuffers", userptr);
+    glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load("glGenVertexArrays", userptr);
+    glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load("glGenerateMipmap", userptr);
+    glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load("glGetBooleani_v", userptr);
+    glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load("glGetFragDataLocation", userptr);
+    glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load("glGetFramebufferAttachmentParameteriv", userptr);
+    glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load("glGetIntegeri_v", userptr);
+    glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load("glGetRenderbufferParameteriv", userptr);
+    glGetStringi = (PFNGLGETSTRINGIPROC) load("glGetStringi", userptr);
+    glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load("glGetTexParameterIiv", userptr);
+    glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load("glGetTexParameterIuiv", userptr);
+    glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load("glGetTransformFeedbackVarying", userptr);
+    glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load("glGetUniformuiv", userptr);
+    glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load("glGetVertexAttribIiv", userptr);
+    glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load("glGetVertexAttribIuiv", userptr);
+    glIsEnabledi = (PFNGLISENABLEDIPROC) load("glIsEnabledi", userptr);
+    glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load("glIsFramebuffer", userptr);
+    glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load("glIsRenderbuffer", userptr);
+    glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load("glIsVertexArray", userptr);
+    glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load("glMapBufferRange", userptr);
+    glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load("glRenderbufferStorage", userptr);
+    glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load("glRenderbufferStorageMultisample", userptr);
+    glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load("glTexParameterIiv", userptr);
+    glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load("glTexParameterIuiv", userptr);
+    glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load("glTransformFeedbackVaryings", userptr);
+    glUniform1ui = (PFNGLUNIFORM1UIPROC) load("glUniform1ui", userptr);
+    glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load("glUniform1uiv", userptr);
+    glUniform2ui = (PFNGLUNIFORM2UIPROC) load("glUniform2ui", userptr);
+    glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load("glUniform2uiv", userptr);
+    glUniform3ui = (PFNGLUNIFORM3UIPROC) load("glUniform3ui", userptr);
+    glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load("glUniform3uiv", userptr);
+    glUniform4ui = (PFNGLUNIFORM4UIPROC) load("glUniform4ui", userptr);
+    glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load("glUniform4uiv", userptr);
+    glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load("glVertexAttribI1i", userptr);
+    glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load("glVertexAttribI1iv", userptr);
+    glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load("glVertexAttribI1ui", userptr);
+    glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load("glVertexAttribI1uiv", userptr);
+    glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load("glVertexAttribI2i", userptr);
+    glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load("glVertexAttribI2iv", userptr);
+    glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load("glVertexAttribI2ui", userptr);
+    glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load("glVertexAttribI2uiv", userptr);
+    glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load("glVertexAttribI3i", userptr);
+    glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load("glVertexAttribI3iv", userptr);
+    glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load("glVertexAttribI3ui", userptr);
+    glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load("glVertexAttribI3uiv", userptr);
+    glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load("glVertexAttribI4bv", userptr);
+    glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load("glVertexAttribI4i", userptr);
+    glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load("glVertexAttribI4iv", userptr);
+    glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load("glVertexAttribI4sv", userptr);
+    glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load("glVertexAttribI4ubv", userptr);
+    glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load("glVertexAttribI4ui", userptr);
+    glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load("glVertexAttribI4uiv", userptr);
+    glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load("glVertexAttribI4usv", userptr);
+    glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load("glVertexAttribIPointer", userptr);
+}
+static void glad_gl_load_GL_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_1) return;
+    glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load("glBindBufferBase", userptr);
+    glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load("glBindBufferRange", userptr);
+    glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load("glCopyBufferSubData", userptr);
+    glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load("glDrawArraysInstanced", userptr);
+    glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load("glDrawElementsInstanced", userptr);
+    glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load("glGetActiveUniformBlockName", userptr);
+    glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load("glGetActiveUniformBlockiv", userptr);
+    glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC) load("glGetActiveUniformName", userptr);
+    glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load("glGetActiveUniformsiv", userptr);
+    glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load("glGetIntegeri_v", userptr);
+    glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load("glGetUniformBlockIndex", userptr);
+    glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load("glGetUniformIndices", userptr);
+    glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC) load("glPrimitiveRestartIndex", userptr);
+    glTexBuffer = (PFNGLTEXBUFFERPROC) load("glTexBuffer", userptr);
+    glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load("glUniformBlockBinding", userptr);
+}
+static void glad_gl_load_GL_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_2) return;
+    glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load("glClientWaitSync", userptr);
+    glDeleteSync = (PFNGLDELETESYNCPROC) load("glDeleteSync", userptr);
+    glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load("glDrawElementsBaseVertex", userptr);
+    glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load("glDrawElementsInstancedBaseVertex", userptr);
+    glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load("glDrawRangeElementsBaseVertex", userptr);
+    glFenceSync = (PFNGLFENCESYNCPROC) load("glFenceSync", userptr);
+    glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load("glFramebufferTexture", userptr);
+    glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load("glGetBufferParameteri64v", userptr);
+    glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load("glGetInteger64i_v", userptr);
+    glGetInteger64v = (PFNGLGETINTEGER64VPROC) load("glGetInteger64v", userptr);
+    glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load("glGetMultisamplefv", userptr);
+    glGetSynciv = (PFNGLGETSYNCIVPROC) load("glGetSynciv", userptr);
+    glIsSync = (PFNGLISSYNCPROC) load("glIsSync", userptr);
+    glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) load("glMultiDrawElementsBaseVertex", userptr);
+    glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC) load("glProvokingVertex", userptr);
+    glSampleMaski = (PFNGLSAMPLEMASKIPROC) load("glSampleMaski", userptr);
+    glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC) load("glTexImage2DMultisample", userptr);
+    glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC) load("glTexImage3DMultisample", userptr);
+    glWaitSync = (PFNGLWAITSYNCPROC) load("glWaitSync", userptr);
+}
+static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_3_3) return;
+    glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC) load("glBindFragDataLocationIndexed", userptr);
+    glBindSampler = (PFNGLBINDSAMPLERPROC) load("glBindSampler", userptr);
+    glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load("glDeleteSamplers", userptr);
+    glGenSamplers = (PFNGLGENSAMPLERSPROC) load("glGenSamplers", userptr);
+    glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC) load("glGetFragDataIndex", userptr);
+    glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) load("glGetQueryObjecti64v", userptr);
+    glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) load("glGetQueryObjectui64v", userptr);
+    glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load("glGetSamplerParameterIiv", userptr);
+    glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load("glGetSamplerParameterIuiv", userptr);
+    glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load("glGetSamplerParameterfv", userptr);
+    glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load("glGetSamplerParameteriv", userptr);
+    glIsSampler = (PFNGLISSAMPLERPROC) load("glIsSampler", userptr);
+    glQueryCounter = (PFNGLQUERYCOUNTERPROC) load("glQueryCounter", userptr);
+    glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load("glSamplerParameterIiv", userptr);
+    glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load("glSamplerParameterIuiv", userptr);
+    glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load("glSamplerParameterf", userptr);
+    glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load("glSamplerParameterfv", userptr);
+    glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load("glSamplerParameteri", userptr);
+    glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load("glSamplerParameteriv", userptr);
+    glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load("glVertexAttribDivisor", userptr);
+    glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC) load("glVertexAttribP1ui", userptr);
+    glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC) load("glVertexAttribP1uiv", userptr);
+    glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC) load("glVertexAttribP2ui", userptr);
+    glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC) load("glVertexAttribP2uiv", userptr);
+    glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC) load("glVertexAttribP3ui", userptr);
+    glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC) load("glVertexAttribP3uiv", userptr);
+    glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC) load("glVertexAttribP4ui", userptr);
+    glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC) load("glVertexAttribP4uiv", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_0( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_0) return;
+    glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC) load("glBeginQueryIndexed", userptr);
+    glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load("glBindTransformFeedback", userptr);
+    glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) load("glBlendEquationSeparatei", userptr);
+    glBlendEquationi = (PFNGLBLENDEQUATIONIPROC) load("glBlendEquationi", userptr);
+    glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) load("glBlendFuncSeparatei", userptr);
+    glBlendFunci = (PFNGLBLENDFUNCIPROC) load("glBlendFunci", userptr);
+    glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load("glDeleteTransformFeedbacks", userptr);
+    glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load("glDrawArraysIndirect", userptr);
+    glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load("glDrawElementsIndirect", userptr);
+    glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC) load("glDrawTransformFeedback", userptr);
+    glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC) load("glDrawTransformFeedbackStream", userptr);
+    glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC) load("glEndQueryIndexed", userptr);
+    glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load("glGenTransformFeedbacks", userptr);
+    glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC) load("glGetActiveSubroutineName", userptr);
+    glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC) load("glGetActiveSubroutineUniformName", userptr);
+    glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC) load("glGetActiveSubroutineUniformiv", userptr);
+    glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC) load("glGetProgramStageiv", userptr);
+    glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC) load("glGetQueryIndexediv", userptr);
+    glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC) load("glGetSubroutineIndex", userptr);
+    glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC) load("glGetSubroutineUniformLocation", userptr);
+    glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC) load("glGetUniformSubroutineuiv", userptr);
+    glGetUniformdv = (PFNGLGETUNIFORMDVPROC) load("glGetUniformdv", userptr);
+    glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load("glIsTransformFeedback", userptr);
+    glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) load("glMinSampleShading", userptr);
+    glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC) load("glPatchParameterfv", userptr);
+    glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load("glPatchParameteri", userptr);
+    glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load("glPauseTransformFeedback", userptr);
+    glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load("glResumeTransformFeedback", userptr);
+    glUniform1d = (PFNGLUNIFORM1DPROC) load("glUniform1d", userptr);
+    glUniform1dv = (PFNGLUNIFORM1DVPROC) load("glUniform1dv", userptr);
+    glUniform2d = (PFNGLUNIFORM2DPROC) load("glUniform2d", userptr);
+    glUniform2dv = (PFNGLUNIFORM2DVPROC) load("glUniform2dv", userptr);
+    glUniform3d = (PFNGLUNIFORM3DPROC) load("glUniform3d", userptr);
+    glUniform3dv = (PFNGLUNIFORM3DVPROC) load("glUniform3dv", userptr);
+    glUniform4d = (PFNGLUNIFORM4DPROC) load("glUniform4d", userptr);
+    glUniform4dv = (PFNGLUNIFORM4DVPROC) load("glUniform4dv", userptr);
+    glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC) load("glUniformMatrix2dv", userptr);
+    glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC) load("glUniformMatrix2x3dv", userptr);
+    glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC) load("glUniformMatrix2x4dv", userptr);
+    glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC) load("glUniformMatrix3dv", userptr);
+    glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC) load("glUniformMatrix3x2dv", userptr);
+    glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC) load("glUniformMatrix3x4dv", userptr);
+    glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC) load("glUniformMatrix4dv", userptr);
+    glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC) load("glUniformMatrix4x2dv", userptr);
+    glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC) load("glUniformMatrix4x3dv", userptr);
+    glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC) load("glUniformSubroutinesuiv", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_1( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_1) return;
+    glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) load("glActiveShaderProgram", userptr);
+    glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) load("glBindProgramPipeline", userptr);
+    glClearDepthf = (PFNGLCLEARDEPTHFPROC) load("glClearDepthf", userptr);
+    glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) load("glCreateShaderProgramv", userptr);
+    glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) load("glDeleteProgramPipelines", userptr);
+    glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC) load("glDepthRangeArrayv", userptr);
+    glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC) load("glDepthRangeIndexed", userptr);
+    glDepthRangef = (PFNGLDEPTHRANGEFPROC) load("glDepthRangef", userptr);
+    glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) load("glGenProgramPipelines", userptr);
+    glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC) load("glGetDoublei_v", userptr);
+    glGetFloati_v = (PFNGLGETFLOATI_VPROC) load("glGetFloati_v", userptr);
+    glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load("glGetProgramBinary", userptr);
+    glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) load("glGetProgramPipelineInfoLog", userptr);
+    glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) load("glGetProgramPipelineiv", userptr);
+    glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load("glGetShaderPrecisionFormat", userptr);
+    glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC) load("glGetVertexAttribLdv", userptr);
+    glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) load("glIsProgramPipeline", userptr);
+    glProgramBinary = (PFNGLPROGRAMBINARYPROC) load("glProgramBinary", userptr);
+    glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load("glProgramParameteri", userptr);
+    glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC) load("glProgramUniform1d", userptr);
+    glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC) load("glProgramUniform1dv", userptr);
+    glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) load("glProgramUniform1f", userptr);
+    glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) load("glProgramUniform1fv", userptr);
+    glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) load("glProgramUniform1i", userptr);
+    glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) load("glProgramUniform1iv", userptr);
+    glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) load("glProgramUniform1ui", userptr);
+    glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) load("glProgramUniform1uiv", userptr);
+    glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC) load("glProgramUniform2d", userptr);
+    glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC) load("glProgramUniform2dv", userptr);
+    glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) load("glProgramUniform2f", userptr);
+    glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) load("glProgramUniform2fv", userptr);
+    glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) load("glProgramUniform2i", userptr);
+    glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) load("glProgramUniform2iv", userptr);
+    glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) load("glProgramUniform2ui", userptr);
+    glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) load("glProgramUniform2uiv", userptr);
+    glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC) load("glProgramUniform3d", userptr);
+    glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC) load("glProgramUniform3dv", userptr);
+    glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) load("glProgramUniform3f", userptr);
+    glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) load("glProgramUniform3fv", userptr);
+    glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) load("glProgramUniform3i", userptr);
+    glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) load("glProgramUniform3iv", userptr);
+    glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) load("glProgramUniform3ui", userptr);
+    glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) load("glProgramUniform3uiv", userptr);
+    glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC) load("glProgramUniform4d", userptr);
+    glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC) load("glProgramUniform4dv", userptr);
+    glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) load("glProgramUniform4f", userptr);
+    glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) load("glProgramUniform4fv", userptr);
+    glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) load("glProgramUniform4i", userptr);
+    glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) load("glProgramUniform4iv", userptr);
+    glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) load("glProgramUniform4ui", userptr);
+    glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) load("glProgramUniform4uiv", userptr);
+    glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC) load("glProgramUniformMatrix2dv", userptr);
+    glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) load("glProgramUniformMatrix2fv", userptr);
+    glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC) load("glProgramUniformMatrix2x3dv", userptr);
+    glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) load("glProgramUniformMatrix2x3fv", userptr);
+    glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC) load("glProgramUniformMatrix2x4dv", userptr);
+    glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) load("glProgramUniformMatrix2x4fv", userptr);
+    glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC) load("glProgramUniformMatrix3dv", userptr);
+    glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) load("glProgramUniformMatrix3fv", userptr);
+    glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC) load("glProgramUniformMatrix3x2dv", userptr);
+    glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) load("glProgramUniformMatrix3x2fv", userptr);
+    glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC) load("glProgramUniformMatrix3x4dv", userptr);
+    glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) load("glProgramUniformMatrix3x4fv", userptr);
+    glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC) load("glProgramUniformMatrix4dv", userptr);
+    glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) load("glProgramUniformMatrix4fv", userptr);
+    glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC) load("glProgramUniformMatrix4x2dv", userptr);
+    glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) load("glProgramUniformMatrix4x2fv", userptr);
+    glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC) load("glProgramUniformMatrix4x3dv", userptr);
+    glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) load("glProgramUniformMatrix4x3fv", userptr);
+    glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load("glReleaseShaderCompiler", userptr);
+    glScissorArrayv = (PFNGLSCISSORARRAYVPROC) load("glScissorArrayv", userptr);
+    glScissorIndexed = (PFNGLSCISSORINDEXEDPROC) load("glScissorIndexed", userptr);
+    glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC) load("glScissorIndexedv", userptr);
+    glShaderBinary = (PFNGLSHADERBINARYPROC) load("glShaderBinary", userptr);
+    glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) load("glUseProgramStages", userptr);
+    glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) load("glValidateProgramPipeline", userptr);
+    glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC) load("glVertexAttribL1d", userptr);
+    glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC) load("glVertexAttribL1dv", userptr);
+    glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC) load("glVertexAttribL2d", userptr);
+    glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC) load("glVertexAttribL2dv", userptr);
+    glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC) load("glVertexAttribL3d", userptr);
+    glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC) load("glVertexAttribL3dv", userptr);
+    glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC) load("glVertexAttribL4d", userptr);
+    glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC) load("glVertexAttribL4dv", userptr);
+    glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC) load("glVertexAttribLPointer", userptr);
+    glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC) load("glViewportArrayv", userptr);
+    glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC) load("glViewportIndexedf", userptr);
+    glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC) load("glViewportIndexedfv", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_2( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_2) return;
+    glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC) load("glBindImageTexture", userptr);
+    glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) load("glDrawArraysInstancedBaseInstance", userptr);
+    glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) load("glDrawElementsInstancedBaseInstance", userptr);
+    glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) load("glDrawElementsInstancedBaseVertexBaseInstance", userptr);
+    glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC) load("glDrawTransformFeedbackInstanced", userptr);
+    glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC) load("glDrawTransformFeedbackStreamInstanced", userptr);
+    glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) load("glGetActiveAtomicCounterBufferiv", userptr);
+    glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) load("glGetInternalformativ", userptr);
+    glMemoryBarrier = (PFNGLMEMORYBARRIERPROC) load("glMemoryBarrier", userptr);
+    glTexStorage1D = (PFNGLTEXSTORAGE1DPROC) load("glTexStorage1D", userptr);
+    glTexStorage2D = (PFNGLTEXSTORAGE2DPROC) load("glTexStorage2D", userptr);
+    glTexStorage3D = (PFNGLTEXSTORAGE3DPROC) load("glTexStorage3D", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_3( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_3) return;
+    glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC) load("glBindVertexBuffer", userptr);
+    glClearBufferData = (PFNGLCLEARBUFFERDATAPROC) load("glClearBufferData", userptr);
+    glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC) load("glClearBufferSubData", userptr);
+    glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC) load("glCopyImageSubData", userptr);
+    glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load("glDebugMessageCallback", userptr);
+    glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load("glDebugMessageControl", userptr);
+    glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load("glDebugMessageInsert", userptr);
+    glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC) load("glDispatchCompute", userptr);
+    glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC) load("glDispatchComputeIndirect", userptr);
+    glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC) load("glFramebufferParameteri", userptr);
+    glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load("glGetDebugMessageLog", userptr);
+    glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) load("glGetFramebufferParameteriv", userptr);
+    glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC) load("glGetInternalformati64v", userptr);
+    glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load("glGetObjectLabel", userptr);
+    glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load("glGetObjectPtrLabel", userptr);
+    glGetPointerv = (PFNGLGETPOINTERVPROC) load("glGetPointerv", userptr);
+    glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC) load("glGetProgramInterfaceiv", userptr);
+    glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC) load("glGetProgramResourceIndex", userptr);
+    glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC) load("glGetProgramResourceLocation", userptr);
+    glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) load("glGetProgramResourceLocationIndex", userptr);
+    glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC) load("glGetProgramResourceName", userptr);
+    glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC) load("glGetProgramResourceiv", userptr);
+    glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC) load("glInvalidateBufferData", userptr);
+    glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC) load("glInvalidateBufferSubData", userptr);
+    glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC) load("glInvalidateFramebuffer", userptr);
+    glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC) load("glInvalidateSubFramebuffer", userptr);
+    glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC) load("glInvalidateTexImage", userptr);
+    glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC) load("glInvalidateTexSubImage", userptr);
+    glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC) load("glMultiDrawArraysIndirect", userptr);
+    glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC) load("glMultiDrawElementsIndirect", userptr);
+    glObjectLabel = (PFNGLOBJECTLABELPROC) load("glObjectLabel", userptr);
+    glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load("glObjectPtrLabel", userptr);
+    glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load("glPopDebugGroup", userptr);
+    glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load("glPushDebugGroup", userptr);
+    glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC) load("glShaderStorageBlockBinding", userptr);
+    glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC) load("glTexBufferRange", userptr);
+    glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC) load("glTexStorage2DMultisample", userptr);
+    glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC) load("glTexStorage3DMultisample", userptr);
+    glTextureView = (PFNGLTEXTUREVIEWPROC) load("glTextureView", userptr);
+    glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC) load("glVertexAttribBinding", userptr);
+    glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC) load("glVertexAttribFormat", userptr);
+    glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC) load("glVertexAttribIFormat", userptr);
+    glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC) load("glVertexAttribLFormat", userptr);
+    glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC) load("glVertexBindingDivisor", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_4( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_4) return;
+    glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC) load("glBindBuffersBase", userptr);
+    glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC) load("glBindBuffersRange", userptr);
+    glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC) load("glBindImageTextures", userptr);
+    glBindSamplers = (PFNGLBINDSAMPLERSPROC) load("glBindSamplers", userptr);
+    glBindTextures = (PFNGLBINDTEXTURESPROC) load("glBindTextures", userptr);
+    glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC) load("glBindVertexBuffers", userptr);
+    glBufferStorage = (PFNGLBUFFERSTORAGEPROC) load("glBufferStorage", userptr);
+    glClearTexImage = (PFNGLCLEARTEXIMAGEPROC) load("glClearTexImage", userptr);
+    glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC) load("glClearTexSubImage", userptr);
+}
+static void glad_gl_load_GL_VERSION_4_5( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_VERSION_4_5) return;
+    glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC) load("glBindTextureUnit", userptr);
+    glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC) load("glBlitNamedFramebuffer", userptr);
+    glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) load("glCheckNamedFramebufferStatus", userptr);
+    glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC) load("glClearNamedBufferData", userptr);
+    glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC) load("glClearNamedBufferSubData", userptr);
+    glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) load("glClearNamedFramebufferfi", userptr);
+    glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) load("glClearNamedFramebufferfv", userptr);
+    glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) load("glClearNamedFramebufferiv", userptr);
+    glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) load("glClearNamedFramebufferuiv", userptr);
+    glClipControl = (PFNGLCLIPCONTROLPROC) load("glClipControl", userptr);
+    glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC) load("glCompressedTextureSubImage1D", userptr);
+    glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC) load("glCompressedTextureSubImage2D", userptr);
+    glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC) load("glCompressedTextureSubImage3D", userptr);
+    glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC) load("glCopyNamedBufferSubData", userptr);
+    glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC) load("glCopyTextureSubImage1D", userptr);
+    glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC) load("glCopyTextureSubImage2D", userptr);
+    glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC) load("glCopyTextureSubImage3D", userptr);
+    glCreateBuffers = (PFNGLCREATEBUFFERSPROC) load("glCreateBuffers", userptr);
+    glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC) load("glCreateFramebuffers", userptr);
+    glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC) load("glCreateProgramPipelines", userptr);
+    glCreateQueries = (PFNGLCREATEQUERIESPROC) load("glCreateQueries", userptr);
+    glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC) load("glCreateRenderbuffers", userptr);
+    glCreateSamplers = (PFNGLCREATESAMPLERSPROC) load("glCreateSamplers", userptr);
+    glCreateTextures = (PFNGLCREATETEXTURESPROC) load("glCreateTextures", userptr);
+    glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC) load("glCreateTransformFeedbacks", userptr);
+    glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC) load("glCreateVertexArrays", userptr);
+    glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC) load("glDisableVertexArrayAttrib", userptr);
+    glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC) load("glEnableVertexArrayAttrib", userptr);
+    glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC) load("glFlushMappedNamedBufferRange", userptr);
+    glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC) load("glGenerateTextureMipmap", userptr);
+    glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC) load("glGetCompressedTextureImage", userptr);
+    glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC) load("glGetCompressedTextureSubImage", userptr);
+    glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC) load("glGetGraphicsResetStatus", userptr);
+    glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC) load("glGetNamedBufferParameteri64v", userptr);
+    glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC) load("glGetNamedBufferParameteriv", userptr);
+    glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC) load("glGetNamedBufferPointerv", userptr);
+    glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC) load("glGetNamedBufferSubData", userptr);
+    glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load("glGetNamedFramebufferAttachmentParameteriv", userptr);
+    glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) load("glGetNamedFramebufferParameteriv", userptr);
+    glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC) load("glGetNamedRenderbufferParameteriv", userptr);
+    glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC) load("glGetQueryBufferObjecti64v", userptr);
+    glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC) load("glGetQueryBufferObjectiv", userptr);
+    glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC) load("glGetQueryBufferObjectui64v", userptr);
+    glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC) load("glGetQueryBufferObjectuiv", userptr);
+    glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC) load("glGetTextureImage", userptr);
+    glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC) load("glGetTextureLevelParameterfv", userptr);
+    glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC) load("glGetTextureLevelParameteriv", userptr);
+    glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC) load("glGetTextureParameterIiv", userptr);
+    glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC) load("glGetTextureParameterIuiv", userptr);
+    glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC) load("glGetTextureParameterfv", userptr);
+    glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC) load("glGetTextureParameteriv", userptr);
+    glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC) load("glGetTextureSubImage", userptr);
+    glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC) load("glGetTransformFeedbacki64_v", userptr);
+    glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC) load("glGetTransformFeedbacki_v", userptr);
+    glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC) load("glGetTransformFeedbackiv", userptr);
+    glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC) load("glGetVertexArrayIndexed64iv", userptr);
+    glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC) load("glGetVertexArrayIndexediv", userptr);
+    glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC) load("glGetVertexArrayiv", userptr);
+    glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC) load("glGetnCompressedTexImage", userptr);
+    glGetnTexImage = (PFNGLGETNTEXIMAGEPROC) load("glGetnTexImage", userptr);
+    glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC) load("glGetnUniformdv", userptr);
+    glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC) load("glGetnUniformfv", userptr);
+    glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC) load("glGetnUniformiv", userptr);
+    glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC) load("glGetnUniformuiv", userptr);
+    glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC) load("glInvalidateNamedFramebufferData", userptr);
+    glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) load("glInvalidateNamedFramebufferSubData", userptr);
+    glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC) load("glMapNamedBuffer", userptr);
+    glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC) load("glMapNamedBufferRange", userptr);
+    glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC) load("glMemoryBarrierByRegion", userptr);
+    glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC) load("glNamedBufferData", userptr);
+    glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC) load("glNamedBufferStorage", userptr);
+    glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC) load("glNamedBufferSubData", userptr);
+    glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC) load("glNamedFramebufferDrawBuffer", userptr);
+    glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC) load("glNamedFramebufferDrawBuffers", userptr);
+    glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC) load("glNamedFramebufferParameteri", userptr);
+    glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC) load("glNamedFramebufferReadBuffer", userptr);
+    glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC) load("glNamedFramebufferRenderbuffer", userptr);
+    glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC) load("glNamedFramebufferTexture", userptr);
+    glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC) load("glNamedFramebufferTextureLayer", userptr);
+    glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC) load("glNamedRenderbufferStorage", userptr);
+    glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC) load("glNamedRenderbufferStorageMultisample", userptr);
+    glReadnPixels = (PFNGLREADNPIXELSPROC) load("glReadnPixels", userptr);
+    glTextureBarrier = (PFNGLTEXTUREBARRIERPROC) load("glTextureBarrier", userptr);
+    glTextureBuffer = (PFNGLTEXTUREBUFFERPROC) load("glTextureBuffer", userptr);
+    glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC) load("glTextureBufferRange", userptr);
+    glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC) load("glTextureParameterIiv", userptr);
+    glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC) load("glTextureParameterIuiv", userptr);
+    glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC) load("glTextureParameterf", userptr);
+    glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC) load("glTextureParameterfv", userptr);
+    glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC) load("glTextureParameteri", userptr);
+    glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC) load("glTextureParameteriv", userptr);
+    glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC) load("glTextureStorage1D", userptr);
+    glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC) load("glTextureStorage2D", userptr);
+    glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC) load("glTextureStorage2DMultisample", userptr);
+    glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC) load("glTextureStorage3D", userptr);
+    glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC) load("glTextureStorage3DMultisample", userptr);
+    glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC) load("glTextureSubImage1D", userptr);
+    glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC) load("glTextureSubImage2D", userptr);
+    glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC) load("glTextureSubImage3D", userptr);
+    glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC) load("glTransformFeedbackBufferBase", userptr);
+    glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC) load("glTransformFeedbackBufferRange", userptr);
+    glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC) load("glUnmapNamedBuffer", userptr);
+    glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC) load("glVertexArrayAttribBinding", userptr);
+    glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC) load("glVertexArrayAttribFormat", userptr);
+    glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC) load("glVertexArrayAttribIFormat", userptr);
+    glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC) load("glVertexArrayAttribLFormat", userptr);
+    glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC) load("glVertexArrayBindingDivisor", userptr);
+    glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC) load("glVertexArrayElementBuffer", userptr);
+    glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC) load("glVertexArrayVertexBuffer", userptr);
+    glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC) load("glVertexArrayVertexBuffers", userptr);
+}
+static void glad_gl_load_GL_EXT_memory_object( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_EXT_memory_object) return;
+    glBufferStorageMemEXT = (PFNGLBUFFERSTORAGEMEMEXTPROC) load("glBufferStorageMemEXT", userptr);
+    glCreateMemoryObjectsEXT = (PFNGLCREATEMEMORYOBJECTSEXTPROC) load("glCreateMemoryObjectsEXT", userptr);
+    glDeleteMemoryObjectsEXT = (PFNGLDELETEMEMORYOBJECTSEXTPROC) load("glDeleteMemoryObjectsEXT", userptr);
+    glGetMemoryObjectParameterivEXT = (PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC) load("glGetMemoryObjectParameterivEXT", userptr);
+    glGetUnsignedBytei_vEXT = (PFNGLGETUNSIGNEDBYTEI_VEXTPROC) load("glGetUnsignedBytei_vEXT", userptr);
+    glGetUnsignedBytevEXT = (PFNGLGETUNSIGNEDBYTEVEXTPROC) load("glGetUnsignedBytevEXT", userptr);
+    glIsMemoryObjectEXT = (PFNGLISMEMORYOBJECTEXTPROC) load("glIsMemoryObjectEXT", userptr);
+    glMemoryObjectParameterivEXT = (PFNGLMEMORYOBJECTPARAMETERIVEXTPROC) load("glMemoryObjectParameterivEXT", userptr);
+    glNamedBufferStorageMemEXT = (PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC) load("glNamedBufferStorageMemEXT", userptr);
+    glTexStorageMem1DEXT = (PFNGLTEXSTORAGEMEM1DEXTPROC) load("glTexStorageMem1DEXT", userptr);
+    glTexStorageMem2DEXT = (PFNGLTEXSTORAGEMEM2DEXTPROC) load("glTexStorageMem2DEXT", userptr);
+    glTexStorageMem2DMultisampleEXT = (PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC) load("glTexStorageMem2DMultisampleEXT", userptr);
+    glTexStorageMem3DEXT = (PFNGLTEXSTORAGEMEM3DEXTPROC) load("glTexStorageMem3DEXT", userptr);
+    glTexStorageMem3DMultisampleEXT = (PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC) load("glTexStorageMem3DMultisampleEXT", userptr);
+    glTextureStorageMem1DEXT = (PFNGLTEXTURESTORAGEMEM1DEXTPROC) load("glTextureStorageMem1DEXT", userptr);
+    glTextureStorageMem2DEXT = (PFNGLTEXTURESTORAGEMEM2DEXTPROC) load("glTextureStorageMem2DEXT", userptr);
+    glTextureStorageMem2DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC) load("glTextureStorageMem2DMultisampleEXT", userptr);
+    glTextureStorageMem3DEXT = (PFNGLTEXTURESTORAGEMEM3DEXTPROC) load("glTextureStorageMem3DEXT", userptr);
+    glTextureStorageMem3DMultisampleEXT = (PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC) load("glTextureStorageMem3DMultisampleEXT", userptr);
+}
+static void glad_gl_load_GL_EXT_memory_object_fd( GLADuserptrloadfunc load, void* userptr) {
+    if(!GLAD_GL_EXT_memory_object_fd) return;
+    glImportMemoryFdEXT = (PFNGLIMPORTMEMORYFDEXTPROC) load("glImportMemoryFdEXT", userptr);
+}
+
+
+
+#if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0)
+#define GLAD_GL_IS_SOME_NEW_VERSION 1
+#else
+#define GLAD_GL_IS_SOME_NEW_VERSION 0
+#endif
+
+static int glad_gl_get_extensions( int version, const char **out_exts, unsigned int *out_num_exts_i, char ***out_exts_i) {
+#if GLAD_GL_IS_SOME_NEW_VERSION
+    if(GLAD_VERSION_MAJOR(version) < 3) {
+#else
+    (void) version;
+    (void) out_num_exts_i;
+    (void) out_exts_i;
+#endif
+        if (glGetString == NULL) {
+            return 0;
+        }
+        *out_exts = (const char *)glGetString(GL_EXTENSIONS);
+#if GLAD_GL_IS_SOME_NEW_VERSION
+    } else {
+        unsigned int index = 0;
+        unsigned int num_exts_i = 0;
+        char **exts_i = NULL;
+        if (glGetStringi == NULL || glGetIntegerv == NULL) {
+            return 0;
+        }
+        glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i);
+        if (num_exts_i > 0) {
+            exts_i = (char **) malloc(num_exts_i * (sizeof *exts_i));
+        }
+        if (exts_i == NULL) {
+            return 0;
+        }
+        for(index = 0; index < num_exts_i; index++) {
+            const char *gl_str_tmp = (const char*) glGetStringi(GL_EXTENSIONS, index);
+            size_t len = strlen(gl_str_tmp) + 1;
+
+            char *local_str = (char*) malloc(len * sizeof(char));
+            if(local_str != NULL) {
+                memcpy(local_str, gl_str_tmp, len * sizeof(char));
+            }
+
+            exts_i[index] = local_str;
+        }
+
+        *out_num_exts_i = num_exts_i;
+        *out_exts_i = exts_i;
+    }
+#endif
+    return 1;
+}
+static void glad_gl_free_extensions(char **exts_i, unsigned int num_exts_i) {
+    if (exts_i != NULL) {
+        unsigned int index;
+        for(index = 0; index < num_exts_i; index++) {
+            free((void *) (exts_i[index]));
+        }
+        free((void *)exts_i);
+        exts_i = NULL;
+    }
+}
+static int glad_gl_has_extension(int version, const char *exts, unsigned int num_exts_i, char **exts_i, const char *ext) {
+    if(GLAD_VERSION_MAJOR(version) < 3 || !GLAD_GL_IS_SOME_NEW_VERSION) {
+        const char *extensions;
+        const char *loc;
+        const char *terminator;
+        extensions = exts;
+        if(extensions == NULL || ext == NULL) {
+            return 0;
+        }
+        while(1) {
+            loc = strstr(extensions, ext);
+            if(loc == NULL) {
+                return 0;
+            }
+            terminator = loc + strlen(ext);
+            if((loc == extensions || *(loc - 1) == ' ') &&
+                (*terminator == ' ' || *terminator == '\0')) {
+                return 1;
+            }
+            extensions = terminator;
+        }
+    } else {
+        unsigned int index;
+        for(index = 0; index < num_exts_i; index++) {
+            const char *e = exts_i[index];
+            if(strcmp(e, ext) == 0) {
+                return 1;
+            }
+        }
+    }
+    return 0;
+}
+
+static GLADapiproc glad_gl_get_proc_from_userptr(const char* name, void *userptr) {
+    return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
+}
+
+static int glad_gl_find_extensions_gl( int version) {
+    const char *exts = NULL;
+    unsigned int num_exts_i = 0;
+    char **exts_i = NULL;
+    if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;
+
+    GLAD_GL_EXT_memory_object = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object");
+    GLAD_GL_EXT_memory_object_fd = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_EXT_memory_object_fd");
+
+    glad_gl_free_extensions(exts_i, num_exts_i);
+
+    return 1;
+}
+
+static int glad_gl_find_core_gl(void) {
+    int i, major, minor;
+    const char* version;
+    const char* prefixes[] = {
+        "OpenGL ES-CM ",
+        "OpenGL ES-CL ",
+        "OpenGL ES ",
+        NULL
+    };
+    version = (const char*) glGetString(GL_VERSION);
+    if (!version) return 0;
+    for (i = 0;  prefixes[i];  i++) {
+        const size_t length = strlen(prefixes[i]);
+        if (strncmp(version, prefixes[i], length) == 0) {
+            version += length;
+            break;
+        }
+    }
+
+    GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
+
+    GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
+    GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
+    GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
+    GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
+    GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
+    GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
+    GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
+    GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2;
+    GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
+    GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
+    GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
+    GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3;
+    GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4;
+    GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4;
+    GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4;
+    GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4;
+    GLAD_GL_VERSION_4_4 = (major == 4 && minor >= 4) || major > 4;
+    GLAD_GL_VERSION_4_5 = (major == 4 && minor >= 5) || major > 4;
+
+    return GLAD_MAKE_VERSION(major, minor);
+}
+
+int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) {
+    int version;
+
+    glGetString = (PFNGLGETSTRINGPROC) load("glGetString", userptr);
+    if(glGetString == NULL) return 0;
+    if(glGetString(GL_VERSION) == NULL) return 0;
+    version = glad_gl_find_core_gl();
+
+    glad_gl_load_GL_VERSION_1_0(load, userptr);
+    glad_gl_load_GL_VERSION_1_1(load, userptr);
+    glad_gl_load_GL_VERSION_1_2(load, userptr);
+    glad_gl_load_GL_VERSION_1_3(load, userptr);
+    glad_gl_load_GL_VERSION_1_4(load, userptr);
+    glad_gl_load_GL_VERSION_1_5(load, userptr);
+    glad_gl_load_GL_VERSION_2_0(load, userptr);
+    glad_gl_load_GL_VERSION_2_1(load, userptr);
+    glad_gl_load_GL_VERSION_3_0(load, userptr);
+    glad_gl_load_GL_VERSION_3_1(load, userptr);
+    glad_gl_load_GL_VERSION_3_2(load, userptr);
+    glad_gl_load_GL_VERSION_3_3(load, userptr);
+    glad_gl_load_GL_VERSION_4_0(load, userptr);
+    glad_gl_load_GL_VERSION_4_1(load, userptr);
+    glad_gl_load_GL_VERSION_4_2(load, userptr);
+    glad_gl_load_GL_VERSION_4_3(load, userptr);
+    glad_gl_load_GL_VERSION_4_4(load, userptr);
+    glad_gl_load_GL_VERSION_4_5(load, userptr);
+
+    if (!glad_gl_find_extensions_gl(version)) return 0;
+    glad_gl_load_GL_EXT_memory_object(load, userptr);
+    glad_gl_load_GL_EXT_memory_object_fd(load, userptr);
+
+
+
+    return version;
+}
+
+
+int gladLoadGL( GLADloadfunc load) {
+    return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
+}
+
+
+
+
diff --git a/src/external/glad/gl.h b/src/external/glad/gl.h
new file mode 100644
index 000000000..01ad3848e
--- /dev/null
+++ b/src/external/glad/gl.h
@@ -0,0 +1,3692 @@
+/**
+ * Loader generated by glad 2.0.0-beta on Fri Feb 22 16:29:14 2019
+ *
+ * Generator: C/C++
+ * Specification: gl
+ * Extensions: 2
+ *
+ * APIs:
+ *  - gl:core=4.5
+ *
+ * Options:
+ *  - MX_GLOBAL = False
+ *  - LOADER = False
+ *  - ALIAS = False
+ *  - HEADER_ONLY = False
+ *  - DEBUG = False
+ *  - MX = False
+ *
+ * Commandline:
+ *    --api='gl:core=4.5' --extensions='GL_EXT_memory_object,GL_EXT_memory_object_fd' c
+ *
+ * Online:
+ *    http://glad.sh/#api=gl%3Acore%3D4.5&extensions=GL_EXT_memory_object%2CGL_EXT_memory_object_fd&generator=c&options=
+ *
+ */
+
+#ifndef GLAD_GL_H_
+#define GLAD_GL_H_
+
+#ifdef __gl_h_
+    #error OpenGL header already included (API: gl), remove previous include!
+#endif
+#define __gl_h_ 1
+
+
+#define GLAD_GL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GLAD_PLATFORM_H_
+#define GLAD_PLATFORM_H_
+
+#ifndef GLAD_PLATFORM_WIN32
+  #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
+    #define GLAD_PLATFORM_WIN32 1
+  #else
+    #define GLAD_PLATFORM_WIN32 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_APPLE
+  #ifdef __APPLE__
+    #define GLAD_PLATFORM_APPLE 1
+  #else
+    #define GLAD_PLATFORM_APPLE 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_EMSCRIPTEN
+  #ifdef __EMSCRIPTEN__
+    #define GLAD_PLATFORM_EMSCRIPTEN 1
+  #else
+    #define GLAD_PLATFORM_EMSCRIPTEN 0
+  #endif
+#endif
+
+#ifndef GLAD_PLATFORM_UWP
+  #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
+    #ifdef __has_include
+      #if __has_include(<winapifamily.h>)
+        #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+      #endif
+    #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
+      #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+    #endif
+  #endif
+
+  #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
+    #include <winapifamily.h>
+    #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+      #define GLAD_PLATFORM_UWP 1
+    #endif
+  #endif
+
+  #ifndef GLAD_PLATFORM_UWP
+    #define GLAD_PLATFORM_UWP 0
+  #endif
+#endif
+
+#ifdef __GNUC__
+  #define GLAD_GNUC_EXTENSION __extension__
+#else
+  #define GLAD_GNUC_EXTENSION
+#endif
+
+#ifndef GLAD_API_CALL
+  #if defined(GLAD_API_CALL_EXPORT)
+    #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
+      #if defined(GLAD_API_CALL_EXPORT_BUILD)
+        #if defined(__GNUC__)
+          #define GLAD_API_CALL __attribute__ ((dllexport)) extern
+        #else
+          #define GLAD_API_CALL __declspec(dllexport) extern
+        #endif
+      #else
+        #if defined(__GNUC__)
+          #define GLAD_API_CALL __attribute__ ((dllimport)) extern
+        #else
+          #define GLAD_API_CALL __declspec(dllimport) extern
+        #endif
+      #endif
+    #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
+      #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
+    #else
+      #define GLAD_API_CALL extern
+    #endif
+  #else
+    #define GLAD_API_CALL extern
+  #endif
+#endif
+
+#ifdef APIENTRY
+  #define GLAD_API_PTR APIENTRY
+#elif GLAD_PLATFORM_WIN32
+  #define GLAD_API_PTR __stdcall
+#else
+  #define GLAD_API_PTR
+#endif
+
+#ifndef GLAPI
+#define GLAPI GLAD_API_CALL
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY GLAD_API_PTR
+#endif
+
+
+#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
+#define GLAD_VERSION_MAJOR(version) (version / 10000)
+#define GLAD_VERSION_MINOR(version) (version % 10000)
+
+typedef void (*GLADapiproc)(void);
+
+typedef GLADapiproc (*GLADloadfunc)(const char *name);
+typedef GLADapiproc (*GLADuserptrloadfunc)(const char *name, void *userptr);
+
+typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
+typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
+
+#endif /* GLAD_PLATFORM_H_ */
+
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_ACTIVE_PROGRAM 0x8259
+#define GL_ACTIVE_RESOURCES 0x92F5
+#define GL_ACTIVE_SUBROUTINES 0x8DE5
+#define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48
+#define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47
+#define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49
+#define GL_ACTIVE_TEXTURE 0x84E0
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_VARIABLES 0x9305
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+#define GL_ALL_SHADER_BITS 0xFFFFFFFF
+#define GL_ALPHA 0x1906
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_ALWAYS 0x0207
+#define GL_AND 0x1501
+#define GL_AND_INVERTED 0x1504
+#define GL_AND_REVERSE 0x1502
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ARRAY_SIZE 0x92FB
+#define GL_ARRAY_STRIDE 0x92FE
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5
+#define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4
+#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9
+#define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_AUTO_GENERATE_MIPMAP 0x8295
+#define GL_BACK 0x0405
+#define GL_BACK_LEFT 0x0402
+#define GL_BACK_RIGHT 0x0403
+#define GL_BGR 0x80E0
+#define GL_BGRA 0x80E1
+#define GL_BGRA_INTEGER 0x8D9B
+#define GL_BGR_INTEGER 0x8D9A
+#define GL_BLEND 0x0BE2
+#define GL_BLEND_COLOR 0x8005
+#define GL_BLEND_DST 0x0BE0
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+#define GL_BLEND_EQUATION_RGB 0x8009
+#define GL_BLEND_SRC 0x0BE1
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLOCK_INDEX 0x92FD
+#define GL_BLUE 0x1905
+#define GL_BLUE_INTEGER 0x8D96
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_BUFFER 0x82E0
+#define GL_BUFFER_ACCESS 0x88BB
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_BINDING 0x9302
+#define GL_BUFFER_DATA_SIZE 0x9303
+#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_STORAGE_FLAGS 0x8220
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#define GL_BUFFER_USAGE 0x8765
+#define GL_BUFFER_VARIABLE 0x92E5
+#define GL_BYTE 0x1400
+#define GL_CAVEAT_SUPPORT 0x82B8
+#define GL_CCW 0x0901
+#define GL_CLAMP_READ_COLOR 0x891C
+#define GL_CLAMP_TO_BORDER 0x812D
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_CLEAR 0x1500
+#define GL_CLEAR_BUFFER 0x82B4
+#define GL_CLEAR_TEXTURE 0x9365
+#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
+#define GL_CLIENT_STORAGE_BIT 0x0200
+#define GL_CLIP_DEPTH_MODE 0x935D
+#define GL_CLIP_DISTANCE0 0x3000
+#define GL_CLIP_DISTANCE1 0x3001
+#define GL_CLIP_DISTANCE2 0x3002
+#define GL_CLIP_DISTANCE3 0x3003
+#define GL_CLIP_DISTANCE4 0x3004
+#define GL_CLIP_DISTANCE5 0x3005
+#define GL_CLIP_DISTANCE6 0x3006
+#define GL_CLIP_DISTANCE7 0x3007
+#define GL_CLIP_ORIGIN 0x935C
+#define GL_COLOR 0x1800
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_COLOR_ATTACHMENT16 0x8CF0
+#define GL_COLOR_ATTACHMENT17 0x8CF1
+#define GL_COLOR_ATTACHMENT18 0x8CF2
+#define GL_COLOR_ATTACHMENT19 0x8CF3
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT20 0x8CF4
+#define GL_COLOR_ATTACHMENT21 0x8CF5
+#define GL_COLOR_ATTACHMENT22 0x8CF6
+#define GL_COLOR_ATTACHMENT23 0x8CF7
+#define GL_COLOR_ATTACHMENT24 0x8CF8
+#define GL_COLOR_ATTACHMENT25 0x8CF9
+#define GL_COLOR_ATTACHMENT26 0x8CFA
+#define GL_COLOR_ATTACHMENT27 0x8CFB
+#define GL_COLOR_ATTACHMENT28 0x8CFC
+#define GL_COLOR_ATTACHMENT29 0x8CFD
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT30 0x8CFE
+#define GL_COLOR_ATTACHMENT31 0x8CFF
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_BUFFER_BIT 0x00004000
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_COMPONENTS 0x8283
+#define GL_COLOR_ENCODING 0x8296
+#define GL_COLOR_LOGIC_OP 0x0BF2
+#define GL_COLOR_RENDERABLE 0x8286
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_COMPATIBLE_SUBROUTINES 0x8E4B
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_COMPRESSED_R11_EAC 0x9270
+#define GL_COMPRESSED_RED 0x8225
+#define GL_COMPRESSED_RED_RGTC1 0x8DBB
+#define GL_COMPRESSED_RG 0x8226
+#define GL_COMPRESSED_RG11_EAC 0x9272
+#define GL_COMPRESSED_RGB 0x84ED
+#define GL_COMPRESSED_RGB8_ETC2 0x9274
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_RGBA 0x84EE
+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C
+#define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E
+#define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F
+#define GL_COMPRESSED_RG_RGTC2 0x8DBD
+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE
+#define GL_COMPRESSED_SRGB 0x8C48
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_COMPRESSED_SRGB8_ETC2 0x9275
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPRESSED_SRGB_ALPHA 0x8C49
+#define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+#define GL_COMPUTE_SHADER 0x91B9
+#define GL_COMPUTE_SHADER_BIT 0x00000020
+#define GL_COMPUTE_SUBROUTINE 0x92ED
+#define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3
+#define GL_COMPUTE_TEXTURE 0x82A0
+#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001
+#define GL_CONTEXT_FLAGS 0x821E
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
+#define GL_CONTEXT_LOST 0x0507
+#define GL_CONTEXT_PROFILE_MASK 0x9126
+#define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB
+#define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC
+#define GL_COPY 0x1503
+#define GL_COPY_INVERTED 0x150C
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_READ_BUFFER_BINDING 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
+#define GL_CULL_FACE 0x0B44
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_CURRENT_PROGRAM 0x8B8D
+#define GL_CURRENT_QUERY 0x8865
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+#define GL_CW 0x0900
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DECR 0x1E03
+#define GL_DECR_WRAP 0x8508
+#define GL_DEDICATED_MEMORY_OBJECT_EXT 0x9581
+#define GL_DELETE_STATUS 0x8B80
+#define GL_DEPTH 0x1801
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_DEPTH_CLAMP 0x864F
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_DEPTH_COMPONENT32 0x81A7
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH_COMPONENTS 0x8284
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_RENDERABLE 0x8287
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
+#define GL_DEPTH_TEST 0x0B71
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEVICE_UUID_EXT 0x9597
+#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
+#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
+#define GL_DITHER 0x0BD0
+#define GL_DONT_CARE 0x1100
+#define GL_DOUBLE 0x140A
+#define GL_DOUBLEBUFFER 0x0C32
+#define GL_DOUBLE_MAT2 0x8F46
+#define GL_DOUBLE_MAT2x3 0x8F49
+#define GL_DOUBLE_MAT2x4 0x8F4A
+#define GL_DOUBLE_MAT3 0x8F47
+#define GL_DOUBLE_MAT3x2 0x8F4B
+#define GL_DOUBLE_MAT3x4 0x8F4C
+#define GL_DOUBLE_MAT4 0x8F48
+#define GL_DOUBLE_MAT4x2 0x8F4D
+#define GL_DOUBLE_MAT4x3 0x8F4E
+#define GL_DOUBLE_VEC2 0x8FFC
+#define GL_DOUBLE_VEC3 0x8FFD
+#define GL_DOUBLE_VEC4 0x8FFE
+#define GL_DRAW_BUFFER 0x0C01
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
+#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
+#define GL_DRIVER_UUID_EXT 0x9598
+#define GL_DST_ALPHA 0x0304
+#define GL_DST_COLOR 0x0306
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_DYNAMIC_DRAW 0x88E8
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_STORAGE_BIT 0x0100
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_EQUAL 0x0202
+#define GL_EQUIV 0x1509
+#define GL_EXTENSIONS 0x1F03
+#define GL_FALSE 0
+#define GL_FASTEST 0x1101
+#define GL_FILL 0x1B02
+#define GL_FILTER 0x829A
+#define GL_FIRST_VERTEX_CONVENTION 0x8E4D
+#define GL_FIXED 0x140C
+#define GL_FIXED_ONLY 0x891D
+#define GL_FLOAT 0x1406
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_FRACTIONAL_EVEN 0x8E7C
+#define GL_FRACTIONAL_ODD 0x8E7B
+#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_FRAGMENT_SHADER_BIT 0x00000002
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_FRAGMENT_SUBROUTINE 0x92EC
+#define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2
+#define GL_FRAGMENT_TEXTURE 0x829F
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_FRAMEBUFFER_BLEND 0x828B
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
+#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
+#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
+#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
+#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
+#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
+#define GL_FRAMEBUFFER_RENDERABLE 0x8289
+#define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+#define GL_FRONT 0x0404
+#define GL_FRONT_AND_BACK 0x0408
+#define GL_FRONT_FACE 0x0B46
+#define GL_FRONT_LEFT 0x0400
+#define GL_FRONT_RIGHT 0x0401
+#define GL_FULL_SUPPORT 0x82B7
+#define GL_FUNC_ADD 0x8006
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_GEOMETRY_INPUT_TYPE 0x8917
+#define GL_GEOMETRY_OUTPUT_TYPE 0x8918
+#define GL_GEOMETRY_SHADER 0x8DD9
+#define GL_GEOMETRY_SHADER_BIT 0x00000004
+#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
+#define GL_GEOMETRY_SUBROUTINE 0x92EB
+#define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1
+#define GL_GEOMETRY_TEXTURE 0x829E
+#define GL_GEOMETRY_VERTICES_OUT 0x8916
+#define GL_GEQUAL 0x0206
+#define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291
+#define GL_GET_TEXTURE_IMAGE_TYPE 0x8292
+#define GL_GREATER 0x0204
+#define GL_GREEN 0x1904
+#define GL_GREEN_INTEGER 0x8D95
+#define GL_GUILTY_CONTEXT_RESET 0x8253
+#define GL_HALF_FLOAT 0x140B
+#define GL_HANDLE_TYPE_OPAQUE_FD_EXT 0x9586
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_HIGH_INT 0x8DF5
+#define GL_IMAGE_1D 0x904C
+#define GL_IMAGE_1D_ARRAY 0x9052
+#define GL_IMAGE_2D 0x904D
+#define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_2D_MULTISAMPLE 0x9055
+#define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+#define GL_IMAGE_2D_RECT 0x904F
+#define GL_IMAGE_3D 0x904E
+#define GL_IMAGE_BINDING_ACCESS 0x8F3E
+#define GL_IMAGE_BINDING_FORMAT 0x906E
+#define GL_IMAGE_BINDING_LAYER 0x8F3D
+#define GL_IMAGE_BINDING_LAYERED 0x8F3C
+#define GL_IMAGE_BINDING_LEVEL 0x8F3B
+#define GL_IMAGE_BINDING_NAME 0x8F3A
+#define GL_IMAGE_BUFFER 0x9051
+#define GL_IMAGE_CLASS_10_10_10_2 0x82C3
+#define GL_IMAGE_CLASS_11_11_10 0x82C2
+#define GL_IMAGE_CLASS_1_X_16 0x82BE
+#define GL_IMAGE_CLASS_1_X_32 0x82BB
+#define GL_IMAGE_CLASS_1_X_8 0x82C1
+#define GL_IMAGE_CLASS_2_X_16 0x82BD
+#define GL_IMAGE_CLASS_2_X_32 0x82BA
+#define GL_IMAGE_CLASS_2_X_8 0x82C0
+#define GL_IMAGE_CLASS_4_X_16 0x82BC
+#define GL_IMAGE_CLASS_4_X_32 0x82B9
+#define GL_IMAGE_CLASS_4_X_8 0x82BF
+#define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8
+#define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMAGE_PIXEL_FORMAT 0x82A9
+#define GL_IMAGE_PIXEL_TYPE 0x82AA
+#define GL_IMAGE_TEXEL_SIZE 0x82A7
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_INCR 0x1E02
+#define GL_INCR_WRAP 0x8507
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_INNOCENT_CONTEXT_RESET 0x8254
+#define GL_INT 0x1404
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274
+#define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B
+#define GL_INTERNALFORMAT_BLUE_SIZE 0x8273
+#define GL_INTERNALFORMAT_BLUE_TYPE 0x827A
+#define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275
+#define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C
+#define GL_INTERNALFORMAT_GREEN_SIZE 0x8272
+#define GL_INTERNALFORMAT_GREEN_TYPE 0x8279
+#define GL_INTERNALFORMAT_PREFERRED 0x8270
+#define GL_INTERNALFORMAT_RED_SIZE 0x8271
+#define GL_INTERNALFORMAT_RED_TYPE 0x8278
+#define GL_INTERNALFORMAT_SHARED_SIZE 0x8277
+#define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276
+#define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D
+#define GL_INTERNALFORMAT_SUPPORTED 0x826F
+#define GL_INT_2_10_10_10_REV 0x8D9F
+#define GL_INT_IMAGE_1D 0x9057
+#define GL_INT_IMAGE_1D_ARRAY 0x905D
+#define GL_INT_IMAGE_2D 0x9058
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+#define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+#define GL_INT_IMAGE_2D_RECT 0x905A
+#define GL_INT_IMAGE_3D 0x9059
+#define GL_INT_IMAGE_BUFFER 0x905C
+#define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#define GL_INT_SAMPLER_1D 0x8DC9
+#define GL_INT_SAMPLER_1D_ARRAY 0x8DCE
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C
+#define GL_INT_SAMPLER_2D_RECT 0x8DCD
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_BUFFER 0x8DD0
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+#define GL_INVALID_INDEX 0xFFFFFFFF
+#define GL_INVALID_OPERATION 0x0502
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVERT 0x150A
+#define GL_ISOLINES 0x8E7A
+#define GL_IS_PER_PATCH 0x92E7
+#define GL_IS_ROW_MAJOR 0x9300
+#define GL_KEEP 0x1E00
+#define GL_LAST_VERTEX_CONVENTION 0x8E4E
+#define GL_LAYER_PROVOKING_VERTEX 0x825E
+#define GL_LEFT 0x0406
+#define GL_LEQUAL 0x0203
+#define GL_LESS 0x0201
+#define GL_LINE 0x1B01
+#define GL_LINEAR 0x2601
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_LINEAR_TILING_EXT 0x9585
+#define GL_LINES 0x0001
+#define GL_LINES_ADJACENCY 0x000A
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_SMOOTH 0x0B20
+#define GL_LINE_SMOOTH_HINT 0x0C52
+#define GL_LINE_STRIP 0x0003
+#define GL_LINE_STRIP_ADJACENCY 0x000B
+#define GL_LINE_WIDTH 0x0B21
+#define GL_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_LINE_WIDTH_RANGE 0x0B22
+#define GL_LINK_STATUS 0x8B82
+#define GL_LOCATION 0x930E
+#define GL_LOCATION_COMPONENT 0x934A
+#define GL_LOCATION_INDEX 0x930F
+#define GL_LOGIC_OP_MODE 0x0BF0
+#define GL_LOSE_CONTEXT_ON_RESET 0x8252
+#define GL_LOWER_LEFT 0x8CA1
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_LOW_INT 0x8DF3
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MANUAL_GENERATE_MIPMAP 0x8294
+#define GL_MAP_COHERENT_BIT 0x0080
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_PERSISTENT_BIT 0x0040
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MATRIX_STRIDE 0x92FF
+#define GL_MAX 0x8008
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_CLIP_DISTANCES 0x0D32
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA
+#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
+#define GL_MAX_COMBINED_DIMENSIONS 0x8282
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
+#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
+#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
+#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
+#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
+#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
+#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
+#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
+#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
+#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
+#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
+#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
+#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
+#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+#define GL_MAX_CULL_DISTANCES 0x82F9
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_DEPTH 0x8280
+#define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENT_INDEX 0x8D6B
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
+#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
+#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
+#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
+#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
+#define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123
+#define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124
+#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0
+#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
+#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
+#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29
+#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1
+#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
+#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF
+#define GL_MAX_HEIGHT 0x827F
+#define GL_MAX_IMAGE_SAMPLES 0x906D
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#define GL_MAX_INTEGER_SAMPLES 0x9110
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_MAX_LAYERS 0x8281
+#define GL_MAX_NAME_LENGTH 0x92F6
+#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
+#define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8
+#define GL_MAX_PATCH_VERTICES 0x8E7D
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_MAX_SAMPLE_MASK_WORDS 0x8E59
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
+#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+#define GL_MAX_SUBROUTINES 0x8DE7
+#define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
+#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
+#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
+#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
+#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
+#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
+#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
+#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
+#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
+#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
+#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
+#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
+#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
+#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
+#define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_UNIFORM_LOCATIONS 0x826E
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_MAX_VARYING_FLOATS 0x8B4B
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
+#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
+#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
+#define GL_MAX_VERTEX_STREAMS 0x8E71
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VIEWPORTS 0x825B
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_MAX_WIDTH 0x827E
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_MIN 0x8007
+#define GL_MINOR_VERSION 0x821C
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
+#define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
+#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
+#define GL_MIPMAP 0x8293
+#define GL_MIRRORED_REPEAT 0x8370
+#define GL_MIRROR_CLAMP_TO_EDGE 0x8743
+#define GL_MULTISAMPLE 0x809D
+#define GL_NAME_LENGTH 0x92F9
+#define GL_NAND 0x150E
+#define GL_NEAREST 0x2600
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_NEGATIVE_ONE_TO_ONE 0x935E
+#define GL_NEVER 0x0200
+#define GL_NICEST 0x1102
+#define GL_NONE 0
+#define GL_NOOP 0x1505
+#define GL_NOR 0x1508
+#define GL_NOTEQUAL 0x0205
+#define GL_NO_ERROR 0
+#define GL_NO_RESET_NOTIFICATION 0x8261
+#define GL_NUM_ACTIVE_VARIABLES 0x9304
+#define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_NUM_DEVICE_UUIDS_EXT 0x9596
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#define GL_NUM_SAMPLE_COUNTS 0x9380
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9
+#define GL_NUM_TILING_TYPES_EXT 0x9582
+#define GL_OBJECT_TYPE 0x9112
+#define GL_OFFSET 0x92FC
+#define GL_ONE 1
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_ONE_MINUS_SRC1_ALPHA 0x88FB
+#define GL_ONE_MINUS_SRC1_COLOR 0x88FA
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_OPTIMAL_TILING_EXT 0x9584
+#define GL_OR 0x1507
+#define GL_OR_INVERTED 0x150D
+#define GL_OR_REVERSE 0x150B
+#define GL_OUT_OF_MEMORY 0x0505
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D
+#define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C
+#define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E
+#define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B
+#define GL_PACK_IMAGE_HEIGHT 0x806C
+#define GL_PACK_LSB_FIRST 0x0D01
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_IMAGES 0x806B
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SWAP_BYTES 0x0D00
+#define GL_PATCHES 0x000E
+#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73
+#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74
+#define GL_PATCH_VERTICES 0x8E72
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_POINT 0x1B00
+#define GL_POINTS 0x0000
+#define GL_POINT_FADE_THRESHOLD_SIZE 0x8128
+#define GL_POINT_SIZE 0x0B11
+#define GL_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_POINT_SIZE_RANGE 0x0B12
+#define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0
+#define GL_POLYGON_MODE 0x0B40
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_POLYGON_OFFSET_LINE 0x2A02
+#define GL_POLYGON_OFFSET_POINT 0x2A01
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+#define GL_POLYGON_SMOOTH 0x0B41
+#define GL_POLYGON_SMOOTH_HINT 0x0C53
+#define GL_PRIMITIVES_GENERATED 0x8C87
+#define GL_PRIMITIVE_RESTART 0x8F9D
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
+#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
+#define GL_PRIMITIVE_RESTART_INDEX 0x8F9E
+#define GL_PROGRAM 0x82E2
+#define GL_PROGRAM_BINARY_FORMATS 0x87FF
+#define GL_PROGRAM_BINARY_LENGTH 0x8741
+#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
+#define GL_PROGRAM_INPUT 0x92E3
+#define GL_PROGRAM_OUTPUT 0x92E4
+#define GL_PROGRAM_PIPELINE 0x82E4
+#define GL_PROGRAM_PIPELINE_BINDING 0x825A
+#define GL_PROGRAM_POINT_SIZE 0x8642
+#define GL_PROGRAM_SEPARABLE 0x8258
+#define GL_PROTECTED_MEMORY_OBJECT_EXT 0x959B
+#define GL_PROVOKING_VERTEX 0x8E4F
+#define GL_PROXY_TEXTURE_1D 0x8063
+#define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19
+#define GL_PROXY_TEXTURE_2D 0x8064
+#define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101
+#define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103
+#define GL_PROXY_TEXTURE_3D 0x8070
+#define GL_PROXY_TEXTURE_CUBE_MAP 0x851B
+#define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B
+#define GL_PROXY_TEXTURE_RECTANGLE 0x84F7
+#define GL_QUADS 0x0007
+#define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C
+#define GL_QUERY 0x82E3
+#define GL_QUERY_BUFFER 0x9192
+#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
+#define GL_QUERY_BUFFER_BINDING 0x9193
+#define GL_QUERY_BY_REGION_NO_WAIT 0x8E16
+#define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A
+#define GL_QUERY_BY_REGION_WAIT 0x8E15
+#define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19
+#define GL_QUERY_COUNTER_BITS 0x8864
+#define GL_QUERY_NO_WAIT 0x8E14
+#define GL_QUERY_NO_WAIT_INVERTED 0x8E18
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_QUERY_RESULT_NO_WAIT 0x9194
+#define GL_QUERY_TARGET 0x82EA
+#define GL_QUERY_WAIT 0x8E13
+#define GL_QUERY_WAIT_INVERTED 0x8E17
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_R16 0x822A
+#define GL_R16F 0x822D
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R16_SNORM 0x8F98
+#define GL_R32F 0x822E
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_R3_G3_B2 0x2A10
+#define GL_R8 0x8229
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R8_SNORM 0x8F94
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_READ_BUFFER 0x0C02
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_READ_ONLY 0x88B8
+#define GL_READ_PIXELS 0x828C
+#define GL_READ_PIXELS_FORMAT 0x828D
+#define GL_READ_PIXELS_TYPE 0x828E
+#define GL_READ_WRITE 0x88BA
+#define GL_RED 0x1903
+#define GL_RED_INTEGER 0x8D94
+#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
+#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
+#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
+#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
+#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
+#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
+#define GL_RENDERBUFFER 0x8D41
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERER 0x1F01
+#define GL_REPEAT 0x2901
+#define GL_REPLACE 0x1E01
+#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
+#define GL_RG 0x8227
+#define GL_RG16 0x822C
+#define GL_RG16F 0x822F
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG16_SNORM 0x8F99
+#define GL_RG32F 0x8230
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_RG8 0x822B
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB 0x1907
+#define GL_RGB10 0x8052
+#define GL_RGB10_A2 0x8059
+#define GL_RGB10_A2UI 0x906F
+#define GL_RGB12 0x8053
+#define GL_RGB16 0x8054
+#define GL_RGB16F 0x881B
+#define GL_RGB16I 0x8D89
+#define GL_RGB16UI 0x8D77
+#define GL_RGB16_SNORM 0x8F9A
+#define GL_RGB32F 0x8815
+#define GL_RGB32I 0x8D83
+#define GL_RGB32UI 0x8D71
+#define GL_RGB4 0x804F
+#define GL_RGB5 0x8050
+#define GL_RGB565 0x8D62
+#define GL_RGB5_A1 0x8057
+#define GL_RGB8 0x8051
+#define GL_RGB8I 0x8D8F
+#define GL_RGB8UI 0x8D7D
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGB9_E5 0x8C3D
+#define GL_RGBA 0x1908
+#define GL_RGBA12 0x805A
+#define GL_RGBA16 0x805B
+#define GL_RGBA16F 0x881A
+#define GL_RGBA16I 0x8D88
+#define GL_RGBA16UI 0x8D76
+#define GL_RGBA16_SNORM 0x8F9B
+#define GL_RGBA2 0x8055
+#define GL_RGBA32F 0x8814
+#define GL_RGBA32I 0x8D82
+#define GL_RGBA32UI 0x8D70
+#define GL_RGBA4 0x8056
+#define GL_RGBA8 0x8058
+#define GL_RGBA8I 0x8D8E
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RG_INTEGER 0x8228
+#define GL_RIGHT 0x0407
+#define GL_SAMPLER 0x82E6
+#define GL_SAMPLER_1D 0x8B5D
+#define GL_SAMPLER_1D_ARRAY 0x8DC0
+#define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3
+#define GL_SAMPLER_1D_SHADOW 0x8B61
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B
+#define GL_SAMPLER_2D_RECT 0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW 0x8B64
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_SAMPLER_BUFFER 0x8DC2
+#define GL_SAMPLER_CUBE 0x8B60
+#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLES_PASSED 0x8914
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE 0x809F
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLE_COVERAGE 0x80A0
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_MASK 0x8E51
+#define GL_SAMPLE_MASK_VALUE 0x8E52
+#define GL_SAMPLE_POSITION 0x8E50
+#define GL_SAMPLE_SHADING 0x8C36
+#define GL_SCISSOR_BOX 0x0C10
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_SET 0x150F
+#define GL_SHADER 0x82E1
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_SHADER_COMPILER 0x8DFA
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_SHADER_IMAGE_ATOMIC 0x82A6
+#define GL_SHADER_IMAGE_LOAD 0x82A4
+#define GL_SHADER_IMAGE_STORE 0x82A5
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+#define GL_SHADER_STORAGE_BLOCK 0x92E6
+#define GL_SHADER_STORAGE_BUFFER 0x90D2
+#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
+#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
+#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
+#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_SHORT 0x1402
+#define GL_SIGNALED 0x9119
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC
+#define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD
+#define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF
+#define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23
+#define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22
+#define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13
+#define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12
+#define GL_SRC1_ALPHA 0x8589
+#define GL_SRC1_COLOR 0x88F9
+#define GL_SRC_ALPHA 0x0302
+#define GL_SRC_ALPHA_SATURATE 0x0308
+#define GL_SRC_COLOR 0x0300
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_SRGB_ALPHA 0x8C42
+#define GL_SRGB_READ 0x8297
+#define GL_SRGB_WRITE 0x8298
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#define GL_STATIC_COPY 0x88E6
+#define GL_STATIC_DRAW 0x88E4
+#define GL_STATIC_READ 0x88E5
+#define GL_STENCIL 0x1802
+#define GL_STENCIL_ATTACHMENT 0x8D20
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_COMPONENTS 0x8285
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX1 0x8D46
+#define GL_STENCIL_INDEX16 0x8D49
+#define GL_STENCIL_INDEX4 0x8D47
+#define GL_STENCIL_INDEX8 0x8D48
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_RENDERABLE 0x8288
+#define GL_STENCIL_TEST 0x0B90
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STEREO 0x0C33
+#define GL_STREAM_COPY 0x88E2
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STREAM_READ 0x88E1
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_SYNC_STATUS 0x9114
+#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
+#define GL_TESS_CONTROL_SHADER 0x8E88
+#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
+#define GL_TESS_CONTROL_SUBROUTINE 0x92E9
+#define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF
+#define GL_TESS_CONTROL_TEXTURE 0x829C
+#define GL_TESS_EVALUATION_SHADER 0x8E87
+#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
+#define GL_TESS_EVALUATION_SUBROUTINE 0x92EA
+#define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0
+#define GL_TESS_EVALUATION_TEXTURE 0x829D
+#define GL_TESS_GEN_MODE 0x8E76
+#define GL_TESS_GEN_POINT_MODE 0x8E79
+#define GL_TESS_GEN_SPACING 0x8E77
+#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
+#define GL_TEXTURE 0x1702
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE_1D 0x0DE0
+#define GL_TEXTURE_1D_ARRAY 0x8C18
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#define GL_TEXTURE_3D 0x806F
+#define GL_TEXTURE_ALPHA_SIZE 0x805F
+#define GL_TEXTURE_ALPHA_TYPE 0x8C13
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_BINDING_1D 0x8068
+#define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104
+#define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_TEXTURE_BINDING_BUFFER 0x8C2C
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
+#define GL_TEXTURE_BINDING_RECTANGLE 0x84F6
+#define GL_TEXTURE_BLUE_SIZE 0x805E
+#define GL_TEXTURE_BLUE_TYPE 0x8C12
+#define GL_TEXTURE_BORDER_COLOR 0x1004
+#define GL_TEXTURE_BUFFER 0x8C2A
+#define GL_TEXTURE_BUFFER_BINDING 0x8C2A
+#define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D
+#define GL_TEXTURE_BUFFER_OFFSET 0x919D
+#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
+#define GL_TEXTURE_BUFFER_SIZE 0x919E
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPRESSED 0x86A1
+#define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2
+#define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3
+#define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1
+#define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0
+#define GL_TEXTURE_COMPRESSION_HINT 0x84EF
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
+#define GL_TEXTURE_DEPTH 0x8071
+#define GL_TEXTURE_DEPTH_SIZE 0x884A
+#define GL_TEXTURE_DEPTH_TYPE 0x8C16
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107
+#define GL_TEXTURE_GATHER 0x82A2
+#define GL_TEXTURE_GATHER_SHADOW 0x82A3
+#define GL_TEXTURE_GREEN_SIZE 0x805D
+#define GL_TEXTURE_GREEN_TYPE 0x8C11
+#define GL_TEXTURE_HEIGHT 0x1001
+#define GL_TEXTURE_IMAGE_FORMAT 0x828F
+#define GL_TEXTURE_IMAGE_TYPE 0x8290
+#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
+#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
+#define GL_TEXTURE_INTERNAL_FORMAT 0x1003
+#define GL_TEXTURE_LOD_BIAS 0x8501
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_RECTANGLE 0x84F5
+#define GL_TEXTURE_RED_SIZE 0x805C
+#define GL_TEXTURE_RED_TYPE 0x8C10
+#define GL_TEXTURE_SAMPLES 0x9106
+#define GL_TEXTURE_SHADOW 0x82A1
+#define GL_TEXTURE_SHARED_SIZE 0x8C3F
+#define GL_TEXTURE_STENCIL_SIZE 0x88F1
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#define GL_TEXTURE_TARGET 0x1006
+#define GL_TEXTURE_TILING_EXT 0x9580
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#define GL_TEXTURE_VIEW 0x82B5
+#define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD
+#define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB
+#define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE
+#define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC
+#define GL_TEXTURE_WIDTH 0x1000
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+#define GL_TILING_TYPES_EXT 0x9583
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF
+#define GL_TIMESTAMP 0x8E28
+#define GL_TIME_ELAPSED 0x88BF
+#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
+#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
+#define GL_TRANSFORM_FEEDBACK 0x8E22
+#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C
+#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLES_ADJACENCY 0x000C
+#define GL_TRIANGLE_FAN 0x0006
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_STRIP_ADJACENCY 0x000D
+#define GL_TRUE 1
+#define GL_TYPE 0x92FA
+#define GL_UNDEFINED_VERTEX 0x8260
+#define GL_UNIFORM 0x92E1
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#define GL_UNIFORM_BLOCK 0x92E2
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNKNOWN_CONTEXT_RESET 0x8255
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129
+#define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128
+#define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A
+#define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_UNPACK_LSB_FIRST 0x0CF1
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SWAP_BYTES 0x0CF0
+#define GL_UNSIGNALED 0x9118
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362
+#define GL_UNSIGNED_BYTE_3_3_2 0x8032
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_UNSIGNED_INT_10_10_10_2 0x8036
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_UNSIGNED_INT_8_8_8_8 0x8035
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
+#define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+#define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+#define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+#define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1
+#define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D
+#define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
+#define GL_UPPER_LEFT 0x8CA2
+#define GL_UUID_SIZE_EXT 16
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_VENDOR 0x1F00
+#define GL_VERSION 0x1F02
+#define GL_VERTEX_ARRAY 0x8074
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_BINDING 0x82D4
+#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
+#define GL_VERTEX_BINDING_BUFFER 0x8F4F
+#define GL_VERTEX_BINDING_DIVISOR 0x82D6
+#define GL_VERTEX_BINDING_OFFSET 0x82D7
+#define GL_VERTEX_BINDING_STRIDE 0x82D8
+#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_VERTEX_SHADER_BIT 0x00000001
+#define GL_VERTEX_SUBROUTINE 0x92E8
+#define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE
+#define GL_VERTEX_TEXTURE 0x829B
+#define GL_VIEWPORT 0x0BA2
+#define GL_VIEWPORT_BOUNDS_RANGE 0x825D
+#define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F
+#define GL_VIEWPORT_SUBPIXEL_BITS 0x825C
+#define GL_VIEW_CLASS_128_BITS 0x82C4
+#define GL_VIEW_CLASS_16_BITS 0x82CA
+#define GL_VIEW_CLASS_24_BITS 0x82C9
+#define GL_VIEW_CLASS_32_BITS 0x82C8
+#define GL_VIEW_CLASS_48_BITS 0x82C7
+#define GL_VIEW_CLASS_64_BITS 0x82C6
+#define GL_VIEW_CLASS_8_BITS 0x82CB
+#define GL_VIEW_CLASS_96_BITS 0x82C5
+#define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3
+#define GL_VIEW_CLASS_BPTC_UNORM 0x82D2
+#define GL_VIEW_CLASS_RGTC1_RED 0x82D0
+#define GL_VIEW_CLASS_RGTC2_RG 0x82D1
+#define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC
+#define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD
+#define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE
+#define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF
+#define GL_VIEW_COMPATIBILITY_CLASS 0x82B6
+#define GL_WAIT_FAILED 0x911D
+#define GL_WRITE_ONLY 0x88B9
+#define GL_XOR 0x1506
+#define GL_ZERO 0
+#define GL_ZERO_TO_ONE 0x935F
+
+
+#include <stddef.h>
+#include <KHR/khrplatform.h>
+#ifndef GLEXT_64_TYPES_DEFINED
+/* This code block is duplicated in glxext.h, so must be protected */
+#define GLEXT_64_TYPES_DEFINED
+/* Define int32_t, int64_t, and uint64_t types for UST/MSC */
+/* (as used in the GL_EXT_timer_query extension). */
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <inttypes.h>
+#elif defined(__sun__) || defined(__digital__)
+#include <inttypes.h>
+#if defined(__STDC__)
+#if defined(__arch64__) || defined(_LP64)
+typedef long int int64_t;
+typedef unsigned long int uint64_t;
+#else
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#endif /* __arch64__ */
+#endif /* __STDC__ */
+#elif defined( __VMS ) || defined(__sgi)
+#include <inttypes.h>
+#elif defined(__SCO__) || defined(__USLC__)
+#include <stdint.h>
+#elif defined(__UNIXOS2__) || defined(__SOL64__)
+typedef long int int32_t;
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#elif defined(_WIN32) && defined(__GNUC__)
+#include <stdint.h>
+#elif defined(_WIN32)
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#else
+/* Fallback if nothing above works */
+#include <inttypes.h>
+#endif
+#endif
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef void GLvoid;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLclampx;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef int GLsizei;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef void *GLeglClientBufferEXT;
+typedef void *GLeglImageOES;
+typedef char GLchar;
+typedef char GLcharARB;
+#ifdef __APPLE__
+typedef void *GLhandleARB;
+#else
+typedef unsigned int GLhandleARB;
+#endif
+typedef unsigned short GLhalfARB;
+typedef unsigned short GLhalf;
+typedef GLint GLfixed;
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_intptr_t GLintptr;
+#else
+typedef khronos_intptr_t GLintptr;
+#endif
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef khronos_ssize_t GLsizeiptr;
+#else
+typedef khronos_ssize_t GLsizeiptr;
+#endif
+typedef int64_t GLint64;
+typedef uint64_t GLuint64;
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef long GLintptrARB;
+#else
+typedef ptrdiff_t GLintptrARB;
+#endif
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060)
+typedef long GLsizeiptrARB;
+#else
+typedef ptrdiff_t GLsizeiptrARB;
+#endif
+typedef int64_t GLint64EXT;
+typedef uint64_t GLuint64EXT;
+typedef struct __GLsync *GLsync;
+struct _cl_context;
+struct _cl_event;
+typedef void ( *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void ( *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void ( *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+typedef void ( *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam);
+typedef unsigned short GLhalfNV;
+typedef GLintptr GLvdpauSurfaceNV;
+typedef void ( *GLVULKANPROCNV)(void);
+
+
+#define GL_VERSION_1_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_0;
+#define GL_VERSION_1_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_1;
+#define GL_VERSION_1_2 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_2;
+#define GL_VERSION_1_3 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_3;
+#define GL_VERSION_1_4 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_4;
+#define GL_VERSION_1_5 1
+GLAD_API_CALL int GLAD_GL_VERSION_1_5;
+#define GL_VERSION_2_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_2_0;
+#define GL_VERSION_2_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_2_1;
+#define GL_VERSION_3_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_0;
+#define GL_VERSION_3_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_1;
+#define GL_VERSION_3_2 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_2;
+#define GL_VERSION_3_3 1
+GLAD_API_CALL int GLAD_GL_VERSION_3_3;
+#define GL_VERSION_4_0 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_0;
+#define GL_VERSION_4_1 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_1;
+#define GL_VERSION_4_2 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_2;
+#define GL_VERSION_4_3 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_3;
+#define GL_VERSION_4_4 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_4;
+#define GL_VERSION_4_5 1
+GLAD_API_CALL int GLAD_GL_VERSION_4_5;
+#define GL_EXT_memory_object 1
+GLAD_API_CALL int GLAD_GL_EXT_memory_object;
+#define GL_EXT_memory_object_fd 1
+GLAD_API_CALL int GLAD_GL_EXT_memory_object_fd;
+
+
+typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint   pipeline, GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum   texture);
+typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint   program, GLuint   shader);
+typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint   id, GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum   target, GLuint   id);
+typedef void (GLAD_API_PTR *PFNGLBEGINQUERYINDEXEDPROC)(GLenum   target, GLuint   index, GLuint   id);
+typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum   primitiveMode);
+typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint   program, GLuint   index, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum   target, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum   target, GLuint   index, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum   target, GLuint   index, GLuint   buffer, GLintptr   offset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERSBASEPROC)(GLenum   target, GLuint   first, GLsizei   count, const  GLuint  * buffers);
+typedef void (GLAD_API_PTR *PFNGLBINDBUFFERSRANGEPROC)(GLenum   target, GLuint   first, GLsizei   count, const  GLuint  * buffers, const  GLintptr  * offsets, const  GLsizeiptr  * sizes);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint   program, GLuint   color, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint   program, GLuint   colorNumber, GLuint   index, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum   target, GLuint   framebuffer);
+typedef void (GLAD_API_PTR *PFNGLBINDIMAGETEXTUREPROC)(GLuint   unit, GLuint   texture, GLint   level, GLboolean   layered, GLint   layer, GLenum   access, GLenum   format);
+typedef void (GLAD_API_PTR *PFNGLBINDIMAGETEXTURESPROC)(GLuint   first, GLsizei   count, const  GLuint  * textures);
+typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEPROC)(GLuint   pipeline);
+typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum   target, GLuint   renderbuffer);
+typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERPROC)(GLuint   unit, GLuint   sampler);
+typedef void (GLAD_API_PTR *PFNGLBINDSAMPLERSPROC)(GLuint   first, GLsizei   count, const  GLuint  * samplers);
+typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum   target, GLuint   texture);
+typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREUNITPROC)(GLuint   unit, GLuint   texture);
+typedef void (GLAD_API_PTR *PFNGLBINDTEXTURESPROC)(GLuint   first, GLsizei   count, const  GLuint  * textures);
+typedef void (GLAD_API_PTR *PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum   target, GLuint   id);
+typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint   array);
+typedef void (GLAD_API_PTR *PFNGLBINDVERTEXBUFFERPROC)(GLuint   bindingindex, GLuint   buffer, GLintptr   offset, GLsizei   stride);
+typedef void (GLAD_API_PTR *PFNGLBINDVERTEXBUFFERSPROC)(GLuint   first, GLsizei   count, const  GLuint  * buffers, const  GLintptr  * offsets, const  GLsizei  * strides);
+typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat   red, GLfloat   green, GLfloat   blue, GLfloat   alpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum   modeRGB, GLenum   modeAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint   buf, GLenum   modeRGB, GLenum   modeAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIPROC)(GLuint   buf, GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum   sfactor, GLenum   dfactor);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum   sfactorRGB, GLenum   dfactorRGB, GLenum   sfactorAlpha, GLenum   dfactorAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIPROC)(GLuint   buf, GLenum   srcRGB, GLenum   dstRGB, GLenum   srcAlpha, GLenum   dstAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIPROC)(GLuint   buf, GLenum   src, GLenum   dst);
+typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint   srcX0, GLint   srcY0, GLint   srcX1, GLint   srcY1, GLint   dstX0, GLint   dstY0, GLint   dstX1, GLint   dstY1, GLbitfield   mask, GLenum   filter);
+typedef void (GLAD_API_PTR *PFNGLBLITNAMEDFRAMEBUFFERPROC)(GLuint   readFramebuffer, GLuint   drawFramebuffer, GLint   srcX0, GLint   srcY0, GLint   srcX1, GLint   srcY1, GLint   dstX0, GLint   dstY0, GLint   dstX1, GLint   dstY1, GLbitfield   mask, GLenum   filter);
+typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum   target, GLsizeiptr   size, const void * data, GLenum   usage);
+typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEPROC)(GLenum   target, GLsizeiptr   size, const void * data, GLbitfield   flags);
+typedef void (GLAD_API_PTR *PFNGLBUFFERSTORAGEMEMEXTPROC)(GLenum   target, GLsizeiptr   size, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum   target, GLintptr   offset, GLsizeiptr   size, const void * data);
+typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum   target);
+typedef GLenum (GLAD_API_PTR *PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint   framebuffer, GLenum   target);
+typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum   target, GLenum   clamp);
+typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield   mask);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERDATAPROC)(GLenum   target, GLenum   internalformat, GLenum   format, GLenum   type, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERSUBDATAPROC)(GLenum   target, GLenum   internalformat, GLintptr   offset, GLsizeiptr   size, GLenum   format, GLenum   type, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum   buffer, GLint   drawbuffer, GLfloat   depth, GLint   stencil);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum   buffer, GLint   drawbuffer, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum   buffer, GLint   drawbuffer, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum   buffer, GLint   drawbuffer, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat   red, GLfloat   green, GLfloat   blue, GLfloat   alpha);
+typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble   depth);
+typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat   d);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDBUFFERDATAPROC)(GLuint   buffer, GLenum   internalformat, GLenum   format, GLenum   type, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint   buffer, GLenum   internalformat, GLintptr   offset, GLsizeiptr   size, GLenum   format, GLenum   type, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint   framebuffer, GLenum   buffer, GLint   drawbuffer, GLfloat   depth, GLint   stencil);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint   framebuffer, GLenum   buffer, GLint   drawbuffer, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint   framebuffer, GLenum   buffer, GLint   drawbuffer, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint   framebuffer, GLenum   buffer, GLint   drawbuffer, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint   s);
+typedef void (GLAD_API_PTR *PFNGLCLEARTEXIMAGEPROC)(GLuint   texture, GLint   level, GLenum   format, GLenum   type, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCLEARTEXSUBIMAGEPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLenum   type, const void * data);
+typedef GLenum (GLAD_API_PTR *PFNGLCLIENTWAITSYNCPROC)(GLsync   sync, GLbitfield   flags, GLuint64   timeout);
+typedef void (GLAD_API_PTR *PFNGLCLIPCONTROLPROC)(GLenum   origin, GLenum   depth);
+typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean   red, GLboolean   green, GLboolean   blue, GLboolean   alpha);
+typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint   index, GLboolean   r, GLboolean   g, GLboolean   b, GLboolean   a);
+typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint   shader);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum   target, GLint   level, GLenum   internalformat, GLsizei   width, GLint   border, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum   target, GLint   level, GLenum   internalformat, GLsizei   width, GLsizei   height, GLint   border, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum   target, GLint   level, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth, GLint   border, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLsizei   width, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLsizei   width, GLsizei   height, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLsizei   width, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLsizei   width, GLsizei   height, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLsizei   imageSize, const void * data);
+typedef void (GLAD_API_PTR *PFNGLCOPYBUFFERSUBDATAPROC)(GLenum   readTarget, GLenum   writeTarget, GLintptr   readOffset, GLintptr   writeOffset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAPROC)(GLuint   srcName, GLenum   srcTarget, GLint   srcLevel, GLint   srcX, GLint   srcY, GLint   srcZ, GLuint   dstName, GLenum   dstTarget, GLint   dstLevel, GLint   dstX, GLint   dstY, GLint   dstZ, GLsizei   srcWidth, GLsizei   srcHeight, GLsizei   srcDepth);
+typedef void (GLAD_API_PTR *PFNGLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint   readBuffer, GLuint   writeBuffer, GLintptr   readOffset, GLintptr   writeOffset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum   target, GLint   level, GLenum   internalformat, GLint   x, GLint   y, GLsizei   width, GLint   border);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum   target, GLint   level, GLenum   internalformat, GLint   x, GLint   y, GLsizei   width, GLsizei   height, GLint   border);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   x, GLint   y, GLsizei   width);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE1DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   x, GLint   y, GLsizei   width);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE2DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURESUBIMAGE3DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLCREATEBUFFERSPROC)(GLsizei   n, GLuint  * buffers);
+typedef void (GLAD_API_PTR *PFNGLCREATEFRAMEBUFFERSPROC)(GLsizei   n, GLuint  * framebuffers);
+typedef void (GLAD_API_PTR *PFNGLCREATEMEMORYOBJECTSEXTPROC)(GLsizei   n, GLuint  * memoryObjects);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLCREATEPROGRAMPIPELINESPROC)(GLsizei   n, GLuint  * pipelines);
+typedef void (GLAD_API_PTR *PFNGLCREATEQUERIESPROC)(GLenum   target, GLsizei   n, GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLCREATERENDERBUFFERSPROC)(GLsizei   n, GLuint  * renderbuffers);
+typedef void (GLAD_API_PTR *PFNGLCREATESAMPLERSPROC)(GLsizei   n, GLuint  * samplers);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum   type);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVPROC)(GLenum   type, GLsizei   count, const  GLchar  *const* strings);
+typedef void (GLAD_API_PTR *PFNGLCREATETEXTURESPROC)(GLenum   target, GLsizei   n, GLuint  * textures);
+typedef void (GLAD_API_PTR *PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei   n, GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLCREATEVERTEXARRAYSPROC)(GLsizei   n, GLuint  * arrays);
+typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC   callback, const void * userParam);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum   source, GLenum   type, GLenum   severity, GLsizei   count, const  GLuint  * ids, GLboolean   enabled);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum   source, GLenum   type, GLuint   id, GLenum   severity, GLsizei   length, const  GLchar  * buf);
+typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei   n, const  GLuint  * buffers);
+typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei   n, const  GLuint  * framebuffers);
+typedef void (GLAD_API_PTR *PFNGLDELETEMEMORYOBJECTSEXTPROC)(GLsizei   n, const  GLuint  * memoryObjects);
+typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei   n, const  GLuint  * pipelines);
+typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei   n, const  GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei   n, const  GLuint  * renderbuffers);
+typedef void (GLAD_API_PTR *PFNGLDELETESAMPLERSPROC)(GLsizei   count, const  GLuint  * samplers);
+typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint   shader);
+typedef void (GLAD_API_PTR *PFNGLDELETESYNCPROC)(GLsync   sync);
+typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei   n, const  GLuint  * textures);
+typedef void (GLAD_API_PTR *PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei   n, const  GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei   n, const  GLuint  * arrays);
+typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum   func);
+typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean   flag);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble   n, GLdouble   f);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEARRAYVPROC)(GLuint   first, GLsizei   count, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEINDEXEDPROC)(GLuint   index, GLdouble   n, GLdouble   f);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat   n, GLfloat   f);
+typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint   program, GLuint   shader);
+typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum   cap);
+typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXARRAYATTRIBPROC)(GLuint   vaobj, GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum   target, GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEPROC)(GLuint   num_groups_x, GLuint   num_groups_y, GLuint   num_groups_z);
+typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr   indirect);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum   mode, GLint   first, GLsizei   count);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINDIRECTPROC)(GLenum   mode, const void * indirect);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum   mode, GLint   first, GLsizei   count, GLsizei   instancecount);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum   mode, GLint   first, GLsizei   count, GLsizei   instancecount, GLuint   baseinstance);
+typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum   buf);
+typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei   n, const  GLenum  * bufs);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices, GLint   basevertex);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum   mode, GLenum   type, const void * indirect);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices, GLsizei   instancecount);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices, GLsizei   instancecount, GLuint   baseinstance);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices, GLsizei   instancecount, GLint   basevertex);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum   mode, GLsizei   count, GLenum   type, const void * indices, GLsizei   instancecount, GLint   basevertex, GLuint   baseinstance);
+typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum   mode, GLuint   start, GLuint   end, GLsizei   count, GLenum   type, const void * indices);
+typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum   mode, GLuint   start, GLuint   end, GLsizei   count, GLenum   type, const void * indices, GLint   basevertex);
+typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum   mode, GLuint   id);
+typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum   mode, GLuint   id, GLsizei   instancecount);
+typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum   mode, GLuint   id, GLuint   stream);
+typedef void (GLAD_API_PTR *PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum   mode, GLuint   id, GLuint   stream, GLsizei   instancecount);
+typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum   cap);
+typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXARRAYATTRIBPROC)(GLuint   vaobj, GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum   target, GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum   target);
+typedef void (GLAD_API_PTR *PFNGLENDQUERYINDEXEDPROC)(GLenum   target, GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void);
+typedef GLsync (GLAD_API_PTR *PFNGLFENCESYNCPROC)(GLenum   condition, GLbitfield   flags);
+typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum   target, GLintptr   offset, GLsizeiptr   length);
+typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint   buffer, GLintptr   offset, GLsizeiptr   length);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum   target, GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum   target, GLenum   attachment, GLenum   renderbuffertarget, GLuint   renderbuffer);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum   target, GLenum   attachment, GLuint   texture, GLint   level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum   target, GLenum   attachment, GLenum   textarget, GLuint   texture, GLint   level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum   target, GLenum   attachment, GLenum   textarget, GLuint   texture, GLint   level);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum   target, GLenum   attachment, GLenum   textarget, GLuint   texture, GLint   level, GLint   zoffset);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum   target, GLenum   attachment, GLuint   texture, GLint   level, GLint   layer);
+typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei   n, GLuint  * buffers);
+typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei   n, GLuint  * framebuffers);
+typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESPROC)(GLsizei   n, GLuint  * pipelines);
+typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei   n, GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei   n, GLuint  * renderbuffers);
+typedef void (GLAD_API_PTR *PFNGLGENSAMPLERSPROC)(GLsizei   count, GLuint  * samplers);
+typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei   n, GLuint  * textures);
+typedef void (GLAD_API_PTR *PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei   n, GLuint  * ids);
+typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei   n, GLuint  * arrays);
+typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum   target);
+typedef void (GLAD_API_PTR *PFNGLGENERATETEXTUREMIPMAPPROC)(GLuint   texture);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint   program, GLuint   bufferIndex, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint   program, GLuint   index, GLsizei   bufSize, GLsizei  * length, GLint  * size, GLenum  * type, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint   program, GLenum   shadertype, GLuint   index, GLsizei   bufsize, GLsizei  * length, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint   program, GLenum   shadertype, GLuint   index, GLsizei   bufsize, GLsizei  * length, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint   program, GLenum   shadertype, GLuint   index, GLenum   pname, GLint  * values);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint   program, GLuint   index, GLsizei   bufSize, GLsizei  * length, GLint  * size, GLenum  * type, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint   program, GLuint   uniformBlockIndex, GLsizei   bufSize, GLsizei  * length, GLchar  * uniformBlockName);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint   program, GLuint   uniformBlockIndex, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint   program, GLuint   uniformIndex, GLsizei   bufSize, GLsizei  * length, GLchar  * uniformName);
+typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint   program, GLsizei   uniformCount, const  GLuint  * uniformIndices, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint   program, GLsizei   maxCount, GLsizei  * count, GLuint  * shaders);
+typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint   program, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum   target, GLuint   index, GLboolean  * data);
+typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum   pname, GLboolean  * data);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum   target, GLenum   pname, GLint64  * params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum   target, GLenum   pname, void ** params);
+typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum   target, GLintptr   offset, GLsizeiptr   size, void * data);
+typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum   target, GLint   level, void * img);
+typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint   texture, GLint   level, GLsizei   bufSize, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLsizei   bufSize, void * pixels);
+typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint   count, GLsizei   bufSize, GLenum  * sources, GLenum  * types, GLuint  * ids, GLenum  * severities, GLsizei  * lengths, GLchar  * messageLog);
+typedef void (GLAD_API_PTR *PFNGLGETDOUBLEI_VPROC)(GLenum   target, GLuint   index, GLdouble  * data);
+typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum   pname, GLdouble  * data);
+typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLGETFLOATI_VPROC)(GLenum   target, GLuint   index, GLfloat  * data);
+typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum   pname, GLfloat  * data);
+typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATAINDEXPROC)(GLuint   program, const  GLchar  * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint   program, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum   target, GLenum   attachment, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGER64I_VPROC)(GLenum   target, GLuint   index, GLint64  * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGER64VPROC)(GLenum   pname, GLint64  * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum   target, GLuint   index, GLint  * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum   pname, GLint  * data);
+typedef void (GLAD_API_PTR *PFNGLGETINTERNALFORMATI64VPROC)(GLenum   target, GLenum   internalformat, GLenum   pname, GLsizei   bufSize, GLint64  * params);
+typedef void (GLAD_API_PTR *PFNGLGETINTERNALFORMATIVPROC)(GLenum   target, GLenum   internalformat, GLenum   pname, GLsizei   bufSize, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint   memoryObject, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETMULTISAMPLEFVPROC)(GLenum   pname, GLuint   index, GLfloat  * val);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint   buffer, GLenum   pname, GLint64  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint   buffer, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERPOINTERVPROC)(GLuint   buffer, GLenum   pname, void ** params);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDBUFFERSUBDATAPROC)(GLuint   buffer, GLintptr   offset, GLsizeiptr   size, void * data);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint   framebuffer, GLenum   attachment, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint   framebuffer, GLenum   pname, GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint   renderbuffer, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum   identifier, GLuint   name, GLsizei   bufSize, GLsizei  * length, GLchar  * label);
+typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei   bufSize, GLsizei  * length, GLchar  * label);
+typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum   pname, void ** params);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMBINARYPROC)(GLuint   program, GLsizei   bufSize, GLsizei  * length, GLenum  * binaryFormat, void * binary);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint   program, GLsizei   bufSize, GLsizei  * length, GLchar  * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint   program, GLenum   programInterface, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint   pipeline, GLsizei   bufSize, GLsizei  * length, GLchar  * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint   pipeline, GLenum   pname, GLint  * params);
+typedef GLuint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint   program, GLenum   programInterface, const  GLchar  * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint   program, GLenum   programInterface, const  GLchar  * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint   program, GLenum   programInterface, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint   program, GLenum   programInterface, GLuint   index, GLsizei   bufSize, GLsizei  * length, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint   program, GLenum   programInterface, GLuint   index, GLsizei   propCount, const  GLenum  * props, GLsizei   bufSize, GLsizei  * length, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMSTAGEIVPROC)(GLuint   program, GLenum   shadertype, GLenum   pname, GLint  * values);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint   program, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTI64VPROC)(GLuint   id, GLuint   buffer, GLenum   pname, GLintptr   offset);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTIVPROC)(GLuint   id, GLuint   buffer, GLenum   pname, GLintptr   offset);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint   id, GLuint   buffer, GLenum   pname, GLintptr   offset);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint   id, GLuint   buffer, GLenum   pname, GLintptr   offset);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYINDEXEDIVPROC)(GLenum   target, GLuint   index, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTI64VPROC)(GLuint   id, GLenum   pname, GLint64  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint   id, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUI64VPROC)(GLuint   id, GLenum   pname, GLuint64  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint   id, GLenum   pname, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint   sampler, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint   sampler, GLenum   pname, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint   sampler, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint   sampler, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint   shader, GLsizei   bufSize, GLsizei  * length, GLchar  * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum   shadertype, GLenum   precisiontype, GLint  * range, GLint  * precision);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint   shader, GLsizei   bufSize, GLsizei  * length, GLchar  * source);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint   shader, GLenum   pname, GLint  * params);
+typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum   name);
+typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum   name, GLuint   index);
+typedef GLuint (GLAD_API_PTR *PFNGLGETSUBROUTINEINDEXPROC)(GLuint   program, GLenum   shadertype, const  GLchar  * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint   program, GLenum   shadertype, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETSYNCIVPROC)(GLsync   sync, GLenum   pname, GLsizei   bufSize, GLsizei  * length, GLint  * values);
+typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum   target, GLint   level, GLenum   format, GLenum   type, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum   target, GLint   level, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum   target, GLint   level, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum   target, GLenum   pname, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum   target, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum   target, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTUREIMAGEPROC)(GLuint   texture, GLint   level, GLenum   format, GLenum   type, GLsizei   bufSize, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTURELEVELPARAMETERFVPROC)(GLuint   texture, GLint   level, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTURELEVELPARAMETERIVPROC)(GLuint   texture, GLint   level, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIIVPROC)(GLuint   texture, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIUIVPROC)(GLuint   texture, GLenum   pname, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERFVPROC)(GLuint   texture, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTUREPARAMETERIVPROC)(GLuint   texture, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETTEXTURESUBIMAGEPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLenum   type, GLsizei   bufSize, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint   program, GLuint   index, GLsizei   bufSize, GLsizei  * length, GLsizei  * size, GLenum  * type, GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint   xfb, GLenum   pname, GLuint   index, GLint64  * param);
+typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKI_VPROC)(GLuint   xfb, GLenum   pname, GLuint   index, GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKIVPROC)(GLuint   xfb, GLenum   pname, GLint  * param);
+typedef GLuint (GLAD_API_PTR *PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint   program, const  GLchar  * uniformBlockName);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMINDICESPROC)(GLuint   program, GLsizei   uniformCount, const  GLchar  *const* uniformNames, GLuint  * uniformIndices);
+typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint   program, const  GLchar  * name);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum   shadertype, GLint   location, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMDVPROC)(GLuint   program, GLint   location, GLdouble  * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint   program, GLint   location, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint   program, GLint   location, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint   program, GLint   location, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEI_VEXTPROC)(GLenum   target, GLuint   index, GLubyte  * data);
+typedef void (GLAD_API_PTR *PFNGLGETUNSIGNEDBYTEVEXTPROC)(GLenum   pname, GLubyte  * data);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYINDEXED64IVPROC)(GLuint   vaobj, GLuint   index, GLenum   pname, GLint64  * param);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYINDEXEDIVPROC)(GLuint   vaobj, GLuint   index, GLenum   pname, GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXARRAYIVPROC)(GLuint   vaobj, GLenum   pname, GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint   index, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint   index, GLenum   pname, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBLDVPROC)(GLuint   index, GLenum   pname, GLdouble  * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint   index, GLenum   pname, void ** pointer);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint   index, GLenum   pname, GLdouble  * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint   index, GLenum   pname, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint   index, GLenum   pname, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum   target, GLint   lod, GLsizei   bufSize, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETNTEXIMAGEPROC)(GLenum   target, GLint   level, GLenum   format, GLenum   type, GLsizei   bufSize, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMDVPROC)(GLuint   program, GLint   location, GLsizei   bufSize, GLdouble  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVPROC)(GLuint   program, GLint   location, GLsizei   bufSize, GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVPROC)(GLuint   program, GLint   location, GLsizei   bufSize, GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVPROC)(GLuint   program, GLint   location, GLsizei   bufSize, GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum   target, GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLIMPORTMEMORYFDEXTPROC)(GLuint   memory, GLuint64   size, GLenum   handleType, GLint   fd);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATEBUFFERDATAPROC)(GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint   buffer, GLintptr   offset, GLsizeiptr   length);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum   target, GLsizei   numAttachments, const  GLenum  * attachments);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint   framebuffer, GLsizei   numAttachments, const  GLenum  * attachments);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint   framebuffer, GLsizei   numAttachments, const  GLenum  * attachments, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum   target, GLsizei   numAttachments, const  GLenum  * attachments, GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATETEXIMAGEPROC)(GLuint   texture, GLint   level);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth);
+typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint   buffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum   cap);
+typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum   target, GLuint   index);
+typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint   framebuffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISMEMORYOBJECTEXTPROC)(GLuint   memoryObject);
+typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint   program);
+typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEPROC)(GLuint   pipeline);
+typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint   id);
+typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint   renderbuffer);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSAMPLERPROC)(GLuint   sampler);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint   shader);
+typedef GLboolean (GLAD_API_PTR *PFNGLISSYNCPROC)(GLsync   sync);
+typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint   texture);
+typedef GLboolean (GLAD_API_PTR *PFNGLISTRANSFORMFEEDBACKPROC)(GLuint   id);
+typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint   array);
+typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat   width);
+typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum   opcode);
+typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum   target, GLenum   access);
+typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum   target, GLintptr   offset, GLsizeiptr   length, GLbitfield   access);
+typedef void * (GLAD_API_PTR *PFNGLMAPNAMEDBUFFERPROC)(GLuint   buffer, GLenum   access);
+typedef void * (GLAD_API_PTR *PFNGLMAPNAMEDBUFFERRANGEPROC)(GLuint   buffer, GLintptr   offset, GLsizeiptr   length, GLbitfield   access);
+typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERPROC)(GLbitfield   barriers);
+typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield   barriers);
+typedef void (GLAD_API_PTR *PFNGLMEMORYOBJECTPARAMETERIVEXTPROC)(GLuint   memoryObject, GLenum   pname, const  GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGPROC)(GLfloat   value);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum   mode, const  GLint  * first, const  GLsizei  * count, GLsizei   drawcount);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum   mode, const void * indirect, GLsizei   drawcount, GLsizei   stride);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum   mode, const  GLsizei  * count, GLenum   type, const void *const* indices, GLsizei   drawcount);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum   mode, const  GLsizei  * count, GLenum   type, const void *const* indices, GLsizei   drawcount, const  GLint  * basevertex);
+typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum   mode, GLenum   type, const void * indirect, GLsizei   drawcount, GLsizei   stride);
+typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERDATAPROC)(GLuint   buffer, GLsizeiptr   size, const void * data, GLenum   usage);
+typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEPROC)(GLuint   buffer, GLsizeiptr   size, const void * data, GLbitfield   flags);
+typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC)(GLuint   buffer, GLsizeiptr   size, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLNAMEDBUFFERSUBDATAPROC)(GLuint   buffer, GLintptr   offset, GLsizeiptr   size, const void * data);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint   framebuffer, GLenum   buf);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint   framebuffer, GLsizei   n, const  GLenum  * bufs);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint   framebuffer, GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint   framebuffer, GLenum   src);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint   framebuffer, GLenum   attachment, GLenum   renderbuffertarget, GLuint   renderbuffer);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint   framebuffer, GLenum   attachment, GLuint   texture, GLint   level);
+typedef void (GLAD_API_PTR *PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint   framebuffer, GLenum   attachment, GLuint   texture, GLint   level, GLint   layer);
+typedef void (GLAD_API_PTR *PFNGLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint   renderbuffer, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLuint   renderbuffer, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum   identifier, GLuint   name, GLsizei   length, const  GLchar  * label);
+typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei   length, const  GLchar  * label);
+typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERFVPROC)(GLenum   pname, const  GLfloat  * values);
+typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIPROC)(GLenum   pname, GLint   value);
+typedef void (GLAD_API_PTR *PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum   pname, GLfloat   param);
+typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum   pname, GLfloat   param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum   pname, const  GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum   pname, const  GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat   size);
+typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum   face, GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat   factor, GLfloat   units);
+typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint   index);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMBINARYPROC)(GLuint   program, GLenum   binaryFormat, const void * binary, GLsizei   length);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMPARAMETERIPROC)(GLuint   program, GLenum   pname, GLint   value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DPROC)(GLuint   program, GLint   location, GLdouble   v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1DVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FPROC)(GLuint   program, GLint   location, GLfloat   v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IPROC)(GLuint   program, GLint   location, GLint   v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIPROC)(GLuint   program, GLint   location, GLuint   v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DPROC)(GLuint   program, GLint   location, GLdouble   v0, GLdouble   v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2DVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FPROC)(GLuint   program, GLint   location, GLfloat   v0, GLfloat   v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IPROC)(GLuint   program, GLint   location, GLint   v0, GLint   v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIPROC)(GLuint   program, GLint   location, GLuint   v0, GLuint   v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DPROC)(GLuint   program, GLint   location, GLdouble   v0, GLdouble   v1, GLdouble   v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3DVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FPROC)(GLuint   program, GLint   location, GLfloat   v0, GLfloat   v1, GLfloat   v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IPROC)(GLuint   program, GLint   location, GLint   v0, GLint   v1, GLint   v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIPROC)(GLuint   program, GLint   location, GLuint   v0, GLuint   v1, GLuint   v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DPROC)(GLuint   program, GLint   location, GLdouble   v0, GLdouble   v1, GLdouble   v2, GLdouble   v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4DVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FPROC)(GLuint   program, GLint   location, GLfloat   v0, GLfloat   v1, GLfloat   v2, GLfloat   v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IPROC)(GLuint   program, GLint   location, GLint   v0, GLint   v1, GLint   v2, GLint   v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIPROC)(GLuint   program, GLint   location, GLuint   v0, GLuint   v1, GLuint   v2, GLuint   v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint   program, GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint   program, GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLPROVOKINGVERTEXPROC)(GLenum   mode);
+typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum   source, GLuint   id, GLsizei   length, const  GLchar  * message);
+typedef void (GLAD_API_PTR *PFNGLQUERYCOUNTERPROC)(GLuint   id, GLenum   target);
+typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum   src);
+typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint   x, GLint   y, GLsizei   width, GLsizei   height, GLenum   format, GLenum   type, void * pixels);
+typedef void (GLAD_API_PTR *PFNGLREADNPIXELSPROC)(GLint   x, GLint   y, GLsizei   width, GLsizei   height, GLenum   format, GLenum   type, GLsizei   bufSize, void * data);
+typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum   target, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum   target, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat   value, GLboolean   invert);
+typedef void (GLAD_API_PTR *PFNGLSAMPLEMASKIPROC)(GLuint   maskNumber, GLbitfield   mask);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIIVPROC)(GLuint   sampler, GLenum   pname, const  GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint   sampler, GLenum   pname, const  GLuint  * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFPROC)(GLuint   sampler, GLenum   pname, GLfloat   param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERFVPROC)(GLuint   sampler, GLenum   pname, const  GLfloat  * param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIPROC)(GLuint   sampler, GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLSAMPLERPARAMETERIVPROC)(GLuint   sampler, GLenum   pname, const  GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLSCISSORARRAYVPROC)(GLuint   first, GLsizei   count, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDPROC)(GLuint   index, GLint   left, GLint   bottom, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLSCISSORINDEXEDVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei   count, const  GLuint  * shaders, GLenum   binaryformat, const void * binary, GLsizei   length);
+typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint   shader, GLsizei   count, const  GLchar  *const* string, const  GLint  * length);
+typedef void (GLAD_API_PTR *PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint   program, GLuint   storageBlockIndex, GLuint   storageBlockBinding);
+typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum   func, GLint   ref, GLuint   mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum   face, GLenum   func, GLint   ref, GLuint   mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint   mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum   face, GLuint   mask);
+typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum   fail, GLenum   zfail, GLenum   zpass);
+typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum   face, GLenum   sfail, GLenum   dpfail, GLenum   dppass);
+typedef void (GLAD_API_PTR *PFNGLTEXBUFFERPROC)(GLenum   target, GLenum   internalformat, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEPROC)(GLenum   target, GLenum   internalformat, GLuint   buffer, GLintptr   offset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum   target, GLint   level, GLint   internalformat, GLsizei   width, GLint   border, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum   target, GLint   level, GLint   internalformat, GLsizei   width, GLsizei   height, GLint   border, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum   target, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum   target, GLint   level, GLint   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth, GLint   border, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum   target, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum   target, GLenum   pname, const  GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum   target, GLenum   pname, const  GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum   target, GLenum   pname, GLfloat   param);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum   target, GLenum   pname, const  GLfloat  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum   target, GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum   target, GLenum   pname, const  GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE1DPROC)(GLenum   target, GLsizei   levels, GLenum   internalformat, GLsizei   width);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DPROC)(GLenum   target, GLsizei   levels, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum   target, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DPROC)(GLenum   target, GLsizei   levels, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum   target, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM1DEXTPROC)(GLenum   target, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DEXTPROC)(GLenum   target, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC)(GLenum   target, GLsizei   samples, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLboolean   fixedSampleLocations, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DEXTPROC)(GLenum   target, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLsizei   depth, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC)(GLenum   target, GLsizei   samples, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLsizei   depth, GLboolean   fixedSampleLocations, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLsizei   width, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLsizei   width, GLsizei   height, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum   target, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREBARRIERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREBUFFERPROC)(GLuint   texture, GLenum   internalformat, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREBUFFERRANGEPROC)(GLuint   texture, GLenum   internalformat, GLuint   buffer, GLintptr   offset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIIVPROC)(GLuint   texture, GLenum   pname, const  GLint  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIUIVPROC)(GLuint   texture, GLenum   pname, const  GLuint  * params);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERFPROC)(GLuint   texture, GLenum   pname, GLfloat   param);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERFVPROC)(GLuint   texture, GLenum   pname, const  GLfloat  * param);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIPROC)(GLuint   texture, GLenum   pname, GLint   param);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREPARAMETERIVPROC)(GLuint   texture, GLenum   pname, const  GLint  * param);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE1DPROC)(GLuint   texture, GLsizei   levels, GLenum   internalformat, GLsizei   width);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DPROC)(GLuint   texture, GLsizei   levels, GLenum   internalformat, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint   texture, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DPROC)(GLuint   texture, GLsizei   levels, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint   texture, GLsizei   samples, GLenum   internalformat, GLsizei   width, GLsizei   height, GLsizei   depth, GLboolean   fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM1DEXTPROC)(GLuint   texture, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DEXTPROC)(GLuint   texture, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC)(GLuint   texture, GLsizei   samples, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLboolean   fixedSampleLocations, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DEXTPROC)(GLuint   texture, GLsizei   levels, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLsizei   depth, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC)(GLuint   texture, GLsizei   samples, GLenum   internalFormat, GLsizei   width, GLsizei   height, GLsizei   depth, GLboolean   fixedSampleLocations, GLuint   memory, GLuint64   offset);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE1DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLsizei   width, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE2DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLsizei   width, GLsizei   height, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXTURESUBIMAGE3DPROC)(GLuint   texture, GLint   level, GLint   xoffset, GLint   yoffset, GLint   zoffset, GLsizei   width, GLsizei   height, GLsizei   depth, GLenum   format, GLenum   type, const void * pixels);
+typedef void (GLAD_API_PTR *PFNGLTEXTUREVIEWPROC)(GLuint   texture, GLenum   target, GLuint   origtexture, GLenum   internalformat, GLuint   minlevel, GLuint   numlevels, GLuint   minlayer, GLuint   numlayers);
+typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint   xfb, GLuint   index, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint   xfb, GLuint   index, GLuint   buffer, GLintptr   offset, GLsizeiptr   size);
+typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint   program, GLsizei   count, const  GLchar  *const* varyings, GLenum   bufferMode);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1DPROC)(GLint   location, GLdouble   x);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1DVPROC)(GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint   location, GLfloat   v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint   location, GLint   v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint   location, GLuint   v0);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2DPROC)(GLint   location, GLdouble   x, GLdouble   y);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2DVPROC)(GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint   location, GLfloat   v0, GLfloat   v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint   location, GLint   v0, GLint   v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint   location, GLuint   v0, GLuint   v1);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3DPROC)(GLint   location, GLdouble   x, GLdouble   y, GLdouble   z);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3DVPROC)(GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint   location, GLfloat   v0, GLfloat   v1, GLfloat   v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint   location, GLint   v0, GLint   v1, GLint   v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint   location, GLuint   v0, GLuint   v1, GLuint   v2);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4DPROC)(GLint   location, GLdouble   x, GLdouble   y, GLdouble   z, GLdouble   w);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4DVPROC)(GLint   location, GLsizei   count, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint   location, GLfloat   v0, GLfloat   v1, GLfloat   v2, GLfloat   v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint   location, GLsizei   count, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint   location, GLint   v0, GLint   v1, GLint   v2, GLint   v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint   location, GLsizei   count, const  GLint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint   location, GLuint   v0, GLuint   v1, GLuint   v2, GLuint   v3);
+typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint   location, GLsizei   count, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint   program, GLuint   uniformBlockIndex, GLuint   uniformBlockBinding);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3DVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLdouble  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint   location, GLsizei   count, GLboolean   transpose, const  GLfloat  * value);
+typedef void (GLAD_API_PTR *PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum   shadertype, GLsizei   count, const  GLuint  * indices);
+typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum   target);
+typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPNAMEDBUFFERPROC)(GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESPROC)(GLuint   pipeline, GLbitfield   stages, GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint   program);
+typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint   pipeline);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBBINDINGPROC)(GLuint   vaobj, GLuint   attribindex, GLuint   bindingindex);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBFORMATPROC)(GLuint   vaobj, GLuint   attribindex, GLint   size, GLenum   type, GLboolean   normalized, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBIFORMATPROC)(GLuint   vaobj, GLuint   attribindex, GLint   size, GLenum   type, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYATTRIBLFORMATPROC)(GLuint   vaobj, GLuint   attribindex, GLint   size, GLenum   type, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYBINDINGDIVISORPROC)(GLuint   vaobj, GLuint   bindingindex, GLuint   divisor);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYELEMENTBUFFERPROC)(GLuint   vaobj, GLuint   buffer);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYVERTEXBUFFERPROC)(GLuint   vaobj, GLuint   bindingindex, GLuint   buffer, GLintptr   offset, GLsizei   stride);
+typedef void (GLAD_API_PTR *PFNGLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint   vaobj, GLuint   first, GLsizei   count, const  GLuint  * buffers, const  GLintptr  * offsets, const  GLsizei  * strides);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint   index, GLdouble   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint   index, GLfloat   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint   index, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint   index, GLshort   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint   index, GLdouble   x, GLdouble   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint   index, GLfloat   x, GLfloat   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint   index, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint   index, GLshort   x, GLshort   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint   index, GLdouble   x, GLdouble   y, GLdouble   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint   index, GLfloat   x, GLfloat   y, GLfloat   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint   index, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint   index, GLshort   x, GLshort   y, GLshort   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint   index, const  GLbyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint   index, GLubyte   x, GLubyte   y, GLubyte   z, GLubyte   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint   index, const  GLubyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint   index, const  GLushort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint   index, const  GLbyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint   index, GLdouble   x, GLdouble   y, GLdouble   z, GLdouble   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint   index, GLfloat   x, GLfloat   y, GLfloat   z, GLfloat   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint   index, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint   index, GLshort   x, GLshort   y, GLshort   z, GLshort   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint   index, const  GLubyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint   index, const  GLushort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBBINDINGPROC)(GLuint   attribindex, GLuint   bindingindex);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBDIVISORPROC)(GLuint   index, GLuint   divisor);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBFORMATPROC)(GLuint   attribindex, GLint   size, GLenum   type, GLboolean   normalized, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint   index, GLint   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint   index, GLuint   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint   index, GLint   x, GLint   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint   index, GLuint   x, GLuint   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint   index, GLint   x, GLint   y, GLint   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint   index, GLuint   x, GLuint   y, GLuint   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint   index, const  GLbyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint   index, GLint   x, GLint   y, GLint   z, GLint   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint   index, const  GLint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint   index, const  GLshort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint   index, const  GLubyte  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint   index, GLuint   x, GLuint   y, GLuint   z, GLuint   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint   index, const  GLuint  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint   index, const  GLushort  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIFORMATPROC)(GLuint   attribindex, GLint   size, GLenum   type, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint   index, GLint   size, GLenum   type, GLsizei   stride, const void * pointer);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DPROC)(GLuint   index, GLdouble   x);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL1DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DPROC)(GLuint   index, GLdouble   x, GLdouble   y);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL2DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DPROC)(GLuint   index, GLdouble   x, GLdouble   y, GLdouble   z);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL3DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DPROC)(GLuint   index, GLdouble   x, GLdouble   y, GLdouble   z, GLdouble   w);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBL4DVPROC)(GLuint   index, const  GLdouble  * v);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLFORMATPROC)(GLuint   attribindex, GLint   size, GLenum   type, GLuint   relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint   index, GLint   size, GLenum   type, GLsizei   stride, const void * pointer);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIPROC)(GLuint   index, GLenum   type, GLboolean   normalized, GLuint   value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP1UIVPROC)(GLuint   index, GLenum   type, GLboolean   normalized, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIPROC)(GLuint   index, GLenum   type, GLboolean   normalized, GLuint   value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP2UIVPROC)(GLuint   index, GLenum   type, GLboolean   normalized, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIPROC)(GLuint   index, GLenum   type, GLboolean   normalized, GLuint   value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP3UIVPROC)(GLuint   index, GLenum   type, GLboolean   normalized, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIPROC)(GLuint   index, GLenum   type, GLboolean   normalized, GLuint   value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBP4UIVPROC)(GLuint   index, GLenum   type, GLboolean   normalized, const  GLuint  * value);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint   index, GLint   size, GLenum   type, GLboolean   normalized, GLsizei   stride, const void * pointer);
+typedef void (GLAD_API_PTR *PFNGLVERTEXBINDINGDIVISORPROC)(GLuint   bindingindex, GLuint   divisor);
+typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint   x, GLint   y, GLsizei   width, GLsizei   height);
+typedef void (GLAD_API_PTR *PFNGLVIEWPORTARRAYVPROC)(GLuint   first, GLsizei   count, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFPROC)(GLuint   index, GLfloat   x, GLfloat   y, GLfloat   w, GLfloat   h);
+typedef void (GLAD_API_PTR *PFNGLVIEWPORTINDEXEDFVPROC)(GLuint   index, const  GLfloat  * v);
+typedef void (GLAD_API_PTR *PFNGLWAITSYNCPROC)(GLsync   sync, GLbitfield   flags, GLuint64   timeout);
+
+GLAD_API_CALL PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
+#define glActiveShaderProgram glad_glActiveShaderProgram
+GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture;
+#define glActiveTexture glad_glActiveTexture
+GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader;
+#define glAttachShader glad_glAttachShader
+GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender;
+#define glBeginConditionalRender glad_glBeginConditionalRender
+GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery;
+#define glBeginQuery glad_glBeginQuery
+GLAD_API_CALL PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed;
+#define glBeginQueryIndexed glad_glBeginQueryIndexed
+GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback;
+#define glBeginTransformFeedback glad_glBeginTransformFeedback
+GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation;
+#define glBindAttribLocation glad_glBindAttribLocation
+GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer;
+#define glBindBuffer glad_glBindBuffer
+GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase;
+#define glBindBufferBase glad_glBindBufferBase
+GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange;
+#define glBindBufferRange glad_glBindBufferRange
+GLAD_API_CALL PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase;
+#define glBindBuffersBase glad_glBindBuffersBase
+GLAD_API_CALL PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange;
+#define glBindBuffersRange glad_glBindBuffersRange
+GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation;
+#define glBindFragDataLocation glad_glBindFragDataLocation
+GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed;
+#define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed
+GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer;
+#define glBindFramebuffer glad_glBindFramebuffer
+GLAD_API_CALL PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
+#define glBindImageTexture glad_glBindImageTexture
+GLAD_API_CALL PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures;
+#define glBindImageTextures glad_glBindImageTextures
+GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
+#define glBindProgramPipeline glad_glBindProgramPipeline
+GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer;
+#define glBindRenderbuffer glad_glBindRenderbuffer
+GLAD_API_CALL PFNGLBINDSAMPLERPROC glad_glBindSampler;
+#define glBindSampler glad_glBindSampler
+GLAD_API_CALL PFNGLBINDSAMPLERSPROC glad_glBindSamplers;
+#define glBindSamplers glad_glBindSamplers
+GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture;
+#define glBindTexture glad_glBindTexture
+GLAD_API_CALL PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit;
+#define glBindTextureUnit glad_glBindTextureUnit
+GLAD_API_CALL PFNGLBINDTEXTURESPROC glad_glBindTextures;
+#define glBindTextures glad_glBindTextures
+GLAD_API_CALL PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
+#define glBindTransformFeedback glad_glBindTransformFeedback
+GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray;
+#define glBindVertexArray glad_glBindVertexArray
+GLAD_API_CALL PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
+#define glBindVertexBuffer glad_glBindVertexBuffer
+GLAD_API_CALL PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers;
+#define glBindVertexBuffers glad_glBindVertexBuffers
+GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor;
+#define glBlendColor glad_glBlendColor
+GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation;
+#define glBlendEquation glad_glBlendEquation
+GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate;
+#define glBlendEquationSeparate glad_glBlendEquationSeparate
+GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;
+#define glBlendEquationSeparatei glad_glBlendEquationSeparatei
+GLAD_API_CALL PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;
+#define glBlendEquationi glad_glBlendEquationi
+GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc;
+#define glBlendFunc glad_glBlendFunc
+GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate;
+#define glBlendFuncSeparate glad_glBlendFuncSeparate
+GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;
+#define glBlendFuncSeparatei glad_glBlendFuncSeparatei
+GLAD_API_CALL PFNGLBLENDFUNCIPROC glad_glBlendFunci;
+#define glBlendFunci glad_glBlendFunci
+GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer;
+#define glBlitFramebuffer glad_glBlitFramebuffer
+GLAD_API_CALL PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer;
+#define glBlitNamedFramebuffer glad_glBlitNamedFramebuffer
+GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData;
+#define glBufferData glad_glBufferData
+GLAD_API_CALL PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
+#define glBufferStorage glad_glBufferStorage
+GLAD_API_CALL PFNGLBUFFERSTORAGEMEMEXTPROC glad_glBufferStorageMemEXT;
+#define glBufferStorageMemEXT glad_glBufferStorageMemEXT
+GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData;
+#define glBufferSubData glad_glBufferSubData
+GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus;
+#define glCheckFramebufferStatus glad_glCheckFramebufferStatus
+GLAD_API_CALL PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus;
+#define glCheckNamedFramebufferStatus glad_glCheckNamedFramebufferStatus
+GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor;
+#define glClampColor glad_glClampColor
+GLAD_API_CALL PFNGLCLEARPROC glad_glClear;
+#define glClear glad_glClear
+GLAD_API_CALL PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData;
+#define glClearBufferData glad_glClearBufferData
+GLAD_API_CALL PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData;
+#define glClearBufferSubData glad_glClearBufferSubData
+GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi;
+#define glClearBufferfi glad_glClearBufferfi
+GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv;
+#define glClearBufferfv glad_glClearBufferfv
+GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv;
+#define glClearBufferiv glad_glClearBufferiv
+GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv;
+#define glClearBufferuiv glad_glClearBufferuiv
+GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor;
+#define glClearColor glad_glClearColor
+GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth;
+#define glClearDepth glad_glClearDepth
+GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
+#define glClearDepthf glad_glClearDepthf
+GLAD_API_CALL PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData;
+#define glClearNamedBufferData glad_glClearNamedBufferData
+GLAD_API_CALL PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData;
+#define glClearNamedBufferSubData glad_glClearNamedBufferSubData
+GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi;
+#define glClearNamedFramebufferfi glad_glClearNamedFramebufferfi
+GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv;
+#define glClearNamedFramebufferfv glad_glClearNamedFramebufferfv
+GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv;
+#define glClearNamedFramebufferiv glad_glClearNamedFramebufferiv
+GLAD_API_CALL PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv;
+#define glClearNamedFramebufferuiv glad_glClearNamedFramebufferuiv
+GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil;
+#define glClearStencil glad_glClearStencil
+GLAD_API_CALL PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage;
+#define glClearTexImage glad_glClearTexImage
+GLAD_API_CALL PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage;
+#define glClearTexSubImage glad_glClearTexSubImage
+GLAD_API_CALL PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync;
+#define glClientWaitSync glad_glClientWaitSync
+GLAD_API_CALL PFNGLCLIPCONTROLPROC glad_glClipControl;
+#define glClipControl glad_glClipControl
+GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask;
+#define glColorMask glad_glColorMask
+GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski;
+#define glColorMaski glad_glColorMaski
+GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader;
+#define glCompileShader glad_glCompileShader
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D;
+#define glCompressedTexImage1D glad_glCompressedTexImage1D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D;
+#define glCompressedTexImage2D glad_glCompressedTexImage2D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D;
+#define glCompressedTexImage3D glad_glCompressedTexImage3D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D;
+#define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D;
+#define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D;
+#define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D;
+#define glCompressedTextureSubImage1D glad_glCompressedTextureSubImage1D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D;
+#define glCompressedTextureSubImage2D glad_glCompressedTextureSubImage2D
+GLAD_API_CALL PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D;
+#define glCompressedTextureSubImage3D glad_glCompressedTextureSubImage3D
+GLAD_API_CALL PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData;
+#define glCopyBufferSubData glad_glCopyBufferSubData
+GLAD_API_CALL PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
+#define glCopyImageSubData glad_glCopyImageSubData
+GLAD_API_CALL PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData;
+#define glCopyNamedBufferSubData glad_glCopyNamedBufferSubData
+GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D;
+#define glCopyTexImage1D glad_glCopyTexImage1D
+GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D;
+#define glCopyTexImage2D glad_glCopyTexImage2D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D;
+#define glCopyTexSubImage1D glad_glCopyTexSubImage1D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D;
+#define glCopyTexSubImage2D glad_glCopyTexSubImage2D
+GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D;
+#define glCopyTexSubImage3D glad_glCopyTexSubImage3D
+GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D;
+#define glCopyTextureSubImage1D glad_glCopyTextureSubImage1D
+GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D;
+#define glCopyTextureSubImage2D glad_glCopyTextureSubImage2D
+GLAD_API_CALL PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D;
+#define glCopyTextureSubImage3D glad_glCopyTextureSubImage3D
+GLAD_API_CALL PFNGLCREATEBUFFERSPROC glad_glCreateBuffers;
+#define glCreateBuffers glad_glCreateBuffers
+GLAD_API_CALL PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers;
+#define glCreateFramebuffers glad_glCreateFramebuffers
+GLAD_API_CALL PFNGLCREATEMEMORYOBJECTSEXTPROC glad_glCreateMemoryObjectsEXT;
+#define glCreateMemoryObjectsEXT glad_glCreateMemoryObjectsEXT
+GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram;
+#define glCreateProgram glad_glCreateProgram
+GLAD_API_CALL PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines;
+#define glCreateProgramPipelines glad_glCreateProgramPipelines
+GLAD_API_CALL PFNGLCREATEQUERIESPROC glad_glCreateQueries;
+#define glCreateQueries glad_glCreateQueries
+GLAD_API_CALL PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers;
+#define glCreateRenderbuffers glad_glCreateRenderbuffers
+GLAD_API_CALL PFNGLCREATESAMPLERSPROC glad_glCreateSamplers;
+#define glCreateSamplers glad_glCreateSamplers
+GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader;
+#define glCreateShader glad_glCreateShader
+GLAD_API_CALL PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
+#define glCreateShaderProgramv glad_glCreateShaderProgramv
+GLAD_API_CALL PFNGLCREATETEXTURESPROC glad_glCreateTextures;
+#define glCreateTextures glad_glCreateTextures
+GLAD_API_CALL PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks;
+#define glCreateTransformFeedbacks glad_glCreateTransformFeedbacks
+GLAD_API_CALL PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays;
+#define glCreateVertexArrays glad_glCreateVertexArrays
+GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace;
+#define glCullFace glad_glCullFace
+GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
+#define glDebugMessageCallback glad_glDebugMessageCallback
+GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
+#define glDebugMessageControl glad_glDebugMessageControl
+GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
+#define glDebugMessageInsert glad_glDebugMessageInsert
+GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers;
+#define glDeleteBuffers glad_glDeleteBuffers
+GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers;
+#define glDeleteFramebuffers glad_glDeleteFramebuffers
+GLAD_API_CALL PFNGLDELETEMEMORYOBJECTSEXTPROC glad_glDeleteMemoryObjectsEXT;
+#define glDeleteMemoryObjectsEXT glad_glDeleteMemoryObjectsEXT
+GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram;
+#define glDeleteProgram glad_glDeleteProgram
+GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
+#define glDeleteProgramPipelines glad_glDeleteProgramPipelines
+GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries;
+#define glDeleteQueries glad_glDeleteQueries
+GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers;
+#define glDeleteRenderbuffers glad_glDeleteRenderbuffers
+GLAD_API_CALL PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers;
+#define glDeleteSamplers glad_glDeleteSamplers
+GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader;
+#define glDeleteShader glad_glDeleteShader
+GLAD_API_CALL PFNGLDELETESYNCPROC glad_glDeleteSync;
+#define glDeleteSync glad_glDeleteSync
+GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures;
+#define glDeleteTextures glad_glDeleteTextures
+GLAD_API_CALL PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
+#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks
+GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays;
+#define glDeleteVertexArrays glad_glDeleteVertexArrays
+GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc;
+#define glDepthFunc glad_glDepthFunc
+GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask;
+#define glDepthMask glad_glDepthMask
+GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange;
+#define glDepthRange glad_glDepthRange
+GLAD_API_CALL PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv;
+#define glDepthRangeArrayv glad_glDepthRangeArrayv
+GLAD_API_CALL PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed;
+#define glDepthRangeIndexed glad_glDepthRangeIndexed
+GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
+#define glDepthRangef glad_glDepthRangef
+GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader;
+#define glDetachShader glad_glDetachShader
+GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable;
+#define glDisable glad_glDisable
+GLAD_API_CALL PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib;
+#define glDisableVertexArrayAttrib glad_glDisableVertexArrayAttrib
+GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray;
+#define glDisableVertexAttribArray glad_glDisableVertexAttribArray
+GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei;
+#define glDisablei glad_glDisablei
+GLAD_API_CALL PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
+#define glDispatchCompute glad_glDispatchCompute
+GLAD_API_CALL PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
+#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
+GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays;
+#define glDrawArrays glad_glDrawArrays
+GLAD_API_CALL PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
+#define glDrawArraysIndirect glad_glDrawArraysIndirect
+GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced;
+#define glDrawArraysInstanced glad_glDrawArraysInstanced
+GLAD_API_CALL PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance;
+#define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance
+GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer;
+#define glDrawBuffer glad_glDrawBuffer
+GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers;
+#define glDrawBuffers glad_glDrawBuffers
+GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements;
+#define glDrawElements glad_glDrawElements
+GLAD_API_CALL PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex;
+#define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex
+GLAD_API_CALL PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
+#define glDrawElementsIndirect glad_glDrawElementsIndirect
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced;
+#define glDrawElementsInstanced glad_glDrawElementsInstanced
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance;
+#define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex;
+#define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex
+GLAD_API_CALL PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance;
+#define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance
+GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements;
+#define glDrawRangeElements glad_glDrawRangeElements
+GLAD_API_CALL PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex;
+#define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex
+GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback;
+#define glDrawTransformFeedback glad_glDrawTransformFeedback
+GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced;
+#define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced
+GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream;
+#define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream
+GLAD_API_CALL PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced;
+#define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced
+GLAD_API_CALL PFNGLENABLEPROC glad_glEnable;
+#define glEnable glad_glEnable
+GLAD_API_CALL PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib;
+#define glEnableVertexArrayAttrib glad_glEnableVertexArrayAttrib
+GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray;
+#define glEnableVertexAttribArray glad_glEnableVertexAttribArray
+GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei;
+#define glEnablei glad_glEnablei
+GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender;
+#define glEndConditionalRender glad_glEndConditionalRender
+GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery;
+#define glEndQuery glad_glEndQuery
+GLAD_API_CALL PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed;
+#define glEndQueryIndexed glad_glEndQueryIndexed
+GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback;
+#define glEndTransformFeedback glad_glEndTransformFeedback
+GLAD_API_CALL PFNGLFENCESYNCPROC glad_glFenceSync;
+#define glFenceSync glad_glFenceSync
+GLAD_API_CALL PFNGLFINISHPROC glad_glFinish;
+#define glFinish glad_glFinish
+GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush;
+#define glFlush glad_glFlush
+GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange;
+#define glFlushMappedBufferRange glad_glFlushMappedBufferRange
+GLAD_API_CALL PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange;
+#define glFlushMappedNamedBufferRange glad_glFlushMappedNamedBufferRange
+GLAD_API_CALL PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
+#define glFramebufferParameteri glad_glFramebufferParameteri
+GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer;
+#define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture;
+#define glFramebufferTexture glad_glFramebufferTexture
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D;
+#define glFramebufferTexture1D glad_glFramebufferTexture1D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D;
+#define glFramebufferTexture2D glad_glFramebufferTexture2D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D;
+#define glFramebufferTexture3D glad_glFramebufferTexture3D
+GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer;
+#define glFramebufferTextureLayer glad_glFramebufferTextureLayer
+GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace;
+#define glFrontFace glad_glFrontFace
+GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers;
+#define glGenBuffers glad_glGenBuffers
+GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers;
+#define glGenFramebuffers glad_glGenFramebuffers
+GLAD_API_CALL PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
+#define glGenProgramPipelines glad_glGenProgramPipelines
+GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries;
+#define glGenQueries glad_glGenQueries
+GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers;
+#define glGenRenderbuffers glad_glGenRenderbuffers
+GLAD_API_CALL PFNGLGENSAMPLERSPROC glad_glGenSamplers;
+#define glGenSamplers glad_glGenSamplers
+GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures;
+#define glGenTextures glad_glGenTextures
+GLAD_API_CALL PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
+#define glGenTransformFeedbacks glad_glGenTransformFeedbacks
+GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays;
+#define glGenVertexArrays glad_glGenVertexArrays
+GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap;
+#define glGenerateMipmap glad_glGenerateMipmap
+GLAD_API_CALL PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap;
+#define glGenerateTextureMipmap glad_glGenerateTextureMipmap
+GLAD_API_CALL PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv;
+#define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv
+GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib;
+#define glGetActiveAttrib glad_glGetActiveAttrib
+GLAD_API_CALL PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName;
+#define glGetActiveSubroutineName glad_glGetActiveSubroutineName
+GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName;
+#define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName
+GLAD_API_CALL PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv;
+#define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform;
+#define glGetActiveUniform glad_glGetActiveUniform
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName;
+#define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv;
+#define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName;
+#define glGetActiveUniformName glad_glGetActiveUniformName
+GLAD_API_CALL PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv;
+#define glGetActiveUniformsiv glad_glGetActiveUniformsiv
+GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders;
+#define glGetAttachedShaders glad_glGetAttachedShaders
+GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation;
+#define glGetAttribLocation glad_glGetAttribLocation
+GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v;
+#define glGetBooleani_v glad_glGetBooleani_v
+GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv;
+#define glGetBooleanv glad_glGetBooleanv
+GLAD_API_CALL PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v;
+#define glGetBufferParameteri64v glad_glGetBufferParameteri64v
+GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv;
+#define glGetBufferParameteriv glad_glGetBufferParameteriv
+GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv;
+#define glGetBufferPointerv glad_glGetBufferPointerv
+GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData;
+#define glGetBufferSubData glad_glGetBufferSubData
+GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage;
+#define glGetCompressedTexImage glad_glGetCompressedTexImage
+GLAD_API_CALL PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage;
+#define glGetCompressedTextureImage glad_glGetCompressedTextureImage
+GLAD_API_CALL PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage;
+#define glGetCompressedTextureSubImage glad_glGetCompressedTextureSubImage
+GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
+#define glGetDebugMessageLog glad_glGetDebugMessageLog
+GLAD_API_CALL PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v;
+#define glGetDoublei_v glad_glGetDoublei_v
+GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev;
+#define glGetDoublev glad_glGetDoublev
+GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError;
+#define glGetError glad_glGetError
+GLAD_API_CALL PFNGLGETFLOATI_VPROC glad_glGetFloati_v;
+#define glGetFloati_v glad_glGetFloati_v
+GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv;
+#define glGetFloatv glad_glGetFloatv
+GLAD_API_CALL PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex;
+#define glGetFragDataIndex glad_glGetFragDataIndex
+GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation;
+#define glGetFragDataLocation glad_glGetFragDataLocation
+GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv;
+#define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv
+GLAD_API_CALL PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
+#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv
+GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;
+#define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus
+GLAD_API_CALL PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v;
+#define glGetInteger64i_v glad_glGetInteger64i_v
+GLAD_API_CALL PFNGLGETINTEGER64VPROC glad_glGetInteger64v;
+#define glGetInteger64v glad_glGetInteger64v
+GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v;
+#define glGetIntegeri_v glad_glGetIntegeri_v
+GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv;
+#define glGetIntegerv glad_glGetIntegerv
+GLAD_API_CALL PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v;
+#define glGetInternalformati64v glad_glGetInternalformati64v
+GLAD_API_CALL PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
+#define glGetInternalformativ glad_glGetInternalformativ
+GLAD_API_CALL PFNGLGETMEMORYOBJECTPARAMETERIVEXTPROC glad_glGetMemoryObjectParameterivEXT;
+#define glGetMemoryObjectParameterivEXT glad_glGetMemoryObjectParameterivEXT
+GLAD_API_CALL PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv;
+#define glGetMultisamplefv glad_glGetMultisamplefv
+GLAD_API_CALL PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v;
+#define glGetNamedBufferParameteri64v glad_glGetNamedBufferParameteri64v
+GLAD_API_CALL PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv;
+#define glGetNamedBufferParameteriv glad_glGetNamedBufferParameteriv
+GLAD_API_CALL PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv;
+#define glGetNamedBufferPointerv glad_glGetNamedBufferPointerv
+GLAD_API_CALL PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData;
+#define glGetNamedBufferSubData glad_glGetNamedBufferSubData
+GLAD_API_CALL PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv;
+#define glGetNamedFramebufferAttachmentParameteriv glad_glGetNamedFramebufferAttachmentParameteriv
+GLAD_API_CALL PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv;
+#define glGetNamedFramebufferParameteriv glad_glGetNamedFramebufferParameteriv
+GLAD_API_CALL PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv;
+#define glGetNamedRenderbufferParameteriv glad_glGetNamedRenderbufferParameteriv
+GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
+#define glGetObjectLabel glad_glGetObjectLabel
+GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
+#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
+GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv;
+#define glGetPointerv glad_glGetPointerv
+GLAD_API_CALL PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary;
+#define glGetProgramBinary glad_glGetProgramBinary
+GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog;
+#define glGetProgramInfoLog glad_glGetProgramInfoLog
+GLAD_API_CALL PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
+#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv
+GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
+#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog
+GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
+#define glGetProgramPipelineiv glad_glGetProgramPipelineiv
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
+#define glGetProgramResourceIndex glad_glGetProgramResourceIndex
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
+#define glGetProgramResourceLocation glad_glGetProgramResourceLocation
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex;
+#define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
+#define glGetProgramResourceName glad_glGetProgramResourceName
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
+#define glGetProgramResourceiv glad_glGetProgramResourceiv
+GLAD_API_CALL PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv;
+#define glGetProgramStageiv glad_glGetProgramStageiv
+GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv;
+#define glGetProgramiv glad_glGetProgramiv
+GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v;
+#define glGetQueryBufferObjecti64v glad_glGetQueryBufferObjecti64v
+GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv;
+#define glGetQueryBufferObjectiv glad_glGetQueryBufferObjectiv
+GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v;
+#define glGetQueryBufferObjectui64v glad_glGetQueryBufferObjectui64v
+GLAD_API_CALL PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv;
+#define glGetQueryBufferObjectuiv glad_glGetQueryBufferObjectuiv
+GLAD_API_CALL PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv;
+#define glGetQueryIndexediv glad_glGetQueryIndexediv
+GLAD_API_CALL PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v;
+#define glGetQueryObjecti64v glad_glGetQueryObjecti64v
+GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv;
+#define glGetQueryObjectiv glad_glGetQueryObjectiv
+GLAD_API_CALL PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v;
+#define glGetQueryObjectui64v glad_glGetQueryObjectui64v
+GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv;
+#define glGetQueryObjectuiv glad_glGetQueryObjectuiv
+GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv;
+#define glGetQueryiv glad_glGetQueryiv
+GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv;
+#define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv;
+#define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv;
+#define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv;
+#define glGetSamplerParameterfv glad_glGetSamplerParameterfv
+GLAD_API_CALL PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv;
+#define glGetSamplerParameteriv glad_glGetSamplerParameteriv
+GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog;
+#define glGetShaderInfoLog glad_glGetShaderInfoLog
+GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
+#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
+GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource;
+#define glGetShaderSource glad_glGetShaderSource
+GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv;
+#define glGetShaderiv glad_glGetShaderiv
+GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString;
+#define glGetString glad_glGetString
+GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi;
+#define glGetStringi glad_glGetStringi
+GLAD_API_CALL PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex;
+#define glGetSubroutineIndex glad_glGetSubroutineIndex
+GLAD_API_CALL PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation;
+#define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation
+GLAD_API_CALL PFNGLGETSYNCIVPROC glad_glGetSynciv;
+#define glGetSynciv glad_glGetSynciv
+GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage;
+#define glGetTexImage glad_glGetTexImage
+GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv;
+#define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv
+GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv;
+#define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv;
+#define glGetTexParameterIiv glad_glGetTexParameterIiv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv;
+#define glGetTexParameterIuiv glad_glGetTexParameterIuiv
+GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv;
+#define glGetTexParameterfv glad_glGetTexParameterfv
+GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv;
+#define glGetTexParameteriv glad_glGetTexParameteriv
+GLAD_API_CALL PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage;
+#define glGetTextureImage glad_glGetTextureImage
+GLAD_API_CALL PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv;
+#define glGetTextureLevelParameterfv glad_glGetTextureLevelParameterfv
+GLAD_API_CALL PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv;
+#define glGetTextureLevelParameteriv glad_glGetTextureLevelParameteriv
+GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv;
+#define glGetTextureParameterIiv glad_glGetTextureParameterIiv
+GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv;
+#define glGetTextureParameterIuiv glad_glGetTextureParameterIuiv
+GLAD_API_CALL PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv;
+#define glGetTextureParameterfv glad_glGetTextureParameterfv
+GLAD_API_CALL PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv;
+#define glGetTextureParameteriv glad_glGetTextureParameteriv
+GLAD_API_CALL PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage;
+#define glGetTextureSubImage glad_glGetTextureSubImage
+GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying;
+#define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying
+GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v;
+#define glGetTransformFeedbacki64_v glad_glGetTransformFeedbacki64_v
+GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v;
+#define glGetTransformFeedbacki_v glad_glGetTransformFeedbacki_v
+GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv;
+#define glGetTransformFeedbackiv glad_glGetTransformFeedbackiv
+GLAD_API_CALL PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex;
+#define glGetUniformBlockIndex glad_glGetUniformBlockIndex
+GLAD_API_CALL PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices;
+#define glGetUniformIndices glad_glGetUniformIndices
+GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation;
+#define glGetUniformLocation glad_glGetUniformLocation
+GLAD_API_CALL PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv;
+#define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv
+GLAD_API_CALL PFNGLGETUNIFORMDVPROC glad_glGetUniformdv;
+#define glGetUniformdv glad_glGetUniformdv
+GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv;
+#define glGetUniformfv glad_glGetUniformfv
+GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv;
+#define glGetUniformiv glad_glGetUniformiv
+GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv;
+#define glGetUniformuiv glad_glGetUniformuiv
+GLAD_API_CALL PFNGLGETUNSIGNEDBYTEI_VEXTPROC glad_glGetUnsignedBytei_vEXT;
+#define glGetUnsignedBytei_vEXT glad_glGetUnsignedBytei_vEXT
+GLAD_API_CALL PFNGLGETUNSIGNEDBYTEVEXTPROC glad_glGetUnsignedBytevEXT;
+#define glGetUnsignedBytevEXT glad_glGetUnsignedBytevEXT
+GLAD_API_CALL PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv;
+#define glGetVertexArrayIndexed64iv glad_glGetVertexArrayIndexed64iv
+GLAD_API_CALL PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv;
+#define glGetVertexArrayIndexediv glad_glGetVertexArrayIndexediv
+GLAD_API_CALL PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv;
+#define glGetVertexArrayiv glad_glGetVertexArrayiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv;
+#define glGetVertexAttribIiv glad_glGetVertexAttribIiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv;
+#define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv;
+#define glGetVertexAttribLdv glad_glGetVertexAttribLdv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv;
+#define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv;
+#define glGetVertexAttribdv glad_glGetVertexAttribdv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv;
+#define glGetVertexAttribfv glad_glGetVertexAttribfv
+GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv;
+#define glGetVertexAttribiv glad_glGetVertexAttribiv
+GLAD_API_CALL PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage;
+#define glGetnCompressedTexImage glad_glGetnCompressedTexImage
+GLAD_API_CALL PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage;
+#define glGetnTexImage glad_glGetnTexImage
+GLAD_API_CALL PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv;
+#define glGetnUniformdv glad_glGetnUniformdv
+GLAD_API_CALL PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;
+#define glGetnUniformfv glad_glGetnUniformfv
+GLAD_API_CALL PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;
+#define glGetnUniformiv glad_glGetnUniformiv
+GLAD_API_CALL PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
+#define glGetnUniformuiv glad_glGetnUniformuiv
+GLAD_API_CALL PFNGLHINTPROC glad_glHint;
+#define glHint glad_glHint
+GLAD_API_CALL PFNGLIMPORTMEMORYFDEXTPROC glad_glImportMemoryFdEXT;
+#define glImportMemoryFdEXT glad_glImportMemoryFdEXT
+GLAD_API_CALL PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData;
+#define glInvalidateBufferData glad_glInvalidateBufferData
+GLAD_API_CALL PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData;
+#define glInvalidateBufferSubData glad_glInvalidateBufferSubData
+GLAD_API_CALL PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
+#define glInvalidateFramebuffer glad_glInvalidateFramebuffer
+GLAD_API_CALL PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData;
+#define glInvalidateNamedFramebufferData glad_glInvalidateNamedFramebufferData
+GLAD_API_CALL PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData;
+#define glInvalidateNamedFramebufferSubData glad_glInvalidateNamedFramebufferSubData
+GLAD_API_CALL PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
+#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer
+GLAD_API_CALL PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage;
+#define glInvalidateTexImage glad_glInvalidateTexImage
+GLAD_API_CALL PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage;
+#define glInvalidateTexSubImage glad_glInvalidateTexSubImage
+GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer;
+#define glIsBuffer glad_glIsBuffer
+GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled;
+#define glIsEnabled glad_glIsEnabled
+GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi;
+#define glIsEnabledi glad_glIsEnabledi
+GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer;
+#define glIsFramebuffer glad_glIsFramebuffer
+GLAD_API_CALL PFNGLISMEMORYOBJECTEXTPROC glad_glIsMemoryObjectEXT;
+#define glIsMemoryObjectEXT glad_glIsMemoryObjectEXT
+GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram;
+#define glIsProgram glad_glIsProgram
+GLAD_API_CALL PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
+#define glIsProgramPipeline glad_glIsProgramPipeline
+GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery;
+#define glIsQuery glad_glIsQuery
+GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer;
+#define glIsRenderbuffer glad_glIsRenderbuffer
+GLAD_API_CALL PFNGLISSAMPLERPROC glad_glIsSampler;
+#define glIsSampler glad_glIsSampler
+GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader;
+#define glIsShader glad_glIsShader
+GLAD_API_CALL PFNGLISSYNCPROC glad_glIsSync;
+#define glIsSync glad_glIsSync
+GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture;
+#define glIsTexture glad_glIsTexture
+GLAD_API_CALL PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
+#define glIsTransformFeedback glad_glIsTransformFeedback
+GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray;
+#define glIsVertexArray glad_glIsVertexArray
+GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth;
+#define glLineWidth glad_glLineWidth
+GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram;
+#define glLinkProgram glad_glLinkProgram
+GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp;
+#define glLogicOp glad_glLogicOp
+GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer;
+#define glMapBuffer glad_glMapBuffer
+GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange;
+#define glMapBufferRange glad_glMapBufferRange
+GLAD_API_CALL PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer;
+#define glMapNamedBuffer glad_glMapNamedBuffer
+GLAD_API_CALL PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange;
+#define glMapNamedBufferRange glad_glMapNamedBufferRange
+GLAD_API_CALL PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
+#define glMemoryBarrier glad_glMemoryBarrier
+GLAD_API_CALL PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;
+#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion
+GLAD_API_CALL PFNGLMEMORYOBJECTPARAMETERIVEXTPROC glad_glMemoryObjectParameterivEXT;
+#define glMemoryObjectParameterivEXT glad_glMemoryObjectParameterivEXT
+GLAD_API_CALL PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;
+#define glMinSampleShading glad_glMinSampleShading
+GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays;
+#define glMultiDrawArrays glad_glMultiDrawArrays
+GLAD_API_CALL PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect;
+#define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect
+GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements;
+#define glMultiDrawElements glad_glMultiDrawElements
+GLAD_API_CALL PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex;
+#define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex
+GLAD_API_CALL PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect;
+#define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect
+GLAD_API_CALL PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData;
+#define glNamedBufferData glad_glNamedBufferData
+GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage;
+#define glNamedBufferStorage glad_glNamedBufferStorage
+GLAD_API_CALL PFNGLNAMEDBUFFERSTORAGEMEMEXTPROC glad_glNamedBufferStorageMemEXT;
+#define glNamedBufferStorageMemEXT glad_glNamedBufferStorageMemEXT
+GLAD_API_CALL PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData;
+#define glNamedBufferSubData glad_glNamedBufferSubData
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer;
+#define glNamedFramebufferDrawBuffer glad_glNamedFramebufferDrawBuffer
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers;
+#define glNamedFramebufferDrawBuffers glad_glNamedFramebufferDrawBuffers
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri;
+#define glNamedFramebufferParameteri glad_glNamedFramebufferParameteri
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer;
+#define glNamedFramebufferReadBuffer glad_glNamedFramebufferReadBuffer
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer;
+#define glNamedFramebufferRenderbuffer glad_glNamedFramebufferRenderbuffer
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture;
+#define glNamedFramebufferTexture glad_glNamedFramebufferTexture
+GLAD_API_CALL PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer;
+#define glNamedFramebufferTextureLayer glad_glNamedFramebufferTextureLayer
+GLAD_API_CALL PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage;
+#define glNamedRenderbufferStorage glad_glNamedRenderbufferStorage
+GLAD_API_CALL PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample;
+#define glNamedRenderbufferStorageMultisample glad_glNamedRenderbufferStorageMultisample
+GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel;
+#define glObjectLabel glad_glObjectLabel
+GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
+#define glObjectPtrLabel glad_glObjectPtrLabel
+GLAD_API_CALL PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv;
+#define glPatchParameterfv glad_glPatchParameterfv
+GLAD_API_CALL PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
+#define glPatchParameteri glad_glPatchParameteri
+GLAD_API_CALL PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
+#define glPauseTransformFeedback glad_glPauseTransformFeedback
+GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref;
+#define glPixelStoref glad_glPixelStoref
+GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei;
+#define glPixelStorei glad_glPixelStorei
+GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf;
+#define glPointParameterf glad_glPointParameterf
+GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv;
+#define glPointParameterfv glad_glPointParameterfv
+GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri;
+#define glPointParameteri glad_glPointParameteri
+GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv;
+#define glPointParameteriv glad_glPointParameteriv
+GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize;
+#define glPointSize glad_glPointSize
+GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode;
+#define glPolygonMode glad_glPolygonMode
+GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset;
+#define glPolygonOffset glad_glPolygonOffset
+GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
+#define glPopDebugGroup glad_glPopDebugGroup
+GLAD_API_CALL PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex;
+#define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex
+GLAD_API_CALL PFNGLPROGRAMBINARYPROC glad_glProgramBinary;
+#define glProgramBinary glad_glProgramBinary
+GLAD_API_CALL PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri;
+#define glProgramParameteri glad_glProgramParameteri
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d;
+#define glProgramUniform1d glad_glProgramUniform1d
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv;
+#define glProgramUniform1dv glad_glProgramUniform1dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
+#define glProgramUniform1f glad_glProgramUniform1f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
+#define glProgramUniform1fv glad_glProgramUniform1fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
+#define glProgramUniform1i glad_glProgramUniform1i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
+#define glProgramUniform1iv glad_glProgramUniform1iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
+#define glProgramUniform1ui glad_glProgramUniform1ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
+#define glProgramUniform1uiv glad_glProgramUniform1uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d;
+#define glProgramUniform2d glad_glProgramUniform2d
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv;
+#define glProgramUniform2dv glad_glProgramUniform2dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
+#define glProgramUniform2f glad_glProgramUniform2f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
+#define glProgramUniform2fv glad_glProgramUniform2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
+#define glProgramUniform2i glad_glProgramUniform2i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
+#define glProgramUniform2iv glad_glProgramUniform2iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
+#define glProgramUniform2ui glad_glProgramUniform2ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
+#define glProgramUniform2uiv glad_glProgramUniform2uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d;
+#define glProgramUniform3d glad_glProgramUniform3d
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv;
+#define glProgramUniform3dv glad_glProgramUniform3dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
+#define glProgramUniform3f glad_glProgramUniform3f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
+#define glProgramUniform3fv glad_glProgramUniform3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
+#define glProgramUniform3i glad_glProgramUniform3i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
+#define glProgramUniform3iv glad_glProgramUniform3iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
+#define glProgramUniform3ui glad_glProgramUniform3ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
+#define glProgramUniform3uiv glad_glProgramUniform3uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d;
+#define glProgramUniform4d glad_glProgramUniform4d
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv;
+#define glProgramUniform4dv glad_glProgramUniform4dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
+#define glProgramUniform4f glad_glProgramUniform4f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
+#define glProgramUniform4fv glad_glProgramUniform4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
+#define glProgramUniform4i glad_glProgramUniform4i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
+#define glProgramUniform4iv glad_glProgramUniform4iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
+#define glProgramUniform4ui glad_glProgramUniform4ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
+#define glProgramUniform4uiv glad_glProgramUniform4uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv;
+#define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
+#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv;
+#define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
+#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv;
+#define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
+#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv;
+#define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
+#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv;
+#define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
+#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv;
+#define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
+#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv;
+#define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
+#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv;
+#define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
+#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv;
+#define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
+#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv
+GLAD_API_CALL PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex;
+#define glProvokingVertex glad_glProvokingVertex
+GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
+#define glPushDebugGroup glad_glPushDebugGroup
+GLAD_API_CALL PFNGLQUERYCOUNTERPROC glad_glQueryCounter;
+#define glQueryCounter glad_glQueryCounter
+GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer;
+#define glReadBuffer glad_glReadBuffer
+GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels;
+#define glReadPixels glad_glReadPixels
+GLAD_API_CALL PFNGLREADNPIXELSPROC glad_glReadnPixels;
+#define glReadnPixels glad_glReadnPixels
+GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
+#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
+GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage;
+#define glRenderbufferStorage glad_glRenderbufferStorage
+GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample;
+#define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample
+GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
+#define glResumeTransformFeedback glad_glResumeTransformFeedback
+GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage;
+#define glSampleCoverage glad_glSampleCoverage
+GLAD_API_CALL PFNGLSAMPLEMASKIPROC glad_glSampleMaski;
+#define glSampleMaski glad_glSampleMaski
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv;
+#define glSamplerParameterIiv glad_glSamplerParameterIiv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv;
+#define glSamplerParameterIuiv glad_glSamplerParameterIuiv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf;
+#define glSamplerParameterf glad_glSamplerParameterf
+GLAD_API_CALL PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv;
+#define glSamplerParameterfv glad_glSamplerParameterfv
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri;
+#define glSamplerParameteri glad_glSamplerParameteri
+GLAD_API_CALL PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv;
+#define glSamplerParameteriv glad_glSamplerParameteriv
+GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor;
+#define glScissor glad_glScissor
+GLAD_API_CALL PFNGLSCISSORARRAYVPROC glad_glScissorArrayv;
+#define glScissorArrayv glad_glScissorArrayv
+GLAD_API_CALL PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed;
+#define glScissorIndexed glad_glScissorIndexed
+GLAD_API_CALL PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv;
+#define glScissorIndexedv glad_glScissorIndexedv
+GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary;
+#define glShaderBinary glad_glShaderBinary
+GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource;
+#define glShaderSource glad_glShaderSource
+GLAD_API_CALL PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding;
+#define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding
+GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc;
+#define glStencilFunc glad_glStencilFunc
+GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate;
+#define glStencilFuncSeparate glad_glStencilFuncSeparate
+GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask;
+#define glStencilMask glad_glStencilMask
+GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate;
+#define glStencilMaskSeparate glad_glStencilMaskSeparate
+GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp;
+#define glStencilOp glad_glStencilOp
+GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate;
+#define glStencilOpSeparate glad_glStencilOpSeparate
+GLAD_API_CALL PFNGLTEXBUFFERPROC glad_glTexBuffer;
+#define glTexBuffer glad_glTexBuffer
+GLAD_API_CALL PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
+#define glTexBufferRange glad_glTexBufferRange
+GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D;
+#define glTexImage1D glad_glTexImage1D
+GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D;
+#define glTexImage2D glad_glTexImage2D
+GLAD_API_CALL PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample;
+#define glTexImage2DMultisample glad_glTexImage2DMultisample
+GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D;
+#define glTexImage3D glad_glTexImage3D
+GLAD_API_CALL PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample;
+#define glTexImage3DMultisample glad_glTexImage3DMultisample
+GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv;
+#define glTexParameterIiv glad_glTexParameterIiv
+GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv;
+#define glTexParameterIuiv glad_glTexParameterIuiv
+GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf;
+#define glTexParameterf glad_glTexParameterf
+GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv;
+#define glTexParameterfv glad_glTexParameterfv
+GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri;
+#define glTexParameteri glad_glTexParameteri
+GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv;
+#define glTexParameteriv glad_glTexParameteriv
+GLAD_API_CALL PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D;
+#define glTexStorage1D glad_glTexStorage1D
+GLAD_API_CALL PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
+#define glTexStorage2D glad_glTexStorage2D
+GLAD_API_CALL PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
+#define glTexStorage2DMultisample glad_glTexStorage2DMultisample
+GLAD_API_CALL PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
+#define glTexStorage3D glad_glTexStorage3D
+GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
+#define glTexStorage3DMultisample glad_glTexStorage3DMultisample
+GLAD_API_CALL PFNGLTEXSTORAGEMEM1DEXTPROC glad_glTexStorageMem1DEXT;
+#define glTexStorageMem1DEXT glad_glTexStorageMem1DEXT
+GLAD_API_CALL PFNGLTEXSTORAGEMEM2DEXTPROC glad_glTexStorageMem2DEXT;
+#define glTexStorageMem2DEXT glad_glTexStorageMem2DEXT
+GLAD_API_CALL PFNGLTEXSTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTexStorageMem2DMultisampleEXT;
+#define glTexStorageMem2DMultisampleEXT glad_glTexStorageMem2DMultisampleEXT
+GLAD_API_CALL PFNGLTEXSTORAGEMEM3DEXTPROC glad_glTexStorageMem3DEXT;
+#define glTexStorageMem3DEXT glad_glTexStorageMem3DEXT
+GLAD_API_CALL PFNGLTEXSTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTexStorageMem3DMultisampleEXT;
+#define glTexStorageMem3DMultisampleEXT glad_glTexStorageMem3DMultisampleEXT
+GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D;
+#define glTexSubImage1D glad_glTexSubImage1D
+GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D;
+#define glTexSubImage2D glad_glTexSubImage2D
+GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D;
+#define glTexSubImage3D glad_glTexSubImage3D
+GLAD_API_CALL PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier;
+#define glTextureBarrier glad_glTextureBarrier
+GLAD_API_CALL PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer;
+#define glTextureBuffer glad_glTextureBuffer
+GLAD_API_CALL PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange;
+#define glTextureBufferRange glad_glTextureBufferRange
+GLAD_API_CALL PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv;
+#define glTextureParameterIiv glad_glTextureParameterIiv
+GLAD_API_CALL PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv;
+#define glTextureParameterIuiv glad_glTextureParameterIuiv
+GLAD_API_CALL PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf;
+#define glTextureParameterf glad_glTextureParameterf
+GLAD_API_CALL PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv;
+#define glTextureParameterfv glad_glTextureParameterfv
+GLAD_API_CALL PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri;
+#define glTextureParameteri glad_glTextureParameteri
+GLAD_API_CALL PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv;
+#define glTextureParameteriv glad_glTextureParameteriv
+GLAD_API_CALL PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D;
+#define glTextureStorage1D glad_glTextureStorage1D
+GLAD_API_CALL PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D;
+#define glTextureStorage2D glad_glTextureStorage2D
+GLAD_API_CALL PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample;
+#define glTextureStorage2DMultisample glad_glTextureStorage2DMultisample
+GLAD_API_CALL PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D;
+#define glTextureStorage3D glad_glTextureStorage3D
+GLAD_API_CALL PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample;
+#define glTextureStorage3DMultisample glad_glTextureStorage3DMultisample
+GLAD_API_CALL PFNGLTEXTURESTORAGEMEM1DEXTPROC glad_glTextureStorageMem1DEXT;
+#define glTextureStorageMem1DEXT glad_glTextureStorageMem1DEXT
+GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DEXTPROC glad_glTextureStorageMem2DEXT;
+#define glTextureStorageMem2DEXT glad_glTextureStorageMem2DEXT
+GLAD_API_CALL PFNGLTEXTURESTORAGEMEM2DMULTISAMPLEEXTPROC glad_glTextureStorageMem2DMultisampleEXT;
+#define glTextureStorageMem2DMultisampleEXT glad_glTextureStorageMem2DMultisampleEXT
+GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DEXTPROC glad_glTextureStorageMem3DEXT;
+#define glTextureStorageMem3DEXT glad_glTextureStorageMem3DEXT
+GLAD_API_CALL PFNGLTEXTURESTORAGEMEM3DMULTISAMPLEEXTPROC glad_glTextureStorageMem3DMultisampleEXT;
+#define glTextureStorageMem3DMultisampleEXT glad_glTextureStorageMem3DMultisampleEXT
+GLAD_API_CALL PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D;
+#define glTextureSubImage1D glad_glTextureSubImage1D
+GLAD_API_CALL PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D;
+#define glTextureSubImage2D glad_glTextureSubImage2D
+GLAD_API_CALL PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D;
+#define glTextureSubImage3D glad_glTextureSubImage3D
+GLAD_API_CALL PFNGLTEXTUREVIEWPROC glad_glTextureView;
+#define glTextureView glad_glTextureView
+GLAD_API_CALL PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase;
+#define glTransformFeedbackBufferBase glad_glTransformFeedbackBufferBase
+GLAD_API_CALL PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange;
+#define glTransformFeedbackBufferRange glad_glTransformFeedbackBufferRange
+GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings;
+#define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings
+GLAD_API_CALL PFNGLUNIFORM1DPROC glad_glUniform1d;
+#define glUniform1d glad_glUniform1d
+GLAD_API_CALL PFNGLUNIFORM1DVPROC glad_glUniform1dv;
+#define glUniform1dv glad_glUniform1dv
+GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f;
+#define glUniform1f glad_glUniform1f
+GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv;
+#define glUniform1fv glad_glUniform1fv
+GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i;
+#define glUniform1i glad_glUniform1i
+GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv;
+#define glUniform1iv glad_glUniform1iv
+GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui;
+#define glUniform1ui glad_glUniform1ui
+GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv;
+#define glUniform1uiv glad_glUniform1uiv
+GLAD_API_CALL PFNGLUNIFORM2DPROC glad_glUniform2d;
+#define glUniform2d glad_glUniform2d
+GLAD_API_CALL PFNGLUNIFORM2DVPROC glad_glUniform2dv;
+#define glUniform2dv glad_glUniform2dv
+GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f;
+#define glUniform2f glad_glUniform2f
+GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv;
+#define glUniform2fv glad_glUniform2fv
+GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i;
+#define glUniform2i glad_glUniform2i
+GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv;
+#define glUniform2iv glad_glUniform2iv
+GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui;
+#define glUniform2ui glad_glUniform2ui
+GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv;
+#define glUniform2uiv glad_glUniform2uiv
+GLAD_API_CALL PFNGLUNIFORM3DPROC glad_glUniform3d;
+#define glUniform3d glad_glUniform3d
+GLAD_API_CALL PFNGLUNIFORM3DVPROC glad_glUniform3dv;
+#define glUniform3dv glad_glUniform3dv
+GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f;
+#define glUniform3f glad_glUniform3f
+GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv;
+#define glUniform3fv glad_glUniform3fv
+GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i;
+#define glUniform3i glad_glUniform3i
+GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv;
+#define glUniform3iv glad_glUniform3iv
+GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui;
+#define glUniform3ui glad_glUniform3ui
+GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv;
+#define glUniform3uiv glad_glUniform3uiv
+GLAD_API_CALL PFNGLUNIFORM4DPROC glad_glUniform4d;
+#define glUniform4d glad_glUniform4d
+GLAD_API_CALL PFNGLUNIFORM4DVPROC glad_glUniform4dv;
+#define glUniform4dv glad_glUniform4dv
+GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f;
+#define glUniform4f glad_glUniform4f
+GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv;
+#define glUniform4fv glad_glUniform4fv
+GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i;
+#define glUniform4i glad_glUniform4i
+GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv;
+#define glUniform4iv glad_glUniform4iv
+GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui;
+#define glUniform4ui glad_glUniform4ui
+GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv;
+#define glUniform4uiv glad_glUniform4uiv
+GLAD_API_CALL PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding;
+#define glUniformBlockBinding glad_glUniformBlockBinding
+GLAD_API_CALL PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv;
+#define glUniformMatrix2dv glad_glUniformMatrix2dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv;
+#define glUniformMatrix2fv glad_glUniformMatrix2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv;
+#define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv;
+#define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv;
+#define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv;
+#define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv;
+#define glUniformMatrix3dv glad_glUniformMatrix3dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv;
+#define glUniformMatrix3fv glad_glUniformMatrix3fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv;
+#define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv;
+#define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv;
+#define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv;
+#define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv;
+#define glUniformMatrix4dv glad_glUniformMatrix4dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv;
+#define glUniformMatrix4fv glad_glUniformMatrix4fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv;
+#define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv;
+#define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv;
+#define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv
+GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv;
+#define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv
+GLAD_API_CALL PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv;
+#define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv
+GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer;
+#define glUnmapBuffer glad_glUnmapBuffer
+GLAD_API_CALL PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer;
+#define glUnmapNamedBuffer glad_glUnmapNamedBuffer
+GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram;
+#define glUseProgram glad_glUseProgram
+GLAD_API_CALL PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
+#define glUseProgramStages glad_glUseProgramStages
+GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram;
+#define glValidateProgram glad_glValidateProgram
+GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
+#define glValidateProgramPipeline glad_glValidateProgramPipeline
+GLAD_API_CALL PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding;
+#define glVertexArrayAttribBinding glad_glVertexArrayAttribBinding
+GLAD_API_CALL PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat;
+#define glVertexArrayAttribFormat glad_glVertexArrayAttribFormat
+GLAD_API_CALL PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat;
+#define glVertexArrayAttribIFormat glad_glVertexArrayAttribIFormat
+GLAD_API_CALL PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat;
+#define glVertexArrayAttribLFormat glad_glVertexArrayAttribLFormat
+GLAD_API_CALL PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor;
+#define glVertexArrayBindingDivisor glad_glVertexArrayBindingDivisor
+GLAD_API_CALL PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer;
+#define glVertexArrayElementBuffer glad_glVertexArrayElementBuffer
+GLAD_API_CALL PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer;
+#define glVertexArrayVertexBuffer glad_glVertexArrayVertexBuffer
+GLAD_API_CALL PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers;
+#define glVertexArrayVertexBuffers glad_glVertexArrayVertexBuffers
+GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d;
+#define glVertexAttrib1d glad_glVertexAttrib1d
+GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv;
+#define glVertexAttrib1dv glad_glVertexAttrib1dv
+GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f;
+#define glVertexAttrib1f glad_glVertexAttrib1f
+GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv;
+#define glVertexAttrib1fv glad_glVertexAttrib1fv
+GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s;
+#define glVertexAttrib1s glad_glVertexAttrib1s
+GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv;
+#define glVertexAttrib1sv glad_glVertexAttrib1sv
+GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d;
+#define glVertexAttrib2d glad_glVertexAttrib2d
+GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv;
+#define glVertexAttrib2dv glad_glVertexAttrib2dv
+GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f;
+#define glVertexAttrib2f glad_glVertexAttrib2f
+GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv;
+#define glVertexAttrib2fv glad_glVertexAttrib2fv
+GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s;
+#define glVertexAttrib2s glad_glVertexAttrib2s
+GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv;
+#define glVertexAttrib2sv glad_glVertexAttrib2sv
+GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d;
+#define glVertexAttrib3d glad_glVertexAttrib3d
+GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv;
+#define glVertexAttrib3dv glad_glVertexAttrib3dv
+GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f;
+#define glVertexAttrib3f glad_glVertexAttrib3f
+GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv;
+#define glVertexAttrib3fv glad_glVertexAttrib3fv
+GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s;
+#define glVertexAttrib3s glad_glVertexAttrib3s
+GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv;
+#define glVertexAttrib3sv glad_glVertexAttrib3sv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv;
+#define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv;
+#define glVertexAttrib4Niv glad_glVertexAttrib4Niv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv;
+#define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub;
+#define glVertexAttrib4Nub glad_glVertexAttrib4Nub
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv;
+#define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv;
+#define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv
+GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv;
+#define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv
+GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv;
+#define glVertexAttrib4bv glad_glVertexAttrib4bv
+GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d;
+#define glVertexAttrib4d glad_glVertexAttrib4d
+GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv;
+#define glVertexAttrib4dv glad_glVertexAttrib4dv
+GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f;
+#define glVertexAttrib4f glad_glVertexAttrib4f
+GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv;
+#define glVertexAttrib4fv glad_glVertexAttrib4fv
+GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv;
+#define glVertexAttrib4iv glad_glVertexAttrib4iv
+GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s;
+#define glVertexAttrib4s glad_glVertexAttrib4s
+GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv;
+#define glVertexAttrib4sv glad_glVertexAttrib4sv
+GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv;
+#define glVertexAttrib4ubv glad_glVertexAttrib4ubv
+GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv;
+#define glVertexAttrib4uiv glad_glVertexAttrib4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv;
+#define glVertexAttrib4usv glad_glVertexAttrib4usv
+GLAD_API_CALL PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
+#define glVertexAttribBinding glad_glVertexAttribBinding
+GLAD_API_CALL PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor;
+#define glVertexAttribDivisor glad_glVertexAttribDivisor
+GLAD_API_CALL PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
+#define glVertexAttribFormat glad_glVertexAttribFormat
+GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i;
+#define glVertexAttribI1i glad_glVertexAttribI1i
+GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv;
+#define glVertexAttribI1iv glad_glVertexAttribI1iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui;
+#define glVertexAttribI1ui glad_glVertexAttribI1ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv;
+#define glVertexAttribI1uiv glad_glVertexAttribI1uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i;
+#define glVertexAttribI2i glad_glVertexAttribI2i
+GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv;
+#define glVertexAttribI2iv glad_glVertexAttribI2iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui;
+#define glVertexAttribI2ui glad_glVertexAttribI2ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv;
+#define glVertexAttribI2uiv glad_glVertexAttribI2uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i;
+#define glVertexAttribI3i glad_glVertexAttribI3i
+GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv;
+#define glVertexAttribI3iv glad_glVertexAttribI3iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui;
+#define glVertexAttribI3ui glad_glVertexAttribI3ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv;
+#define glVertexAttribI3uiv glad_glVertexAttribI3uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv;
+#define glVertexAttribI4bv glad_glVertexAttribI4bv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i;
+#define glVertexAttribI4i glad_glVertexAttribI4i
+GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv;
+#define glVertexAttribI4iv glad_glVertexAttribI4iv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv;
+#define glVertexAttribI4sv glad_glVertexAttribI4sv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv;
+#define glVertexAttribI4ubv glad_glVertexAttribI4ubv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui;
+#define glVertexAttribI4ui glad_glVertexAttribI4ui
+GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv;
+#define glVertexAttribI4uiv glad_glVertexAttribI4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv;
+#define glVertexAttribI4usv glad_glVertexAttribI4usv
+GLAD_API_CALL PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
+#define glVertexAttribIFormat glad_glVertexAttribIFormat
+GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer;
+#define glVertexAttribIPointer glad_glVertexAttribIPointer
+GLAD_API_CALL PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d;
+#define glVertexAttribL1d glad_glVertexAttribL1d
+GLAD_API_CALL PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv;
+#define glVertexAttribL1dv glad_glVertexAttribL1dv
+GLAD_API_CALL PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d;
+#define glVertexAttribL2d glad_glVertexAttribL2d
+GLAD_API_CALL PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv;
+#define glVertexAttribL2dv glad_glVertexAttribL2dv
+GLAD_API_CALL PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d;
+#define glVertexAttribL3d glad_glVertexAttribL3d
+GLAD_API_CALL PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv;
+#define glVertexAttribL3dv glad_glVertexAttribL3dv
+GLAD_API_CALL PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d;
+#define glVertexAttribL4d glad_glVertexAttribL4d
+GLAD_API_CALL PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv;
+#define glVertexAttribL4dv glad_glVertexAttribL4dv
+GLAD_API_CALL PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat;
+#define glVertexAttribLFormat glad_glVertexAttribLFormat
+GLAD_API_CALL PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer;
+#define glVertexAttribLPointer glad_glVertexAttribLPointer
+GLAD_API_CALL PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui;
+#define glVertexAttribP1ui glad_glVertexAttribP1ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv;
+#define glVertexAttribP1uiv glad_glVertexAttribP1uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui;
+#define glVertexAttribP2ui glad_glVertexAttribP2ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv;
+#define glVertexAttribP2uiv glad_glVertexAttribP2uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui;
+#define glVertexAttribP3ui glad_glVertexAttribP3ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv;
+#define glVertexAttribP3uiv glad_glVertexAttribP3uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui;
+#define glVertexAttribP4ui glad_glVertexAttribP4ui
+GLAD_API_CALL PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv;
+#define glVertexAttribP4uiv glad_glVertexAttribP4uiv
+GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer;
+#define glVertexAttribPointer glad_glVertexAttribPointer
+GLAD_API_CALL PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
+#define glVertexBindingDivisor glad_glVertexBindingDivisor
+GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport;
+#define glViewport glad_glViewport
+GLAD_API_CALL PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv;
+#define glViewportArrayv glad_glViewportArrayv
+GLAD_API_CALL PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf;
+#define glViewportIndexedf glad_glViewportIndexedf
+GLAD_API_CALL PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv;
+#define glViewportIndexedfv glad_glViewportIndexedfv
+GLAD_API_CALL PFNGLWAITSYNCPROC glad_glWaitSync;
+#define glWaitSync glad_glWaitSync
+
+
+GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr);
+GLAD_API_CALL int gladLoadGL( GLADloadfunc load);
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/external/openxr_includes/loader_interfaces.h b/src/external/openxr_includes/loader_interfaces.h
new file mode 100644
index 000000000..3dda953e3
--- /dev/null
+++ b/src/external/openxr_includes/loader_interfaces.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2017 The Khronos Group Inc.
+// Copyright (c) 2017 Valve Corporation
+// Copyright (c) 2017 LunarG, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Author: Mark Young <marky@lunarg.com>
+//
+
+#pragma once
+
+#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;
+    uint32_t minXrVersion;
+    uint32_t maxXrVersion;
+} 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
+    uint32_t layerXrVersion;
+    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
+    uint32_t runtimeXrVersion;
+    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
diff --git a/src/external/openxr_includes/openxr.h b/src/external/openxr_includes/openxr.h
new file mode 100644
index 000000000..4744a7eac
--- /dev/null
+++ b/src/external/openxr_includes/openxr.h
@@ -0,0 +1,1479 @@
+#ifndef OPENXR_H_
+#define OPENXR_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2017-2019 The Khronos Group Inc.
+**
+** 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.
+*/
+
+/*
+** This header is generated from the Khronos OpenXR XML API Registry.
+**
+*/
+
+
+
+#define XR_VERSION_0_90 1
+#include "openxr_platform_defines.h"
+#define XR_MAKE_VERSION(major, minor, patch) \
+    (((major) << 22) | ((minor) << 12) | (patch))
+
+// OpenXR current version number.
+#define XR_CURRENT_API_VERSION XR_MAKE_VERSION(0, 90, 0)
+
+#define XR_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
+#define XR_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
+#define XR_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
+// Version of this file
+#define XR_HEADER_VERSION 42
+
+
+#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 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_TOUCH_COUNT                2
+#define XR_MAX_ACTION_SOURCES_COUNT       8
+#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_VISIBILITY_UNAVAILABLE = 2,
+    XR_SESSION_LOSS_PENDING = 3,
+    XR_EVENT_UNAVAILABLE = 4,
+    XR_STATE_UNAVAILABLE = 5,
+    XR_STATE_TYPE_UNAVAILABLE = 6,
+    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_RUNTIME_VERSION_INCOMPATIBLE = -4,
+    XR_ERROR_DRIVER_INCOMPATIBLE = -5,
+    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_LAYER_INVALID = -22,
+    XR_ERROR_LAYER_LIMIT_EXCEEDED = -23,
+    XR_ERROR_SWAPCHAIN_RECT_INVALID = -25,
+    XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED = -26,
+    XR_ERROR_ACTION_TYPE_MISMATCH = -27,
+    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_BINDINGS_DUPLICATED = -43,
+    XR_ERROR_NAME_DUPLICATED = -44,
+    XR_ERROR_NAME_INVALID = -45,
+    XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR = -1000003000,
+    XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR = -1000003001,
+    XR_ERROR_DEBUG_UTILS_MESSENGER_INVALID_EXT = -1000019000,
+    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_VECTOR1F = 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_SPACE_RELATION = 39,
+    XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING = 40,
+    XR_TYPE_VIEW_CONFIGURATION_VIEW = 41,
+    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_INFO = 53,
+    XR_TYPE_ACTIVE_ACTION_SET = 54,
+    XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO = 55,
+    XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO = 56,
+    XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO = 57,
+    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_D3D10_KHR = 1000026000,
+    XR_TYPE_SWAPCHAIN_IMAGE_D3D10_KHR = 1000026001,
+    XR_TYPE_GRAPHICS_REQUIREMENTS_D3D10_KHR = 1000026002,
+    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_VISIBILITY_MASK_KHR = 1000031000,
+    XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR = 1000031001,
+    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 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_MAX_ENUM = 0x7FFFFFFF
+} XrReferenceSpaceType;
+
+typedef enum XrViewConfigurationType {
+    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO = 1,
+    XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO = 2,
+    XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM = 0x7FFFFFFF
+} XrViewConfigurationType;
+
+typedef enum XrActionType {
+    XR_INPUT_ACTION_TYPE_BOOLEAN = 1,
+    XR_INPUT_ACTION_TYPE_VECTOR1F = 2,
+    XR_INPUT_ACTION_TYPE_VECTOR2F = 3,
+    XR_INPUT_ACTION_TYPE_POSE = 4,
+    XR_OUTPUT_ACTION_TYPE_VIBRATION = 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_RUNNING = 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_MAX_ENUM = 0x7FFFFFFF
+} XrObjectType;
+typedef XrFlags64 XrInstanceCreateFlags;
+
+// Flag bits for XrInstanceCreateFlags
+
+typedef XrFlags64 XrSessionCreateFlags;
+
+// Flag bits for XrSessionCreateFlags
+
+typedef XrFlags64 XrSpaceRelationFlags;
+
+// Flag bits for XrSpaceRelationFlags
+static const XrSpaceRelationFlags XR_SPACE_RELATION_ORIENTATION_VALID_BIT = 0x00000001;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_POSITION_VALID_BIT = 0x00000002;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT = 0x00000004;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT = 0x00000008;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT = 0x00000010;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT = 0x00000020;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_ORIENTATION_TRACKED_BIT = 0x00000040;
+static const XrSpaceRelationFlags XR_SPACE_RELATION_POSITION_TRACKED_BIT = 0x00000080;
+
+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;
+
+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;
+
+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];
+    uint32_t              specVersion;
+    uint32_t              implementationVersion;
+    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              specVersion;
+} XrExtensionProperties;
+
+typedef struct XrApplicationInfo {
+    char        applicationName[XR_MAX_APPLICATION_NAME_SIZE];
+    uint32_t    applicationVersion;
+    char        engineName[XR_MAX_ENGINE_NAME_SIZE];
+    uint32_t    engineVersion;
+    uint32_t    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;
+    uint32_t              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;
+    void* XR_MAY_ALIAS    next;
+    XrFormFactor          formFactor;
+} XrSystemGetInfo;
+
+typedef struct XrSystemGraphicsProperties {
+    uint32_t    maxSwapchainImageHeight;
+    uint32_t    maxSwapchainImageWidth;
+    uint32_t    maxViewCount;
+    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 XrQuaternionf {
+    float    x;
+    float    y;
+    float    z;
+    float    w;
+} XrQuaternionf;
+
+typedef struct XrVector3f {
+    float    x;
+    float    y;
+    float    z;
+} XrVector3f;
+
+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;
+    XrPath                      subactionPath;
+    XrPosef                     poseInActionSpace;
+} XrActionSpaceCreateInfo;
+
+typedef struct XrSpaceRelation {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    XrSpaceRelationFlags    relationFlags;
+    XrTime                  time;
+    XrPosef                 pose;
+    XrVector3f              linearVelocity;
+    XrVector3f              angularVelocity;
+    XrVector3f              linearAcceleration;
+    XrVector3f              angularAcceleration;
+} XrSpaceRelation;
+
+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;
+} 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;
+    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 XrInteractionProfileInfo {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrPath                      interactionProfile;
+} XrInteractionProfileInfo;
+
+typedef struct XrActionStateBoolean {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    XrBool32              currentState;
+    XrBool32              changedSinceLastSync;
+    XrTime                lastChangeTime;
+    XrBool32              isActive;
+} XrActionStateBoolean;
+
+typedef struct XrActionStateVector1f {
+    XrStructureType       type;
+    void* XR_MAY_ALIAS    next;
+    float                 currentState;
+    XrBool32              changedSinceLastSync;
+    XrTime                lastChangeTime;
+    XrBool32              isActive;
+} XrActionStateVector1f;
+
+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 {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    XrActionSet                 actionSet;
+    XrPath                      subactionPath;
+} XrActiveActionSet;
+
+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;
+    XrVector2f                  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;
+    XrReferenceSpaceType        referenceSpaceType;
+    XrTime                      changeTime;
+    XrBool32                    poseValid;
+    XrPosef                     poseInPreviousSpace;
+} XrEventDataReferenceSpaceChangePending;
+
+typedef struct XrEventDataInteractionProfileChanged {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+} 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, 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)(XrAction action, const XrActionSpaceCreateInfo* createInfo, XrSpace* space);
+typedef XrResult (XRAPI_PTR *PFN_xrLocateSpace)(XrSpace space, XrSpace baseSpace, XrTime   time, XrSpaceRelation* relation);
+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_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)(XrSession session, 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_xrSetInteractionProfileSuggestedBindings)(XrSession session, const XrInteractionProfileSuggestedBinding* suggestedBindings);
+typedef XrResult (XRAPI_PTR *PFN_xrGetCurrentInteractionProfile)(XrSession session, XrPath topLevelUserPath, XrInteractionProfileInfo* interactionProfile);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateBoolean)(XrAction action, uint32_t countSubactionPaths, const XrPath* subactionPaths, XrActionStateBoolean* data);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector1f)(XrAction action, uint32_t countSubactionPaths, const XrPath* subactionPaths, XrActionStateVector1f* data);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStateVector2f)(XrAction action, uint32_t countSubactionPaths, const XrPath* subactionPaths, XrActionStateVector2f* data);
+typedef XrResult (XRAPI_PTR *PFN_xrGetActionStatePose)(XrAction action, XrPath subactionPath, XrActionStatePose* data);
+typedef XrResult (XRAPI_PTR *PFN_xrSyncActionData)(XrSession session, uint32_t countActionSets, const XrActiveActionSet* actionSets);
+typedef XrResult (XRAPI_PTR *PFN_xrGetBoundSourcesForAction)(XrAction action, uint32_t sourceCapacityInput, uint32_t* sourceCountOutput, XrPath* sources);
+typedef XrResult (XRAPI_PTR *PFN_xrGetInputSourceLocalizedName)(XrSession session, XrPath source, XrInputSourceLocalizedNameFlags whichComponents, uint32_t bufferCapacityInput, uint32_t* bufferCountOutput, char* buffer);
+typedef XrResult (XRAPI_PTR *PFN_xrApplyHapticFeedback)(XrAction hapticAction, uint32_t countSubactionPaths, const XrPath* subactionPaths, const XrHapticBaseHeader* hapticEvent);
+typedef XrResult (XRAPI_PTR *PFN_xrStopHapticFeedback)(XrAction hapticAction, uint32_t countSubactionPaths, const XrPath* subactionPaths);
+
+#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,
+    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(
+    XrAction                                    action,
+    const XrActionSpaceCreateInfo*              createInfo,
+    XrSpace*                                    space);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrLocateSpace(
+    XrSpace                                     space,
+    XrSpace                                     baseSpace,
+    XrTime                                      time,
+    XrSpaceRelation*                            relation);
+
+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 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(
+    XrSession                                   session,
+    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 xrSetInteractionProfileSuggestedBindings(
+    XrSession                                   session,
+    const XrInteractionProfileSuggestedBinding* suggestedBindings);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetCurrentInteractionProfile(
+    XrSession                                   session,
+    XrPath                                      topLevelUserPath,
+    XrInteractionProfileInfo*                   interactionProfile);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateBoolean(
+    XrAction                                    action,
+    uint32_t                                    countSubactionPaths,
+    const XrPath*                               subactionPaths,
+    XrActionStateBoolean*                       data);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector1f(
+    XrAction                                    action,
+    uint32_t                                    countSubactionPaths,
+    const XrPath*                               subactionPaths,
+    XrActionStateVector1f*                      data);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStateVector2f(
+    XrAction                                    action,
+    uint32_t                                    countSubactionPaths,
+    const XrPath*                               subactionPaths,
+    XrActionStateVector2f*                      data);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetActionStatePose(
+    XrAction                                    action,
+    XrPath                                      subactionPath,
+    XrActionStatePose*                          data);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrSyncActionData(
+    XrSession                                   session,
+    uint32_t                                    countActionSets,
+    const XrActiveActionSet*                    actionSets);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetBoundSourcesForAction(
+    XrAction                                    action,
+    uint32_t                                    sourceCapacityInput,
+    uint32_t*                                   sourceCountOutput,
+    XrPath*                                     sources);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetInputSourceLocalizedName(
+    XrSession                                   session,
+    XrPath                                      source,
+    XrInputSourceLocalizedNameFlags             whichComponents,
+    uint32_t                                    bufferCapacityInput,
+    uint32_t*                                   bufferCountOutput,
+    char*                                       buffer);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrApplyHapticFeedback(
+    XrAction                                    hapticAction,
+    uint32_t                                    countSubactionPaths,
+    const XrPath*                               subactionPaths,
+    const XrHapticBaseHeader*                   hapticEvent);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrStopHapticFeedback(
+    XrAction                                    hapticAction,
+    uint32_t                                    countSubactionPaths,
+    const XrPath*                               subactionPaths);
+#endif
+
+
+#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;
+    XrVector3f                  offset;
+} 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"
+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_headless 1
+#define XR_KHR_headless_SPEC_VERSION      2
+#define XR_KHR_HEADLESS_EXTENSION_NAME    "XR_KHR_headless"
+
+
+#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;
+    XrVector3f                  offset;
+    XrVector2f                  scale;
+    XrVector2f                  bias;
+} XrCompositionLayerEquirectKHR;
+
+
+
+#define XR_KHR_visibility_mask 1
+#define XR_KHR_visibility_mask_SPEC_VERSION 1
+#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              vertexCount;
+    XrVector2f*           vertices;
+    uint32_t              indexCount;
+    uint32_t*             indices;
+} XrVisibilityMaskKHR;
+
+typedef struct XrEventDataVisibilityMaskChangedKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    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
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVisibilityMaskKHR(
+    XrSession                                   session,
+    XrViewConfigurationType                     viewConfigurationType,
+    uint32_t                                    viewIndex,
+    XrVisibilityMaskTypeKHR                     visibilityMaskType,
+    XrVisibilityMaskKHR*                        visibilityMask);
+#endif
+
+
+#define XR_EXT_performance_settings 1
+#define XR_EXT_performance_settings_SPEC_VERSION 1
+#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
+XRAPI_ATTR XrResult XRAPI_CALL xrPerfSettingsSetPerformanceLevelEXT(
+    XrSession                                   session,
+    XrPerfSettingsDomainEXT                     domain,
+    XrPerfSettingsLevelEXT                      level);
+#endif
+
+
+#define XR_EXT_thermal_query 1
+#define XR_EXT_thermal_query_SPEC_VERSION 1
+#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
+XRAPI_ATTR XrResult XRAPI_CALL xrThermalGetTemperatureTrendEXT(
+    XrSession                                   session,
+    XrPerfSettingsDomainEXT                     domain,
+    XrPerfSettingsNotificationLevelEXT*         notificationLevel,
+    float*                                      tempHeadroom,
+    float*                                      tempSlope);
+#endif
+
+
+#define XR_EXT_debug_utils 1
+XR_DEFINE_HANDLE(XrDebugUtilsMessengerEXT)
+#define XR_EXT_debug_utils_SPEC_VERSION   2
+#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;
+
+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);
+        
+
+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
+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
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/external/openxr_includes/openxr_platform.h b/src/external/openxr_includes/openxr_platform.h
new file mode 100644
index 000000000..e0db2a047
--- /dev/null
+++ b/src/external/openxr_includes/openxr_platform.h
@@ -0,0 +1,415 @@
+#ifndef OPENXR_PLATFORM_H_
+#define OPENXR_PLATFORM_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2017-2019 The Khronos Group Inc.
+**
+** 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.
+*/
+
+/*
+** This header is generated from the Khronos OpenXR XML API Registry.
+**
+*/
+
+
+#ifdef XR_USE_PLATFORM_ANDROID
+
+#define XR_KHR_android_thread_settings 1
+#define XR_KHR_android_thread_settings_SPEC_VERSION 4
+#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
+XRAPI_ATTR XrResult XRAPI_CALL xrSetAndroidApplicationThreadKHR(
+    XrSession                                   session,
+    XrAndroidThreadTypeKHR                      threadType,
+    uint32_t                                    threadId);
+#endif
+#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
+XRAPI_ATTR XrResult XRAPI_CALL xrCreateSwapchainAndroidSurfaceKHR(
+    XrSession                                   session,
+    const XrSwapchainCreateInfo*                info,
+    XrSwapchain*                                swapchain,
+    jobject*                                    surface);
+#endif
+#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 2
+#define XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME "XR_KHR_android_create_instance"
+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 1
+#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 1
+#define XR_KHR_OPENGL_ENABLE_EXTENSION_NAME "XR_KHR_opengl_enable"
+#ifdef XR_USE_PLATFORM_WIN32
+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
+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
+typedef struct XrGraphicsBindingOpenGLXcbKHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    xcb_connection_t*           connection;
+    uint32_t                    screen_number;
+    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
+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;
+    uint32_t              minApiVersionSupported;
+    uint32_t              maxApiVersionSupported;
+} XrGraphicsRequirementsOpenGLKHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
+
+#ifndef XR_NO_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLGraphicsRequirementsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrGraphicsRequirementsOpenGLKHR*            graphicsRequirements);
+#endif
+#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 1
+#define XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME "XR_KHR_opengl_es_enable"
+#ifdef XR_USE_PLATFORM_ANDROID
+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;
+    uint32_t              minApiVersionSupported;
+    uint32_t              maxApiVersionSupported;
+} XrGraphicsRequirementsOpenGLESKHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetOpenGLESGraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsOpenGLESKHR* graphicsRequirements);
+
+#ifndef XR_NO_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetOpenGLESGraphicsRequirementsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrGraphicsRequirementsOpenGLESKHR*          graphicsRequirements);
+#endif
+#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 6
+#define XR_KHR_VULKAN_ENABLE_EXTENSION_NAME "XR_KHR_vulkan_enable"
+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;
+    uint32_t              minApiVersionSupported;
+    uint32_t              maxApiVersionSupported;
+} XrGraphicsRequirementsVulkanKHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanInstanceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t namesCapacityInput, uint32_t* namesCountOutput, char* namesString);
+typedef XrResult (XRAPI_PTR *PFN_xrGetVulkanDeviceExtensionsKHR)(XrInstance instance, XrSystemId systemId, uint32_t namesCapacityInput, uint32_t* namesCountOutput, char* namesString);
+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
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanInstanceExtensionsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    uint32_t                                    namesCapacityInput,
+    uint32_t*                                   namesCountOutput,
+    char*                                       namesString);
+
+XRAPI_ATTR XrResult XRAPI_CALL xrGetVulkanDeviceExtensionsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    uint32_t                                    namesCapacityInput,
+    uint32_t*                                   namesCountOutput,
+    char*                                       namesString);
+
+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
+#endif /* XR_USE_GRAPHICS_API_VULKAN */
+
+#ifdef XR_USE_GRAPHICS_API_D3D10
+
+#define XR_KHR_D3D10_enable 1
+#define XR_KHR_D3D10_enable_SPEC_VERSION  1
+#define XR_KHR_D3D10_ENABLE_EXTENSION_NAME "XR_KHR_D3D10_enable"
+typedef struct XrGraphicsBindingD3D10KHR {
+    XrStructureType             type;
+    const void* XR_MAY_ALIAS    next;
+    ID3D10Device*               device;
+} XrGraphicsBindingD3D10KHR;
+
+typedef struct XrSwapchainImageD3D10KHR {
+     XrStructureType      type;
+    void* XR_MAY_ALIAS    next;
+    ID3D10Texture2D*      texture;
+} XrSwapchainImageD3D10KHR;
+
+typedef struct XrGraphicsRequirementsD3D10KHR {
+    XrStructureType         type;
+    void* XR_MAY_ALIAS      next;
+    LUID                    adapterLuid;
+    D3D10_FEATURE_LEVEL1    minFeatureLevel;
+} XrGraphicsRequirementsD3D10KHR;
+
+typedef XrResult (XRAPI_PTR *PFN_xrGetD3D10GraphicsRequirementsKHR)(XrInstance instance, XrSystemId systemId, XrGraphicsRequirementsD3D10KHR* graphicsRequirements);
+
+#ifndef XR_NO_PROTOTYPES
+XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D10GraphicsRequirementsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrGraphicsRequirementsD3D10KHR*             graphicsRequirements);
+#endif
+#endif /* XR_USE_GRAPHICS_API_D3D10 */
+
+#ifdef XR_USE_GRAPHICS_API_D3D11
+
+#define XR_KHR_D3D11_enable 1
+#define XR_KHR_D3D11_enable_SPEC_VERSION  1
+#define XR_KHR_D3D11_ENABLE_EXTENSION_NAME "XR_KHR_D3D11_enable"
+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
+XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D11GraphicsRequirementsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrGraphicsRequirementsD3D11KHR*             graphicsRequirements);
+#endif
+#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  1
+#define XR_KHR_D3D12_ENABLE_EXTENSION_NAME "XR_KHR_D3D12_enable"
+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
+XRAPI_ATTR XrResult XRAPI_CALL xrGetD3D12GraphicsRequirementsKHR(
+    XrInstance                                  instance,
+    XrSystemId                                  systemId,
+    XrGraphicsRequirementsD3D12KHR*             graphicsRequirements);
+#endif
+#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
+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
+#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
+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
+#endif /* XR_USE_TIMESPEC */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/external/openxr_includes/openxr_platform_defines.h b/src/external/openxr_includes/openxr_platform_defines.h
new file mode 100644
index 000000000..f2ba2ab37
--- /dev/null
+++ b/src/external/openxr_includes/openxr_platform_defines.h
@@ -0,0 +1,120 @@
+/*
+** Copyright (c) 2017-2019 The Khronos Group Inc.
+**
+** 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.
+*/
+
+#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)
+// On Windows, functions use the stdcall convention
+#define XRAPI_ATTR
+#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
diff --git a/src/xrt/.clang-format b/src/xrt/.clang-format
new file mode 100644
index 000000000..e1666781b
--- /dev/null
+++ b/src/xrt/.clang-format
@@ -0,0 +1,48 @@
+---
+Language:             Cpp
+BasedOnStyle:         LLVM
+Standard:             Auto
+
+# Includes
+SortIncludes:         false
+
+# Spacing and Blank Lines
+DerivePointerAlignment: true
+PointerAlignment:       Right
+#AlignEscapedNewlines:   DontAlign
+#AlignConsecutiveDeclarations: false
+#AlignConsecutiveAssignments: false
+MaxEmptyLinesToKeep:    3
+
+# Indentation
+IndentWidth:          8
+TabWidth:             8
+UseTab:               ForIndentation
+AccessModifierOffset: -8
+IndentCaseLabels: false
+NamespaceIndentation: Inner
+
+# Line length/reflow
+ColumnLimit:          80
+ReflowComments:       true
+
+
+# Line breaks
+AlwaysBreakAfterReturnType: All
+AllowShortFunctionsOnASingleLine: Empty
+AllowShortIfStatementsOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: true
+AlwaysBreakBeforeMultilineStrings: true
+BreakBeforeBraces:    Custom
+BraceWrapping:
+  AfterEnum:          true
+  AfterStruct:        true
+  AfterClass:         true
+  SplitEmptyFunction: false
+  AfterFunction:      true
+  AfterNamespace:     false
+
+# false means either "all on one line" or "each on their own",
+# won't put more than one on a line if they don't all fit.
+BinPackArguments:     true
+BinPackParameters:    false
diff --git a/src/xrt/CMakeLists.txt b/src/xrt/CMakeLists.txt
new file mode 100644
index 000000000..e97bf6d5f
--- /dev/null
+++ b/src/xrt/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+add_subdirectory(auxiliary)
+add_subdirectory(drivers)
+add_subdirectory(compositor)
+add_subdirectory(state_trackers)
+add_subdirectory(targets)
diff --git a/src/xrt/auxiliary/CMakeLists.txt b/src/xrt/auxiliary/CMakeLists.txt
new file mode 100644
index 000000000..8ba74c589
--- /dev/null
+++ b/src/xrt/auxiliary/CMakeLists.txt
@@ -0,0 +1,42 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+set(MATH_SOURCE_FILES
+	math/m_api.h
+	math/m_base.cpp
+	math/m_optics.c
+	math/m_eigen_interop.h
+	math/m_quatexpmap.cpp
+	)
+
+set(SOURCE_FILES
+	util/u_misc.c
+	util/u_misc.h
+	util/u_debug.c
+	util/u_debug.h
+	util/u_device.c
+	util/u_device.h
+	util/u_time.cpp
+	util/u_time.h
+	)
+
+# Common includes
+include_directories(
+	${CMAKE_CURRENT_SOURCE_DIR}/../include
+	${CMAKE_CURRENT_SOURCE_DIR}
+	)
+
+# Use OBJECT to not create a archive, since it just gets in the way.
+add_library(aux_util OBJECT ${SOURCE_FILES})
+
+set_property(TARGET aux_util PROPERTY POSITION_INDEPENDENT_CODE ON)
+
+
+# Math library has different includes.
+add_library(aux_math OBJECT ${MATH_SOURCE_FILES})
+
+target_include_directories(aux_math SYSTEM
+	PRIVATE ${EIGEN3_INCLUDE_DIR}
+	)
+
+set_property(TARGET aux_math PROPERTY POSITION_INDEPENDENT_CODE ON)
diff --git a/src/xrt/auxiliary/math/m_api.h b/src/xrt/auxiliary/math/m_api.h
new file mode 100644
index 000000000..0119f295a
--- /dev/null
+++ b/src/xrt/auxiliary/math/m_api.h
@@ -0,0 +1,250 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  C interface to math library.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ *
+ * @see xrt_vec3
+ * @see xrt_quat
+ * @see xrt_pose
+ * @see xrt_space_relation
+ */
+
+#pragma once
+
+#include "xrt/xrt_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @dir auxiliary/math
+ *
+ * @brief C interface to some transform-related math functions.
+ */
+
+/*
+ *
+ * Vector functions
+ *
+ */
+
+/*!
+ * Accumulate a vector by adding in-place.
+ *
+ * Logically, *inAndOut += *additional
+ * OK if the two arguments are the same addresses.
+ *
+ * @relates xrt_vec3
+ */
+void
+math_vec3_accum(const struct xrt_vec3 *additional, struct xrt_vec3 *inAndOut);
+
+/*
+ *
+ * Quat functions.
+ *
+ */
+
+/*!
+ * Rotate a vector.
+ *
+ * @relates xrt_quat
+ * @relatesalso xrt_vec3
+ */
+void
+math_quat_rotate_vec3(const struct xrt_quat *left,
+                      const struct xrt_vec3 *right,
+                      struct xrt_vec3 *result);
+
+/*!
+ * Rotate a quaternion (compose rotations).
+ *
+ * @relates xrt_quat
+ */
+void
+math_quat_rotate(const struct xrt_quat *left,
+                 const struct xrt_quat *right,
+                 struct xrt_quat *result);
+
+
+/*!
+ * Integrate an angular velocity vector (exponential map) and apply to a
+ * quaternion.
+ *
+ * velocity and dt should share the same units of time, and the angular velocity
+ * vector should be in radians per unit of time.
+ *
+ * @relates xrt_quat
+ * @relatesalso xrt_vec3
+ */
+void
+math_quat_integrate_velocity(const struct xrt_quat *quat,
+                             const struct xrt_vec3 *ang_vel,
+                             const float dt,
+                             struct xrt_quat *result);
+/*
+ *
+ * Pose functions.
+ *
+ */
+
+/*!
+ * Check if this pose can be used in transformation operations.
+ *
+ * @relates xrt_pose
+ */
+bool
+math_pose_validate(const struct xrt_pose *pose);
+
+/*!
+ * Invert pose.
+ *
+ * OK if input and output are the same addresses.
+ *
+ * @relates xrt_pose
+ */
+void
+math_pose_invert(const struct xrt_pose *pose, struct xrt_pose *outPose);
+
+/*!
+ * Apply a rigid-body transformation to a pose.
+ *
+ * OK if input and output are the same addresses.
+ *
+ * @relates xrt_pose
+ */
+void
+math_pose_transform(const struct xrt_pose *transform,
+                    const struct xrt_pose *pose,
+                    struct xrt_pose *outPose);
+
+/*!
+ * Combine the poses of the target and base space with the relative pose of
+ * those spaces. In a way that OpenXR specifies in the function xrLocateSpace.
+ *
+ * Performs roughly outPose = spacePose * relativePose * baseSpacePose^-1
+ *
+ * OK if input and output are the same addresses.
+ *
+ * @relates xrt_pose
+ */
+void
+math_pose_openxr_locate(const struct xrt_pose *space_pose,
+                        const struct xrt_pose *relative_pose,
+                        const struct xrt_pose *base_space_pose,
+                        struct xrt_pose *result);
+
+/*
+ *
+ * Space relation functions
+ *
+ */
+
+/*!
+ * Reset a relation to zero velocity, located at origin, and all validity flags.
+ *
+ * @relates xrt_space_relation
+ */
+void
+math_relation_reset(struct xrt_space_relation *out);
+
+/*!
+ * Apply a static pose on top of an existing relation.
+ *
+ * Updates all valid pose and derivative fields. Does not modify the validity
+ * mask. Treats both position and orientation of transform as valid.
+ *
+ * @relates xrt_space_relation
+ * @see xrt_pose
+ */
+void
+math_relation_accumulate_transform(const struct xrt_pose *transform,
+                                   struct xrt_space_relation *in_out_relation);
+
+/*!
+ * Apply another step of space relation on top of an existing relation.
+ *
+ * Updates all valid pose and derivative fields, as well as the validity mask.
+ *
+ * @relates xrt_space_relation
+ */
+void
+math_relation_accumulate_relation(
+    const struct xrt_space_relation *additional_relation,
+    struct xrt_space_relation *in_out_relation);
+
+/*!
+ * Combine the poses of the target and base space with the relative relation of
+ * those spaces. In a way that OpenXR specifies in the function xrLocateSpace.
+ *
+ * Performs roughly `out_relation->pose = space_pose * relative_relation->pose *
+ * base_space_pose^-1`  for the poses, and appropriate rotation
+ *
+ * OK if input and output are the same addresses.
+ *
+ * @relates xrt_space_relation
+ * @see xrt_pose
+ */
+void
+math_relation_openxr_locate(const struct xrt_pose *space_pose,
+                            const struct xrt_space_relation *relative_relation,
+                            const struct xrt_pose *base_space_pose,
+                            struct xrt_space_relation *result);
+
+/*!
+ * Perform the computations from
+ * "Computing Half-Fields-Of-View from Simpler Display Models",
+ * to get half-FOVs from things we can retrieve from other APIs.
+ * The origin is in the lower-left corner of the display, so w_1 is the width to
+ * the left of CoP, and h_1 is the height below CoP.
+ *
+ * If vertfov_total is set to 0, it will be computed from h_total.
+ *
+ * Distances are in arbitrary but consistent units. Angles are in radians.
+ *
+ *
+ * In the diagram below, treating it like a FOV for horizontal,
+ * the top angle is horizfov_total, the length of the bottom
+ * is w_total, and the distance between the vertical line and the left corner is
+ * w_1. Vertical is similar - h_1 is above the center line.
+ * The triangle need not be symmetrical, despite how the diagram looks.
+ *
+ * ```
+ *               horizfov_total
+ *                       *
+ * angle_left (neg) -> / |  \ <- angle_right
+ *                    /  |   \
+ *                   /   |    \
+ *                  /    |     \
+ *                 -------------
+ *                 [ w_1 ]
+ *                 [ --- w  --- ]
+ *
+ * -------     --- |\
+ *                 |   \
+ *             h_1 |      \ angle_up
+ * h_total     ___ |-------* vertfov_total
+ *                 |      / angle_down (neg)
+ *                 |    /
+ *                 |  /
+ * -------         |/
+ * ```
+ *
+ * @return true if successful.
+ */
+bool
+math_compute_fovs(double w_total,
+                  double w_1,
+                  double horizfov_total,
+                  double h_total,
+                  double h_1,
+                  double vertfov_total,
+                  struct xrt_fov *fov);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/auxiliary/math/m_base.cpp b/src/xrt/auxiliary/math/m_base.cpp
new file mode 100644
index 000000000..ca3a248db
--- /dev/null
+++ b/src/xrt/auxiliary/math/m_base.cpp
@@ -0,0 +1,430 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Base implementations for math library.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <assert.h>
+
+#include "math/m_api.h"
+#include "math/m_eigen_interop.h"
+
+/*
+ *
+ * Copy helpers.
+ *
+ */
+
+static inline Eigen::Quaternionf
+copy(const struct xrt_quat& q)
+{
+	// Eigen constructor order is different from XRT, OpenHMD and OpenXR!
+	//  Eigen: `float w, x, y, z`.
+	// OpenXR: `float x, y, z, w`.
+	return Eigen::Quaternionf(q.w, q.x, q.y, q.z);
+}
+
+static inline Eigen::Quaternionf
+copy(const struct xrt_quat* q)
+{
+	return copy(*q);
+}
+
+static inline Eigen::Vector3f
+copy(const struct xrt_vec3& v)
+{
+	return Eigen::Vector3f(v.x, v.y, v.z);
+}
+
+static inline Eigen::Vector3f
+copy(const struct xrt_vec3* v)
+{
+	return copy(*v);
+}
+
+
+/*
+ *
+ * Exported vector functions.
+ *
+ */
+void
+math_vec3_accum(const struct xrt_vec3* additional, struct xrt_vec3* inAndOut)
+{
+	assert(additional != NULL);
+	assert(inAndOut != NULL);
+
+	map_vec3(*inAndOut) += map_vec3(*additional);
+}
+
+/*
+ *
+ * Exported quaternion functions.
+ *
+ */
+
+void
+math_quat_rotate(const struct xrt_quat* left,
+                 const struct xrt_quat* right,
+                 struct xrt_quat* result)
+{
+	assert(left != NULL);
+	assert(right != NULL);
+	assert(result != NULL);
+
+	auto l = copy(left);
+	auto r = copy(right);
+
+	auto q = l * r;
+
+	map_quat(*result) = q;
+}
+
+void
+math_quat_rotate_vec3(const struct xrt_quat* left,
+                      const struct xrt_vec3* right,
+                      struct xrt_vec3* result)
+{
+	assert(left != NULL);
+	assert(right != NULL);
+	assert(result != NULL);
+
+	auto l = copy(left);
+	auto r = copy(right);
+
+	auto v = l * r;
+
+	map_vec3(*result) = v;
+}
+
+
+/*
+ *
+ * Exported pose functions.
+ *
+ */
+
+bool
+math_pose_validate(const struct xrt_pose* pose)
+{
+	assert(pose != NULL);
+
+	const float FLOAT_EPSILON = Eigen::NumTraits<float>::epsilon();
+	auto norm = orientation(*pose).squaredNorm();
+	if (norm > 1.0f + FLOAT_EPSILON || norm < 1.0f - FLOAT_EPSILON) {
+		return false;
+	}
+
+	// Technically not yet a required check, but easier to stop problems
+	// now than once denormalized numbers pollute the rest of our state.
+	// see https://gitlab.khronos.org/openxr/openxr/issues/922
+	if (!orientation(*pose).coeffs().allFinite()) {
+		return false;
+	}
+	if (!position(*pose).allFinite()) {
+		return false;
+	}
+	return true;
+}
+
+void
+math_pose_invert(const struct xrt_pose* pose, struct xrt_pose* outPose)
+{
+	assert(pose != NULL);
+	assert(outPose != NULL);
+
+	// store results to temporary locals so we can do this "in-place"
+	// (pose == outPose) if desired.
+	Eigen::Vector3f newPosition = -position(*pose);
+	// Conjugate legal here since pose must be normalized/unit length.
+	Eigen::Quaternionf newOrientation = orientation(*pose).conjugate();
+
+	position(*outPose) = newPosition;
+	orientation(*outPose) = newOrientation;
+}
+
+/*!
+ * Return the result of transforming a point by a pose/transform.
+ */
+static inline Eigen::Vector3f
+transform_point(const xrt_pose& transform, const xrt_vec3& point)
+{
+	return orientation(transform) * map_vec3(point) + position(transform);
+}
+
+/*!
+ * Return the result of transforming a pose by a pose/transform.
+ */
+static inline xrt_pose
+transform_pose(const xrt_pose& transform, const xrt_pose& pose)
+{
+	xrt_pose ret;
+	position(ret) = transform_point(transform, pose.position);
+	orientation(ret) = orientation(transform) * orientation(pose);
+	return ret;
+}
+
+void
+math_pose_transform(const struct xrt_pose* transform,
+                    const struct xrt_pose* pose,
+                    struct xrt_pose* outPose)
+{
+	assert(pose != NULL);
+	assert(transform != NULL);
+	assert(outPose != NULL);
+
+	xrt_pose newPose = transform_pose(*transform, *pose);
+	memcpy(outPose, &newPose, sizeof(xrt_pose));
+}
+
+void
+math_pose_openxr_locate(const struct xrt_pose* space_pose,
+                        const struct xrt_pose* relative_pose,
+                        const struct xrt_pose* base_space_pose,
+                        struct xrt_pose* result)
+{
+	assert(space_pose != NULL);
+	assert(relative_pose != NULL);
+	assert(base_space_pose != NULL);
+	assert(result != NULL);
+
+	// Compilers are slighty better optimizing
+	// if we copy the arguments in one go.
+	const auto bsp = *base_space_pose;
+	const auto rel = *relative_pose;
+	const auto spc = *space_pose;
+	struct xrt_pose pose;
+
+	// Apply the invert of the base space to identity.
+	math_pose_invert(&bsp, &pose);
+
+	// Apply the pure pose from the space relation.
+	math_pose_transform(&pose, &rel, &pose);
+
+	// Apply the space pose.
+	math_pose_transform(&pose, &spc, &pose);
+
+	*result = pose;
+}
+
+/*!
+ * Return the result of rotating a derivative vector by a matrix.
+ *
+ * This is a differential transform.
+ */
+static inline Eigen::Vector3f
+rotate_deriv(Eigen::Matrix3f const& rotation,
+             const xrt_vec3& derivativeVector,
+             Eigen::Matrix3f const& rotationInverse)
+{
+	return ((rotation * map_vec3(derivativeVector)).transpose() *
+	        rotationInverse)
+	    .transpose();
+}
+
+#ifndef XRT_DOXYGEN
+
+#define MAKE_REL_FLAG_CHECK(NAME, MASK)                                        \
+	static inline bool NAME(xrt_space_relation_flags flags)                \
+	{                                                                      \
+		return ((flags & (MASK)) != 0);                                \
+	}
+
+MAKE_REL_FLAG_CHECK(has_some_pose_component,
+                    XRT_SPACE_RELATION_POSITION_VALID_BIT |
+                        XRT_SPACE_RELATION_ORIENTATION_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_position, XRT_SPACE_RELATION_POSITION_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_orientation, XRT_SPACE_RELATION_ORIENTATION_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_lin_vel, XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_ang_vel, XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_lin_acc,
+                    XRT_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_ang_acc,
+                    XRT_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT)
+MAKE_REL_FLAG_CHECK(has_some_derivative,
+                    XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT |
+                        XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT |
+                        XRT_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT |
+                        XRT_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT)
+
+#undef MAKE_REL_FLAG_CHECK
+
+#endif // !XRT_DOXYGEN
+
+/*!
+ * Apply a transform to a space relation.
+ */
+static inline void
+transform_accumulate_pose(const xrt_pose& transform,
+                          xrt_space_relation& relation,
+                          bool do_translation = true,
+                          bool do_rotation = true)
+{
+	assert(do_translation || do_rotation);
+
+	// Save the quat in case we are self-transforming.
+	Eigen::Quaternionf quat = orientation(transform);
+
+	auto flags = relation.relation_flags;
+	// so code looks similar
+	auto in_out_relation = &relation;
+
+	// transform (rotate and translate) the pose, if applicable.
+	if (has_some_pose_component(flags)) {
+		// Zero out transform parts we don't want to use,
+		// because math_pose_transform doesn't take flags.
+		xrt_pose transform_copy = transform;
+		if (!do_translation) {
+			position(transform_copy) = Eigen::Vector3f::Zero();
+		}
+		if (!do_rotation) {
+			orientation(transform_copy) =
+			    Eigen::Quaternionf::Identity();
+		}
+
+		math_pose_transform(&in_out_relation->pose, &transform,
+		                    &in_out_relation->pose);
+	}
+
+	if (do_rotation && has_some_derivative(flags)) {
+
+		// prepare matrices required for rotating derivatives from the
+		// saved quat.
+		Eigen::Matrix3f rot = quat.toRotationMatrix();
+		Eigen::Matrix3f rotInverse = rot.inverse();
+
+		// Rotate derivatives, if applicable.
+		if (has_lin_vel(flags)) {
+			map_vec3(in_out_relation->linear_velocity) =
+			    rotate_deriv(rot, in_out_relation->linear_velocity,
+			                 rotInverse);
+		}
+
+		if (has_ang_vel(flags)) {
+			map_vec3(in_out_relation->angular_velocity) =
+			    rotate_deriv(rot, in_out_relation->angular_velocity,
+			                 rotInverse);
+		}
+
+		if (has_lin_acc(flags)) {
+			map_vec3(in_out_relation->linear_acceleration) =
+			    rotate_deriv(rot,
+			                 in_out_relation->linear_acceleration,
+			                 rotInverse);
+		}
+
+		if (has_ang_acc(flags)) {
+			map_vec3(in_out_relation->angular_acceleration) =
+			    rotate_deriv(rot,
+			                 in_out_relation->angular_acceleration,
+			                 rotInverse);
+		}
+	}
+}
+
+static const struct xrt_space_relation BLANK_RELATION = {
+    XRT_SPACE_RELATION_BITMASK_ALL,
+    {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+    {0, 0, 0},
+};
+
+void
+math_relation_reset(struct xrt_space_relation* out)
+{
+	*out = BLANK_RELATION;
+}
+
+void
+math_relation_accumulate_transform(const struct xrt_pose* transform,
+                                   struct xrt_space_relation* in_out_relation)
+{
+	assert(transform != nullptr);
+	assert(in_out_relation != nullptr);
+
+	// No modifying the validity flags here.
+	transform_accumulate_pose(*transform, *in_out_relation);
+}
+
+
+void
+math_relation_accumulate_relation(
+    const struct xrt_space_relation* additional_relation,
+    struct xrt_space_relation* in_out_relation)
+{
+	assert(additional_relation != NULL);
+	assert(in_out_relation != NULL);
+
+	// Update the flags.
+	xrt_space_relation_flags flags = (enum xrt_space_relation_flags)(
+	    in_out_relation->relation_flags &
+	    additional_relation->relation_flags);
+	in_out_relation->relation_flags = flags;
+
+	if (has_some_pose_component(flags)) {
+		// First, just do the pose part (including rotating
+		// derivatives, if applicable).
+		transform_accumulate_pose(additional_relation->pose,
+		                          *in_out_relation, has_position(flags),
+		                          has_orientation(flags));
+	}
+
+	// Then, accumulate the derivatives, if required.
+	if (has_lin_vel(flags)) {
+		map_vec3(in_out_relation->linear_velocity) +=
+		    map_vec3(additional_relation->linear_velocity);
+	}
+
+	if (has_ang_vel(flags)) {
+		map_vec3(in_out_relation->angular_velocity) +=
+		    map_vec3(additional_relation->angular_velocity);
+	}
+
+	if (has_lin_acc(flags)) {
+		map_vec3(in_out_relation->linear_acceleration) +=
+		    map_vec3(additional_relation->linear_acceleration);
+	}
+
+	if (has_ang_acc(flags)) {
+		map_vec3(in_out_relation->angular_acceleration) +=
+		    map_vec3(additional_relation->angular_acceleration);
+	}
+}
+
+void
+math_relation_openxr_locate(const struct xrt_pose* space_pose,
+                            const struct xrt_space_relation* relative_relation,
+                            const struct xrt_pose* base_space_pose,
+                            struct xrt_space_relation* result)
+{
+	assert(space_pose != NULL);
+	assert(relative_relation != NULL);
+	assert(base_space_pose != NULL);
+	assert(result != NULL);
+
+	// Compilers are slighty better optimizing
+	// if we copy the arguments in one go.
+	const auto bsp = *base_space_pose;
+	const auto spc = *space_pose;
+	struct xrt_space_relation accumulating_relation = BLANK_RELATION;
+
+	// Apply the invert of the base space to identity.
+	math_pose_invert(&bsp, &accumulating_relation.pose);
+
+	// Apply the pure relation between spaces.
+	math_relation_accumulate_relation(relative_relation,
+	                                  &accumulating_relation);
+
+	// Apply the space pose.
+	math_relation_accumulate_transform(&spc, &accumulating_relation);
+
+	*result = accumulating_relation;
+}
diff --git a/src/xrt/auxiliary/math/m_eigen_interop.h b/src/xrt/auxiliary/math/m_eigen_interop.h
new file mode 100644
index 000000000..8ea1c1748
--- /dev/null
+++ b/src/xrt/auxiliary/math/m_eigen_interop.h
@@ -0,0 +1,111 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interoperability helpers connecting internal math types and Eigen.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#pragma once
+
+#ifndef __cplusplus
+#error "This header only usable from C++"
+#endif
+
+#include "math/m_api.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+/*!
+ * @brief Wrap an internal quaternion struct in an Eigen type, const overload.
+ *
+ * Permits zero-overhead manipulation of `const xrt_quat&` by Eigen routines as
+ * if it were a `const Eigen::Quaternionf&`.
+ */
+static inline Eigen::Map<const Eigen::Quaternionf>
+map_quat(const struct xrt_quat& q)
+{
+	return Eigen::Map<const Eigen::Quaternionf>{&q.x};
+}
+
+/*!
+ * @brief Wrap an internal quaternion struct in an Eigen type, non-const
+ * overload.
+ *
+ * Permits zero-overhead manipulation of `xrt_quat&` by Eigen routines as if it
+ * were a `Eigen::Quaternionf&`.
+ */
+static inline Eigen::Map<Eigen::Quaternionf>
+map_quat(struct xrt_quat& q)
+{
+	return Eigen::Map<Eigen::Quaternionf>{&q.x};
+}
+
+
+/*!
+ * @brief Wrap an internal 3D vector struct in an Eigen type, const overload.
+ *
+ * Permits zero-overhead manipulation of `const xrt_vec3&` by Eigen routines as
+ * if it were a `const Eigen::Vector3f&`.
+ */
+static inline Eigen::Map<const Eigen::Vector3f>
+map_vec3(const struct xrt_vec3& v)
+{
+	return Eigen::Map<const Eigen::Vector3f>{&v.x};
+}
+
+/*!
+ * @brief Wrap an internal 3D vector struct in an Eigen type, non-const
+ * overload.
+ *
+ * Permits zero-overhead manipulation of `xrt_vec3&` by Eigen routines as
+ * if it were a `Eigen::Vector3f&`.
+ */
+static inline Eigen::Map<Eigen::Vector3f>
+map_vec3(struct xrt_vec3& v)
+{
+	return Eigen::Map<Eigen::Vector3f>{&v.x};
+}
+
+/*
+ *
+ * Pose deconstruction helpers.
+ *
+ */
+
+/*!
+ * Return a Eigen type wrapping a pose's orientation (const).
+ */
+static inline Eigen::Map<const Eigen::Quaternionf>
+orientation(const struct xrt_pose& pose)
+{
+	return map_quat(pose.orientation);
+}
+
+/*!
+ * Return a Eigen type wrapping a pose's orientation.
+ */
+static inline Eigen::Map<Eigen::Quaternionf>
+orientation(struct xrt_pose& pose)
+{
+	return map_quat(pose.orientation);
+}
+
+/*!
+ * Return a Eigen type wrapping a pose's position (const).
+ */
+static inline Eigen::Map<const Eigen::Vector3f>
+position(const struct xrt_pose& pose)
+{
+	return map_vec3(pose.position);
+}
+
+/*!
+ * Return a Eigen type wrapping a pose's position.
+ */
+static inline Eigen::Map<Eigen::Vector3f>
+position(struct xrt_pose& pose)
+{
+	return map_vec3(pose.position);
+}
diff --git a/src/xrt/auxiliary/math/m_optics.c b/src/xrt/auxiliary/math/m_optics.c
new file mode 100644
index 000000000..fb1efae79
--- /dev/null
+++ b/src/xrt/auxiliary/math/m_optics.c
@@ -0,0 +1,167 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Functions related to field-of-view.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+
+#include "m_api.h"
+#include "util/u_debug.h"
+#include <math.h>
+#include <assert.h>
+#include <stdio.h>
+
+DEBUG_GET_ONCE_BOOL_OPTION(views, "MATH_DEBUG_VIEWS", false)
+
+/*!
+ * Perform some of the computations from
+ * "Computing Half-Fields-Of-View from Simpler Display Models",
+ * to solve for the half-angles for a triangle where we know the center and
+ * total angle but not the "distance".
+ *
+ * In the diagram below, the top angle is theta_total, the length of the bottom
+ * is w_total, and the distance between the vertical line and the left corner is
+ * w_1.
+ * out_theta_1 is the angle at the top of the left-most right triangle,
+ * out_theta_2 is the angle at the top of the right-most right triangle,
+ * and out_d is the length of that center vertical line, a logical "distance".
+ *
+ * Any outparams that are NULL will simply not be set.
+ *
+ * The triangle need not be symmetrical, despite how the diagram looks.
+ *
+ * ```
+ *               theta_total
+ *                    *
+ *       theta_1 -> / |  \ <- theta_2
+ *                 /  |   \
+ *                /   |d   \
+ *               /    |     \
+ *              -------------
+ *              [ w_1 ][ w_2 ]
+ *
+ *              [ --- w  --- ]
+ * ```
+ *
+ * Distances are in arbitrary but consistent units. Angles are in radians.
+ *
+ * @return true if successful.
+ */
+static bool
+math_solve_triangle(double w_total,
+                    double w_1,
+                    double theta_total,
+                    double *out_theta_1,
+                    double *out_theta_2,
+                    double *out_d)
+{
+	/* should have at least one out-variable */
+	assert(out_theta_1 || out_theta_2 || out_d);
+	const double w_2 = w_total - w_1;
+
+	const double u = w_2 / w_1;
+	const double v = tan(theta_total);
+
+	/* Parts of the quadratic formula solution */
+	const double b = u + 1.0;
+	const double root = sqrt(b + 4 * u * v * v);
+	const double two_a = 2 * v;
+
+	/* The two possible solutions. */
+	const double tan_theta_2_plus = (-b + root) / two_a;
+	const double tan_theta_2_minus = (-b - root) / two_a;
+	const double theta_2_plus = atan(tan_theta_2_plus);
+	const double theta_2_minus = atan(tan_theta_2_minus);
+
+	/* Pick the solution that is in the right range. */
+	double tan_theta_2 = 0;
+	double theta_2 = 0;
+	if (theta_2_plus > 0.f && theta_2_plus < theta_total) {
+		// OH_DEBUG(ohd, "Using the + solution to the quadratic.");
+		tan_theta_2 = tan_theta_2_plus;
+		theta_2 = theta_2_plus;
+	} else if (theta_2_minus > 0.f && theta_2_minus < theta_total) {
+		// OH_DEBUG(ohd, "Using the - solution to the quadratic.");
+		tan_theta_2 = tan_theta_2_minus;
+		theta_2 = theta_2_minus;
+	} else {
+		// OH_ERROR(ohd, "NEITHER QUADRATIC SOLUTION APPLIES!");
+		return false;
+	}
+#define METERS_FORMAT "%0.4fm"
+#define DEG_FORMAT "%0.1f deg"
+	if (debug_get_bool_option_views()) {
+		const double rad_to_deg = M_1_PI * 180.0;
+		// comments are to force wrapping
+		fprintf(stderr,
+		        "w=" METERS_FORMAT " theta=" DEG_FORMAT
+		        "    w1=" METERS_FORMAT " theta1=" DEG_FORMAT
+		        "    w2=" METERS_FORMAT " theta2=" DEG_FORMAT
+		        "    d=" METERS_FORMAT "\n",
+		        w_total, theta_total * rad_to_deg,         //
+		        w_1, (theta_total - theta_2) * rad_to_deg, //
+		        w_2, theta_2 * rad_to_deg,                 //
+		        w_2 / tan_theta_2);
+	}
+	if (out_theta_2) {
+		*out_theta_2 = theta_2;
+	}
+
+	if (out_theta_1) {
+		*out_theta_1 = theta_total - theta_2;
+	}
+	if (out_d) {
+		*out_d = w_2 / tan_theta_2;
+	}
+	return true;
+}
+
+
+bool
+math_compute_fovs(double w_total,
+                  double w_1,
+                  double horizfov_total,
+                  double h_total,
+                  double h_1,
+                  double vertfov_total,
+                  struct xrt_fov *fov)
+{
+	double d = 0;
+	double theta_1 = 0;
+	double theta_2 = 0;
+	if (!math_solve_triangle(w_total, w_1, horizfov_total, &theta_1,
+	                         &theta_2, &d)) {
+		/* failure is contagious */
+		return false;
+	}
+
+	fov->angle_left = -theta_1;
+	fov->angle_right = theta_2;
+
+	double phi_1 = 0;
+	double phi_2 = 0;
+	if (vertfov_total == 0) {
+		phi_1 = atan(h_1 / d);
+
+		/* h_2 is "up".
+		 * so the corresponding phi_2 is naturally positive.
+		 */
+		const double h_2 = h_total - h_1;
+		phi_2 = atan(h_2 / d);
+	} else {
+		/* Run the same algorithm again for vertical. */
+		if (!math_solve_triangle(h_total, h_1, vertfov_total, &phi_1,
+		                         &phi_2, NULL)) {
+			/* failure is contagious */
+			return false;
+		}
+	}
+
+	/* phi_1 is "down" so we record this as negative. */
+	fov->angle_down = phi_1 * -1.0;
+	fov->angle_up = phi_2;
+
+	return true;
+}
diff --git a/src/xrt/auxiliary/math/m_quatexpmap.cpp b/src/xrt/auxiliary/math/m_quatexpmap.cpp
new file mode 100644
index 000000000..8b19cc471
--- /dev/null
+++ b/src/xrt/auxiliary/math/m_quatexpmap.cpp
@@ -0,0 +1,148 @@
+// Copyright 2019, Collabora, Ltd.
+// Copyright 2016, Sensics, Inc.
+// SPDX-License-Identifier: Apache-2.0
+/*!
+ * @file
+ * @brief  Base implementations for math library.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ *
+ * Based in part on inc/osvr/Util/EigenQuatExponentialMap.h in OSVR-Core
+ */
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <assert.h>
+
+#include "math/m_api.h"
+#include "math/m_eigen_interop.h"
+
+// anonymous namespace for internal types
+namespace {
+template <typename Scalar> struct FourthRootMachineEps;
+template <> struct FourthRootMachineEps<double>
+{
+	/// machine epsilon is 1e-53, so fourth root is roughly 1e-13
+	static double
+	get()
+	{
+		return 1.e-13;
+	}
+};
+template <> struct FourthRootMachineEps<float>
+{
+	/// machine epsilon is 1e-24, so fourth root is 1e-6
+	static float
+	get()
+	{
+		return 1.e-6f;
+	}
+};
+/// Computes the "historical" (un-normalized) sinc(Theta)
+/// (sine(theta)/theta for theta != 0, defined as the limit value of 0
+/// at theta = 0)
+template <typename Scalar>
+inline Scalar
+sinc(Scalar theta)
+{
+	/// fourth root of machine epsilon is recommended cutoff for taylor
+	/// series expansion vs. direct computation per
+	/// Grassia, F. S. (1998). Practical Parameterization of Rotations
+	/// Using the Exponential Map. Journal of Graphics Tools, 3(3),
+	/// 29-48. http://doi.org/10.1080/10867651.1998.10487493
+	Scalar ret;
+	if (theta < FourthRootMachineEps<Scalar>::get()) {
+		// taylor series expansion.
+		ret = Scalar(1.f) - theta * theta / Scalar(6.f);
+		return ret;
+	}
+	// direct computation.
+	ret = std::sin(theta) / theta;
+	return ret;
+}
+
+/// fully-templated free function for quaternion expontiation
+template <typename Derived>
+inline Eigen::Quaternion<typename Derived::Scalar>
+quat_exp(Eigen::MatrixBase<Derived> const &vec)
+{
+	EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Derived, 3);
+	using Scalar = typename Derived::Scalar;
+	/// Implementation inspired by
+	/// Grassia, F. S. (1998). Practical Parameterization of Rotations
+	/// Using the Exponential Map. Journal of Graphics Tools, 3(3),
+	/// 29–48. http://doi.org/10.1080/10867651.1998.10487493
+	///
+	/// However, that work introduced a factor of 1/2 which I could not
+	/// derive from the definition of quaternion exponentiation and
+	/// whose absence thus distinguishes this implementation. Without
+	/// that factor of 1/2, the exp and ln functions successfully
+	/// round-trip and match other implementations.
+	Scalar theta = vec.norm();
+	Scalar vecscale = sinc(theta);
+	Eigen::Quaternion<Scalar> ret;
+	ret.vec() = vecscale * vec;
+	ret.w() = std::cos(theta);
+	return ret.normalized();
+}
+
+/// Taylor series expansion of theta over sin(theta), aka cosecant, for
+/// use near 0 when you want continuity and validity at 0.
+template <typename Scalar>
+inline Scalar
+cscTaylorExpansion(Scalar theta)
+{
+	return Scalar(1) +
+	       // theta ^ 2 / 6
+	       (theta * theta) / Scalar(6) +
+	       // 7 theta^4 / 360
+	       (Scalar(7) * theta * theta * theta * theta) / Scalar(360) +
+	       // 31 theta^6/15120
+	       (Scalar(31) * theta * theta * theta * theta * theta * theta) /
+	           Scalar(15120);
+}
+
+/// fully-templated free function for quaternion log map.
+///
+/// Assumes a unit quaternion.
+template <typename Scalar>
+inline Eigen::Matrix<Scalar, 3, 1>
+quat_ln(Eigen::Quaternion<Scalar> const &quat)
+{
+	// ln q = ( (phi)/(norm of vec) vec, ln(norm of quat))
+	// When we assume a unit quaternion, ln(norm of quat) = 0
+	// so then we just scale the vector part by phi/sin(phi) to get the
+	// result (i.e., ln(qv, qw) = (phi/sin(phi)) * qv )
+	Scalar vecnorm = quat.vec().norm();
+
+	// "best for numerical stability" vs asin or acos
+	Scalar phi = std::atan2(vecnorm, quat.w());
+
+	// Here is where we compute the coefficient to scale the vector part
+	// by, which is nominally phi / std::sin(phi).
+	// When the angle approaches zero, we compute the coefficient
+	// differently, since it gets a bit like sinc in that we want it
+	// continuous but 0 is undefined.
+	Scalar phiOverSin = vecnorm < 1e-4 ? cscTaylorExpansion<Scalar>(phi)
+	                                   : (phi / std::sin(phi));
+	return quat.vec() * phiOverSin;
+}
+
+} // namespace
+
+void
+math_quat_integrate_velocity(const struct xrt_quat *quat,
+                             const struct xrt_vec3 *ang_vel,
+                             const float dt,
+                             struct xrt_quat *result)
+{
+	assert(quat != NULL);
+	assert(ang_vel != NULL);
+	assert(result != NULL);
+
+
+	Eigen::Quaternionf q = map_quat(*quat);
+	Eigen::Quaternionf incremental_rotation =
+	    quat_exp(map_vec3(*ang_vel) * dt * 0.5f).normalized();
+	map_quat(*result) = q * incremental_rotation;
+}
diff --git a/src/xrt/auxiliary/util/u_debug.c b/src/xrt/auxiliary/util/u_debug.c
new file mode 100644
index 000000000..96805e964
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_debug.c
@@ -0,0 +1,139 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Small debug helpers.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ *
+ * Debug get option helpers heavily inspired from mesa ones.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util/u_debug.h"
+
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(print, "XRT_PRINT_OPTIONS", false)
+
+static const char *
+os_getenv(const char *name)
+{
+	return getenv(name);
+}
+
+const char *
+debug_get_option(const char *name, const char *_default)
+{
+	const char *raw = getenv(name);
+	const char *ret;
+
+	if (raw == NULL) {
+		ret = _default;
+	} else {
+		ret = raw;
+	}
+
+	if (debug_get_bool_option_print()) {
+		fprintf(stderr, "%s=%s (%s)\n", name, ret,
+		        raw == NULL ? "nil" : raw);
+	}
+
+	return ret;
+}
+
+bool
+debug_get_bool_option(const char *name, bool _default)
+{
+	const char *raw = os_getenv(name);
+	bool ret;
+
+	if (raw == NULL) {
+		ret = _default;
+	} else if (!strcmp(raw, "false")) {
+		ret = false;
+	} else if (!strcmp(raw, "FALSE")) {
+		ret = false;
+	} else if (!strcmp(raw, "off")) {
+		ret = false;
+	} else if (!strcmp(raw, "OFF")) {
+		ret = false;
+	} else if (!strcmp(raw, "no")) {
+		ret = false;
+	} else if (!strcmp(raw, "NO")) {
+		ret = false;
+	} else if (!strcmp(raw, "n")) {
+		ret = false;
+	} else if (!strcmp(raw, "N")) {
+		ret = false;
+	} else if (!strcmp(raw, "f")) {
+		ret = false;
+	} else if (!strcmp(raw, "F")) {
+		ret = false;
+	} else if (!strcmp(raw, "0")) {
+		ret = false;
+	} else {
+		ret = true;
+	}
+
+	if (debug_get_bool_option_print()) {
+		fprintf(stderr, "%s=%s (%s)\n", name, ret ? "TRUE" : "FALSE",
+		        raw == NULL ? "nil" : raw);
+	}
+
+	return ret;
+}
+
+long
+debug_get_num_option(const char *name, long _default)
+{
+	const char *raw = os_getenv(name);
+	long ret;
+
+	if (raw == NULL) {
+		ret = _default;
+	} else {
+		char *endptr;
+
+		ret = strtol(raw, &endptr, 0);
+		// Restore the default value when no digits were found.
+		if (raw == endptr) {
+			ret = _default;
+		}
+	}
+
+	if (debug_get_bool_option_print()) {
+		fprintf(stderr, "%s=%li (%s)\n", name, ret,
+		        raw == NULL ? "nil" : raw);
+	}
+
+	return ret;
+}
+
+float
+debug_get_float_option(const char *name, float _default)
+{
+	const char *raw = os_getenv(name);
+	float ret;
+
+	if (raw == NULL) {
+		ret = _default;
+	} else {
+		char *endptr;
+
+		ret = strtof(raw, &endptr);
+		// Restore the default value when no digits were found.
+		if (raw == endptr) {
+			ret = _default;
+		}
+	}
+
+	if (debug_get_bool_option_print()) {
+		fprintf(stderr, "%s=%f (%s)\n", name, ret,
+		        raw == NULL ? "nil" : raw);
+	}
+
+	return ret;
+}
diff --git a/src/xrt/auxiliary/util/u_debug.h b/src/xrt/auxiliary/util/u_debug.h
new file mode 100644
index 000000000..e9dd7c2d3
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_debug.h
@@ -0,0 +1,81 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Small debug helpers.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ *
+ * Debug get option helpers heavily inspired from mesa ones.
+ */
+
+#pragma once
+
+#include "xrt/xrt_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+const char *
+debug_get_option(const char *name, const char *_default);
+
+bool
+debug_get_bool_option(const char *name, bool _default);
+
+long
+debug_get_num_option(const char *name, long _default);
+
+float
+debug_get_float_option(const char *name, float _default);
+
+#define DEBUG_GET_ONCE_OPTION(suffix, name, _default)                          \
+	static const char *debug_get_option_##suffix()                         \
+	{                                                                      \
+		static bool gotten = false;                                    \
+		static const char *stored;                                     \
+		if (!gotten) {                                                 \
+			gotten = true;                                         \
+			stored = debug_get_option(name, _default);             \
+		}                                                              \
+		return stored;                                                 \
+	}
+
+#define DEBUG_GET_ONCE_BOOL_OPTION(suffix, name, _default)                     \
+	static bool debug_get_bool_option_##suffix()                           \
+	{                                                                      \
+		static bool gotten = false;                                    \
+		static bool stored;                                            \
+		if (!gotten) {                                                 \
+			gotten = true;                                         \
+			stored = debug_get_bool_option(name, _default);        \
+		}                                                              \
+		return stored;                                                 \
+	}
+
+#define DEBUG_GET_ONCE_NUM_OPTION(suffix, name, _default)                      \
+	static long debug_get_num_option_##suffix()                            \
+	{                                                                      \
+		static long gotten = false;                                    \
+		static long stored;                                            \
+		if (!gotten) {                                                 \
+			gotten = true;                                         \
+			stored = debug_get_num_option(name, _default);         \
+		}                                                              \
+		return stored;                                                 \
+	}
+
+#define DEBUG_GET_ONCE_FLOAT_OPTION(suffix, name, _default)                    \
+	static long debug_get_float_option_##suffix()                          \
+	{                                                                      \
+		static long gotten = false;                                    \
+		static long stored;                                            \
+		if (!gotten) {                                                 \
+			gotten = true;                                         \
+			stored = debug_get_float_option(name, _default);       \
+		}                                                              \
+		return stored;                                                 \
+	}
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/auxiliary/util/u_device.c b/src/xrt/auxiliary/util/u_device.c
new file mode 100644
index 000000000..ed4274d5c
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_device.c
@@ -0,0 +1,126 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Misc helpers for device drivers.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util/u_device.h"
+
+
+/*
+ *
+ * Matricies.
+ *
+ */
+
+const struct xrt_matrix_2x2 u_device_rotation_right = {{
+    .vecs =
+        {
+            {0, 1},
+            {-1, 0},
+        },
+}};
+
+
+const struct xrt_matrix_2x2 u_device_rotation_left = {{
+    .vecs =
+        {
+            {0, -1},
+            {1, 0},
+        },
+}};
+
+const struct xrt_matrix_2x2 u_device_rotation_ident = {{
+    .vecs =
+        {
+            {1, 0},
+            {0, 1},
+        },
+}};
+
+const struct xrt_matrix_2x2 u_device_rotation_180 = {{
+    .vecs =
+        {
+            {-1, 0},
+            {0, -1},
+        },
+}};
+
+/*
+ *
+ * Print helpers.
+ *
+ */
+
+#define PRINT(...) fprintf(stderr, __VA_ARGS__)
+
+#define PRINT_STR(name, val) PRINT("\t%s = %s\n", name, val)
+
+#define PRINT_INT(name, val) PRINT("\t%s = %u\n", name, val)
+
+#define PRINT_MM(name, val)                                                    \
+	PRINT("\t%s = %f (%i.%02imm)\n", name, val, (int32_t)(val * 1000.f),   \
+	      abs((int32_t)(val * 100000.f)) % 100)
+
+#define PRINT_ANGLE(name, val)                                                 \
+	PRINT("\t%s = %f (%i°)\n", name, val, (int32_t)(val * (180 / M_PI)))
+
+#define PRINT_MAT2X2(name, rot)                                                \
+	PRINT("\t%s = {%f, %f} {%f, %f}\n", name, rot.v[0], rot.v[1],          \
+	      rot.v[2], rot.v[3])
+
+/*!
+ * Dump the device config to stderr.
+ */
+void
+u_device_dump_config(struct xrt_device* xdev,
+                     const char* prefix,
+                     const char* prod)
+{
+	// clang-format off
+	fprintf(stderr, "%s - device_setup\n", prefix);
+	PRINT_STR(   "prod", prod);
+	PRINT_INT(   "screens[0].w_pixels ", xdev->screens[0].w_pixels);
+	PRINT_INT(   "screens[0].h_pixels ", xdev->screens[0].h_pixels);
+//	PRINT_MM(    "info.display.w_meters", info.display.w_meters);
+//	PRINT_MM(    "info.display.h_meters", info.display.h_meters);
+	PRINT_INT(   "views[0].viewport.x_pixels   ", xdev->views[0].viewport.x_pixels);
+	PRINT_INT(   "views[0].viewport.y_pixels   ", xdev->views[0].viewport.y_pixels);
+	PRINT_INT(   "views[0].viewport.w_pixels   ", xdev->views[0].viewport.w_pixels);
+	PRINT_INT(   "views[0].viewport.h_pixels   ", xdev->views[0].viewport.h_pixels);
+	PRINT_INT(   "views[0].display.w_pixels    ", xdev->views[0].display.w_pixels);
+	PRINT_INT(   "views[0].display.h_pixels    ", xdev->views[0].display.h_pixels);
+	PRINT_MM(    "views[0].display.w_meters    ", xdev->views[0].display.w_meters);
+	PRINT_MM(    "views[0].display.h_meters    ", xdev->views[0].display.h_meters);
+	PRINT_MM(    "views[0].lens_center.x_meters", xdev->views[0].lens_center.x_meters);
+	PRINT_MM(    "views[0].lens_center.y_meters", xdev->views[0].lens_center.y_meters);
+	PRINT_MAT2X2("views[0].rot            ", xdev->views[0].rot);
+	PRINT_ANGLE( "views[0].fov.angle_left ", xdev->views[0].fov.angle_left);
+	PRINT_ANGLE( "views[0].fov.angle_right", xdev->views[0].fov.angle_right);
+	PRINT_ANGLE( "views[0].fov.angle_up   ", xdev->views[0].fov.angle_up);
+	PRINT_ANGLE( "views[0].fov.angle_down ", xdev->views[0].fov.angle_down);
+//	PRINT_ANGLE( "info.views[0].fov       ", info.views[0].fov);
+	PRINT_INT(   "views[1].viewport.x_pixels   ", xdev->views[1].viewport.x_pixels);
+	PRINT_INT(   "views[1].viewport.y_pixels   ", xdev->views[1].viewport.y_pixels);
+	PRINT_INT(   "views[1].viewport.w_pixels   ", xdev->views[1].viewport.w_pixels);
+	PRINT_INT(   "views[1].viewport.h_pixels   ", xdev->views[1].viewport.h_pixels);
+	PRINT_INT(   "views[1].display.w_pixels    ", xdev->views[1].display.w_pixels);
+	PRINT_INT(   "views[1].display.h_pixels    ", xdev->views[1].display.h_pixels);
+	PRINT_MM(    "views[1].display.w_meters    ", xdev->views[1].display.w_meters);
+	PRINT_MM(    "views[1].display.h_meters    ", xdev->views[1].display.h_meters);
+	PRINT_MM(    "views[1].lens_center.x_meters", xdev->views[1].lens_center.x_meters);
+	PRINT_MM(    "views[1].lens_center.y_meters", xdev->views[1].lens_center.y_meters);
+	PRINT_MAT2X2("views[1].rot            ", xdev->views[1].rot);
+	PRINT_ANGLE( "views[1].fov.angle_left ", xdev->views[1].fov.angle_left);
+	PRINT_ANGLE( "views[1].fov.angle_right", xdev->views[1].fov.angle_right);
+	PRINT_ANGLE( "views[1].fov.angle_up   ", xdev->views[1].fov.angle_up);
+	PRINT_ANGLE( "views[1].fov.angle_down ", xdev->views[1].fov.angle_down);
+//	PRINT_ANGLE( "info.views[1].fov       ", info.views[0].fov);
+	// clang-format on
+}
diff --git a/src/xrt/auxiliary/util/u_device.h b/src/xrt/auxiliary/util/u_device.h
new file mode 100644
index 000000000..645092604
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_device.h
@@ -0,0 +1,35 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Misc helpers for device drivers.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#pragma once
+
+#include "xrt/xrt_compiler.h"
+#include "xrt/xrt_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern const struct xrt_matrix_2x2 u_device_rotation_right;
+extern const struct xrt_matrix_2x2 u_device_rotation_left;
+extern const struct xrt_matrix_2x2 u_device_rotation_ident;
+extern const struct xrt_matrix_2x2 u_device_rotation_180;
+
+/*!
+ * Dump the device config to stderr.
+ */
+void
+u_device_dump_config(struct xrt_device* xdev,
+                     const char* prefix,
+                     const char* prod);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/auxiliary/util/u_misc.c b/src/xrt/auxiliary/util/u_misc.c
new file mode 100644
index 000000000..72bdd15d7
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_misc.c
@@ -0,0 +1,16 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Very small misc utils.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#include "util/u_misc.h"
+
+
+int
+u_silence_pedantic_warning()
+{
+	return 42;
+}
diff --git a/src/xrt/auxiliary/util/u_misc.h b/src/xrt/auxiliary/util/u_misc.h
new file mode 100644
index 000000000..d149ffa39
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_misc.h
@@ -0,0 +1,19 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Very small misc utils.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/auxiliary/util/u_time.cpp b/src/xrt/auxiliary/util/u_time.cpp
new file mode 100644
index 000000000..64e580cd6
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_time.cpp
@@ -0,0 +1,135 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Implementation of a steady, convertible clock.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#include "u_time.h"
+
+#include <chrono>
+#include <new>
+#include <assert.h>
+#include <stdlib.h>
+
+using namespace std::chrono;
+
+struct MatchingTimePoints
+{
+	system_clock::time_point sys;
+	steady_clock::time_point steady;
+	// high_resolution_clock::time_point highRes;
+
+	//! Initializes to "right now" in all clocks
+	MatchingTimePoints();
+
+	timepoint_ns
+	getTimestamp(time_state const& prevState);
+};
+
+struct time_state
+{
+	MatchingTimePoints lastTimePoints;
+	timepoint_ns lastTime;
+};
+
+MatchingTimePoints::MatchingTimePoints()
+    : sys(system_clock::now()), steady(steady_clock::now())
+{}
+
+timepoint_ns
+MatchingTimePoints::getTimestamp(time_state const& prevState)
+{
+	//! @todo right now just doing steady clock for simplicity.
+	//! @todo Eventually need to make the high-res clock steady.
+	auto elapsed = steady - prevState.lastTimePoints.steady;
+	return prevState.lastTime + duration_cast<nanoseconds>(elapsed).count();
+}
+
+struct time_state*
+time_state_create()
+{
+
+	time_state* state = new (std::nothrow) time_state;
+	return state;
+}
+
+void
+time_state_destroy(struct time_state* state)
+{
+	delete state;
+}
+
+timepoint_ns
+time_state_get_now(struct time_state const* state)
+{
+	assert(state != NULL);
+	auto now = MatchingTimePoints();
+
+	return now.getTimestamp(*state);
+}
+
+timepoint_ns
+time_state_get_now_and_update(struct time_state* state)
+{
+	assert(state != NULL);
+	auto now = MatchingTimePoints();
+
+	auto timestamp = now.getTimestamp(*state);
+
+	// Update the state
+	state->lastTimePoints = now;
+	state->lastTime = timestamp;
+
+	return timestamp;
+}
+
+void
+time_state_to_timespec(struct time_state const* state,
+                       timepoint_ns timestamp,
+                       struct timespec* out)
+{
+	assert(state != NULL);
+	assert(out != NULL);
+	// Subject to some jitter, roughly up to the magnitude of the actual
+	// resolution difference between the used time source and the system
+	// clock, as well as the non-simultaneity of the calls in
+	// MatchingTimePoints::getNow()
+	auto sinceLastUpdate = nanoseconds{timestamp - state->lastTime};
+	auto equivSystemTimepoint = state->lastTimePoints.sys + sinceLastUpdate;
+
+	// System clock epoch is same as unix epoch for all known
+	// implementations, but not strictly standard-required yet, see
+	// wg21.link/p0355
+	auto sinceEpoch = equivSystemTimepoint.time_since_epoch();
+	auto secondsSinceEpoch = duration_cast<seconds>(sinceEpoch);
+	sinceEpoch -= secondsSinceEpoch;
+	out->tv_sec = secondsSinceEpoch.count();
+	out->tv_nsec = duration_cast<nanoseconds>(sinceEpoch).count();
+}
+
+
+timepoint_ns
+time_state_from_timespec(struct time_state const* state,
+                         const struct timespec* timespecTime)
+{
+	assert(state != NULL);
+	assert(timespecTime != NULL);
+	auto sinceEpoch =
+	    seconds{timespecTime->tv_sec} + nanoseconds{timespecTime->tv_nsec};
+
+
+	// System clock epoch is same as unix epoch for all known
+	// implementations, but not strictly standard-required yet, see
+	// wg21.link/p0355
+	auto systemTimePoint = time_point<system_clock, nanoseconds>{
+	    duration_cast<system_clock::duration>(sinceEpoch)};
+
+	// duration between last update and the supplied timespec
+	auto sinceLastUpdate = state->lastTimePoints.sys - systemTimePoint;
+
+	// Offset the last timestamp by that duration.
+	return state->lastTime +
+	       duration_cast<nanoseconds>(sinceLastUpdate).count();
+}
\ No newline at end of file
diff --git a/src/xrt/auxiliary/util/u_time.h b/src/xrt/auxiliary/util/u_time.h
new file mode 100644
index 000000000..bc284eae3
--- /dev/null
+++ b/src/xrt/auxiliary/util/u_time.h
@@ -0,0 +1,106 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Time-keeping: a clock that is steady, convertible to system time, and
+ * ideally high-resolution.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ *
+ * @see time_state
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * Integer timestamp type.
+ *
+ * @see time_state
+ */
+typedef int64_t timepoint_ns;
+
+/*!
+ * @struct time_state util/u_time.h
+ * @brief Time-keeping state structure.
+ *
+ * Exposed as an opaque pointer.
+ *
+ * @see timepoint_ns
+ */
+struct time_state;
+
+/*!
+ * Create a struct time_state.
+ *
+ * @public @memberof time_state
+ */
+struct time_state*
+time_state_create();
+
+
+/*!
+ * Destroy a struct time_state.
+ *
+ * Should not be called simultaneously with any other time_state function.
+ *
+ * @public @memberof time_state
+ */
+void
+time_state_destroy(struct time_state* state);
+
+/*!
+ * Get the current time as an integer timestamp.
+ *
+ * Does not update internal state for timekeeping.
+ * Should not be called simultaneously with time_state_get_now_and_update.
+ *
+ * @public @memberof time_state
+ */
+timepoint_ns
+time_state_get_now(struct time_state const* state);
+
+/*!
+ * Get the current time as an integer timestamp and update internal state.
+ *
+ * This should be called regularly, but only from one thread.
+ * It updates the association between the timing sources.
+ *
+ * Should not be called simultaneously with any other time_state function.
+ *
+ * @public @memberof time_state
+ */
+timepoint_ns
+time_state_get_now_and_update(struct time_state* state);
+
+/*!
+ * Convert an integer timestamp to a struct timespec (system time).
+ *
+ * Should not be called simultaneously with time_state_get_now_and_update.
+ *
+ * @public @memberof time_state
+ */
+void
+time_state_to_timespec(struct time_state const* state,
+                       timepoint_ns timestamp,
+                       struct timespec* out);
+
+/*!
+ * Convert a struct timespec (system time) to an integer timestamp.
+ *
+ * Should not be called simultaneously with time_state_get_now_and_update.
+ *
+ * @public @memberof time_state
+ */
+timepoint_ns
+time_state_from_timespec(struct time_state const* state,
+                         const struct timespec* timespecTime);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt
new file mode 100644
index 000000000..406d55041
--- /dev/null
+++ b/src/xrt/compositor/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+spirv_shaders(SHADER_HEADERS
+	shaders/distortion.vert
+	shaders/none.frag
+	shaders/panotools.frag
+	shaders/vive.frag
+	)
+
+set(GL_SOURCE_FILES
+	${SHADER_HEADERS}
+	client/comp_gl_api.c
+	client/comp_gl_api.h
+	client/comp_gl_client.c
+	client/comp_gl_client.h
+	client/comp_vk_client.c
+	client/comp_vk_client.h
+	client/comp_xlib_client.c
+	common/comp_vk.c
+	common/comp_vk.h
+	common/comp_vk_swapchain.h
+	common/comp_vk_swapchain.c
+	main/comp_client_interface.h
+	main/comp_compositor.c
+	main/comp_compositor.h
+	main/comp_distortion.c
+	main/comp_distortion.h
+	main/comp_glue_gl.c
+	main/comp_glue_vk.c
+	main/comp_glue_xlib.c
+	main/comp_renderer.c
+	main/comp_renderer.h
+	main/comp_settings.c
+	main/comp_settings.h
+	main/comp_swapchain.c
+	main/comp_window.h
+	main/comp_window_direct_mode.cpp
+	main/comp_window_wayland.cpp
+	main/comp_window_xcb.cpp
+	)
+
+if (${XCB_FOUND})
+	add_definitions(-DVK_USE_PLATFORM_XCB_KHR)
+	add_definitions(-DVK_USE_PLATFORM_XLIB_XRANDR_EXT)
+endif()
+
+# Use OBJECT to not create a archive, since it just gets in the way.
+add_library(comp OBJECT ${GL_SOURCE_FILES})
+set_property(TARGET comp PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_include_directories(comp
+	PRIVATE
+	${XCB_INCLUDE_DIRS}
+	${VULKAN_INCLUDE_DIR}
+	${CMAKE_CURRENT_SOURCE_DIR}
+	${CMAKE_CURRENT_SOURCE_DIR}/../include
+	${CMAKE_CURRENT_SOURCE_DIR}/../auxiliary
+	${CMAKE_CURRENT_SOURCE_DIR}/../../external
+	${CMAKE_CURRENT_BINARY_DIR}
+	)
+
+add_subdirectory(shaders)
diff --git a/src/xrt/compositor/client/comp_gl_api.c b/src/xrt/compositor/client/comp_gl_api.c
new file mode 100644
index 000000000..62f2fef4e
--- /dev/null
+++ b/src/xrt/compositor/client/comp_gl_api.c
@@ -0,0 +1,10 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OpenGL API wrapper.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#include "glad/gl.c"
diff --git a/src/xrt/compositor/client/comp_gl_api.h b/src/xrt/compositor/client/comp_gl_api.h
new file mode 100644
index 000000000..6a6b9b091
--- /dev/null
+++ b/src/xrt/compositor/client/comp_gl_api.h
@@ -0,0 +1,12 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OpenGL API wrapper header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#pragma once
+
+#include "glad/gl.h"
diff --git a/src/xrt/compositor/client/comp_gl_client.c b/src/xrt/compositor/client/comp_gl_client.c
new file mode 100644
index 000000000..f738daff3
--- /dev/null
+++ b/src/xrt/compositor/client/comp_gl_client.c
@@ -0,0 +1,242 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OpenGL client side glue to compositor implementation.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "client/comp_gl_api.h"
+#include "client/comp_gl_client.h"
+
+
+/*
+ *
+ * Swapchain functions.
+ *
+ */
+
+static void
+client_gl_swapchain_destroy(struct xrt_swapchain *xsc)
+{
+	struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
+
+	uint32_t num_images = sc->base.base.num_images;
+	if (num_images > 0) {
+		glDeleteTextures(num_images, &sc->base.images[0]);
+		memset(sc->base.images, 0, sizeof(sc->base.images));
+		glDeleteMemoryObjectsEXT(num_images, &sc->base.memory[0]);
+		memset(sc->base.images, 0, sizeof(sc->base.memory));
+		sc->base.base.num_images = 0;
+	}
+
+	// Destroy the fd swapchain as well.
+	sc->xscfd->base.destroy(&sc->xscfd->base);
+
+	free(sc);
+}
+
+static bool
+client_gl_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *index)
+{
+	struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.acquire_image(&sc->xscfd->base, index);
+}
+
+static bool
+client_gl_swapchain_wait_image(struct xrt_swapchain *xsc,
+                               uint64_t timeout,
+                               uint32_t index)
+{
+	struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.wait_image(&sc->xscfd->base, timeout, index);
+}
+
+static bool
+client_gl_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
+{
+	struct client_gl_swapchain *sc = client_gl_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.release_image(&sc->xscfd->base, index);
+}
+
+
+/*
+ *
+ * Compositor functions.
+ *
+ */
+
+static void
+client_gl_compositor_begin_session(struct xrt_compositor *xc,
+                                   enum xrt_view_type type)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.begin_session(&c->xcfd->base, type);
+}
+
+static void
+client_gl_compositor_end_session(struct xrt_compositor *xc)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.end_session(&c->xcfd->base);
+}
+
+static void
+client_gl_compositor_wait_frame(struct xrt_compositor *xc,
+                                int64_t *predicted_display_time,
+                                int64_t *predicted_display_period)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.wait_frame(&c->xcfd->base, predicted_display_time,
+	                         predicted_display_period);
+}
+
+static void
+client_gl_compositor_begin_frame(struct xrt_compositor *xc)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.begin_frame(&c->xcfd->base);
+}
+
+static void
+client_gl_compositor_discard_frame(struct xrt_compositor *xc)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.discard_frame(&c->xcfd->base);
+}
+
+static void
+client_gl_compositor_end_frame(struct xrt_compositor *xc,
+                               enum xrt_blend_mode blend_mode,
+                               struct xrt_swapchain **xscs,
+                               uint32_t *acquired_index,
+                               uint32_t num_swapchains)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	struct xrt_swapchain *internal[8];
+
+	if (num_swapchains > 8) {
+		fprintf(stderr, "ERROR! %s\n", __func__);
+		return;
+	}
+
+	for (uint32_t i = 0; i < num_swapchains; i++) {
+		struct client_gl_swapchain *sc = client_gl_swapchain(xscs[i]);
+		internal[i] = &sc->xscfd->base;
+	}
+
+	// Pipe down call into fd compositor.
+	c->xcfd->base.end_frame(&c->xcfd->base, blend_mode, internal,
+	                        acquired_index, num_swapchains);
+}
+
+static int64_t
+gl_format_to_vk(int64_t format)
+{
+	switch (format) {
+	case GL_RGBA8: return 37 /*VK_FORMAT_R8G8B8A8_UNORM*/;
+	default: return 0;
+	}
+}
+
+static struct xrt_swapchain *
+client_gl_swapchain_create(struct xrt_compositor *xc,
+                           enum xrt_swapchain_create_flags create,
+                           enum xrt_swapchain_usage_bits bits,
+                           int64_t format,
+                           uint32_t sample_count,
+                           uint32_t width,
+                           uint32_t height,
+                           uint32_t face_count,
+                           uint32_t array_size,
+                           uint32_t mip_count)
+{
+	struct client_gl_compositor *c = client_gl_compositor(xc);
+	uint32_t num_images = 3;
+
+	int64_t vk_format = gl_format_to_vk(format);
+	if (vk_format == 0) {
+		fprintf(stderr, "%s - Invalid format!\n", __func__);
+		return NULL;
+	}
+
+	struct xrt_swapchain *xsc = c->xcfd->base.create_swapchain(
+	    &c->xcfd->base, create, bits, vk_format, sample_count, width,
+	    height, face_count, array_size, mip_count);
+
+	if (xsc == NULL) {
+		return NULL;
+	}
+
+	struct client_gl_swapchain *sc =
+	    calloc(1, sizeof(struct client_gl_swapchain));
+	sc->base.base.destroy = client_gl_swapchain_destroy;
+	sc->base.base.acquire_image = client_gl_swapchain_acquire_image;
+	sc->base.base.wait_image = client_gl_swapchain_wait_image;
+	sc->base.base.release_image = client_gl_swapchain_release_image;
+	sc->base.base.num_images = num_images;
+	sc->xscfd = xrt_swapchain_fd(xsc);
+
+	glCreateTextures(GL_TEXTURE_2D, num_images, &sc->base.images[0]);
+	glCreateMemoryObjectsEXT(num_images, &sc->base.memory[0]);
+	for (uint32_t i = 0; i < num_images; i++) {
+		GLint dedicated = GL_TRUE;
+		glMemoryObjectParameterivEXT(sc->base.memory[i],
+		                             GL_DEDICATED_MEMORY_OBJECT_EXT,
+		                             &dedicated);
+		glImportMemoryFdEXT(
+		    sc->base.memory[i], sc->xscfd->images[i].size,
+		    GL_HANDLE_TYPE_OPAQUE_FD_EXT, sc->xscfd->images[i].fd);
+		glTextureStorageMem2DEXT(sc->base.images[i], mip_count,
+		                         (GLuint)format, width, height,
+		                         sc->base.memory[i], 0);
+	}
+
+	return &sc->base.base;
+}
+
+bool
+client_gl_compositor_init(struct client_gl_compositor *c,
+                          struct xrt_compositor_fd *xcfd,
+                          client_gl_get_procaddr get_gl_procaddr)
+{
+	c->base.base.create_swapchain = client_gl_swapchain_create;
+	c->base.base.begin_session = client_gl_compositor_begin_session;
+	c->base.base.end_session = client_gl_compositor_end_session;
+	c->base.base.wait_frame = client_gl_compositor_wait_frame;
+	c->base.base.begin_frame = client_gl_compositor_begin_frame;
+	c->base.base.discard_frame = client_gl_compositor_discard_frame;
+	c->base.base.end_frame = client_gl_compositor_end_frame;
+	c->base.base.formats[0] = GL_RGBA8;
+	c->base.base.num_formats = 1;
+	c->xcfd = xcfd;
+
+	gladLoadGL(get_gl_procaddr);
+
+	if (!GLAD_GL_EXT_memory_object_fd) {
+		// @todo log this to a proper logger.
+		fprintf(stderr,
+		        "%s - Needed extension"
+		        " GL_EXT_memory_object_fd not supported\n",
+		        __func__);
+		return false;
+	}
+
+	return true;
+}
diff --git a/src/xrt/compositor/client/comp_gl_client.h b/src/xrt/compositor/client/comp_gl_client.h
new file mode 100644
index 000000000..2c59cc5a1
--- /dev/null
+++ b/src/xrt/compositor/client/comp_gl_client.h
@@ -0,0 +1,91 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OpenGL client side glue to compositor header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#pragma once
+
+#include "xrt/xrt_compositor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+/*!
+ * Wraps the real compositor swapchain providing a OpenGL based interface.
+ *
+ * Almost a one to one mapping to a OpenXR swapchain.
+ *
+ * @ingroup comp_client
+ */
+struct client_gl_swapchain
+{
+	struct xrt_swapchain_gl base;
+
+	struct xrt_swapchain_fd *xscfd;
+};
+
+/*!
+ * Wraps the real compositor providing a OpenGL based interface.
+ *
+ * @ingroup comp_client
+ */
+struct client_gl_compositor
+{
+	struct xrt_compositor_gl base;
+
+	struct xrt_compositor_fd *xcfd;
+};
+
+
+/*
+ *
+ * Functions and helpers.
+ *
+ */
+
+/*!
+ * Convinence function to convert a xrt_swapchain to a client_gl_swapchain.
+ */
+XRT_MAYBE_UNUSED static struct client_gl_swapchain *
+client_gl_swapchain(struct xrt_swapchain *xsc)
+{
+	return (struct client_gl_swapchain *)xsc;
+}
+
+/*!
+ * Convinence function to convert a xrt_compositor to a client_gl_compositor.
+ */
+XRT_MAYBE_UNUSED static struct client_gl_compositor *
+client_gl_compositor(struct xrt_compositor *xc)
+{
+	return (struct client_gl_compositor *)xc;
+}
+
+typedef void (*client_gl_void_ptr_func)();
+
+typedef client_gl_void_ptr_func (*client_gl_get_procaddr)(const char *name);
+
+/*!
+ * Fill in a client_gl_compositor and do common OpenGL sanity checking.
+ */
+bool
+client_gl_compositor_init(struct client_gl_compositor *c,
+                          struct xrt_compositor_fd *xcfd,
+                          client_gl_get_procaddr get_gl_procaddr);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/client/comp_vk_client.c b/src/xrt/compositor/client/comp_vk_client.c
new file mode 100644
index 000000000..ca9ae0964
--- /dev/null
+++ b/src/xrt/compositor/client/comp_vk_client.c
@@ -0,0 +1,276 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Vulkan client side glue to compositor implementation.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp_client
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "comp_vk_client.h"
+
+
+/*
+ *
+ * Swapchain function.
+ *
+ */
+
+static void
+client_vk_swapchain_destroy(struct xrt_swapchain *xsc)
+{
+	struct client_vk_swapchain *sc = client_vk_swapchain(xsc);
+	struct client_vk_compositor *c = sc->c;
+
+	for (uint32_t i = 0; i < sc->base.base.num_images; i++) {
+		if (sc->base.images[i] != NULL) {
+			c->vk.vkDestroyImage(c->vk.device, sc->base.images[i],
+			                     NULL);
+			sc->base.images[i] = NULL;
+		}
+
+		if (sc->base.mems[i] != NULL) {
+			c->vk.vkFreeMemory(c->vk.device, sc->base.mems[i],
+			                   NULL);
+			sc->base.mems[i] = NULL;
+		}
+	}
+
+	// Destroy the fd swapchain as well.
+	sc->xscfd->base.destroy(&sc->xscfd->base);
+
+	free(sc);
+}
+
+static bool
+client_vk_swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *index)
+{
+	struct client_vk_swapchain *sc = client_vk_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.acquire_image(&sc->xscfd->base, index);
+}
+
+static bool
+client_vk_swapchain_wait_image(struct xrt_swapchain *xsc,
+                               uint64_t timeout,
+                               uint32_t index)
+{
+	struct client_vk_swapchain *sc = client_vk_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.wait_image(&sc->xscfd->base, timeout, index);
+}
+
+static bool
+client_vk_swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
+{
+	struct client_vk_swapchain *sc = client_vk_swapchain(xsc);
+
+	// Pipe down call into fd swapchain.
+	return sc->xscfd->base.release_image(&sc->xscfd->base, index);
+}
+
+
+/*
+ *
+ * Compositor functions.
+ *
+ */
+
+static void
+client_vk_compositor_destroy(struct xrt_compositor *xc)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.destroy(&c->xcfd->base);
+	free(c);
+}
+
+static void
+client_vk_compositor_begin_session(struct xrt_compositor *xc,
+                                   enum xrt_view_type type)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.begin_session(&c->xcfd->base, type);
+}
+
+static void
+client_vk_compositor_end_session(struct xrt_compositor *xc)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.end_session(&c->xcfd->base);
+}
+
+static void
+client_vk_compositor_wait_frame(struct xrt_compositor *xc,
+                                int64_t *predicted_display_time,
+                                int64_t *predicted_display_period)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.wait_frame(&c->xcfd->base, predicted_display_time,
+	                         predicted_display_period);
+}
+
+static void
+client_vk_compositor_begin_frame(struct xrt_compositor *xc)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.begin_frame(&c->xcfd->base);
+}
+
+static void
+client_vk_compositor_discard_frame(struct xrt_compositor *xc)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->xcfd->base.discard_frame(&c->xcfd->base);
+}
+
+static void
+client_vk_compositor_end_frame(struct xrt_compositor *xc,
+                               enum xrt_blend_mode blend_mode,
+                               struct xrt_swapchain **xscs,
+                               uint32_t *acquired_index,
+                               uint32_t num_swapchains)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	struct xrt_swapchain *internal[8];
+
+	if (num_swapchains > 8) {
+		fprintf(stderr, "ERROR! %s\n", __func__);
+		return;
+	}
+
+	for (uint32_t i = 0; i < num_swapchains; i++) {
+		struct client_vk_swapchain *sc = client_vk_swapchain(xscs[i]);
+		internal[i] = &sc->xscfd->base;
+	}
+
+	// Pipe down call into fd compositor.
+	c->xcfd->base.end_frame(&c->xcfd->base, blend_mode, internal,
+	                        acquired_index, num_swapchains);
+}
+
+static struct xrt_swapchain *
+client_vk_swapchain_create(struct xrt_compositor *xc,
+                           enum xrt_swapchain_create_flags create,
+                           enum xrt_swapchain_usage_bits bits,
+                           int64_t format,
+                           uint32_t sample_count,
+                           uint32_t width,
+                           uint32_t height,
+                           uint32_t face_count,
+                           uint32_t array_size,
+                           uint32_t mip_count)
+{
+	struct client_vk_compositor *c = client_vk_compositor(xc);
+	VkCommandBuffer cmd_buffer;
+	uint32_t num_images = 3;
+	VkResult ret;
+
+	struct xrt_swapchain *xsc = c->xcfd->base.create_swapchain(
+	    &c->xcfd->base, create, bits, format, sample_count, width, height,
+	    face_count, array_size, mip_count);
+
+	if (xsc == NULL) {
+		return NULL;
+	}
+
+	ret = vk_init_cmd_buffer(&c->vk, &cmd_buffer);
+	if (ret != VK_SUCCESS) {
+		return NULL;
+	}
+
+	VkImageSubresourceRange subresource_range = {
+	    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	    .baseMipLevel = 0,
+	    .levelCount = 1,
+	    .baseArrayLayer = 0,
+	    .layerCount = 1,
+	};
+
+	struct client_vk_swapchain *sc =
+	    calloc(1, sizeof(struct client_vk_swapchain));
+	sc->base.base.destroy = client_vk_swapchain_destroy;
+	sc->base.base.acquire_image = client_vk_swapchain_acquire_image;
+	sc->base.base.wait_image = client_vk_swapchain_wait_image;
+	sc->base.base.release_image = client_vk_swapchain_release_image;
+	sc->base.base.num_images = num_images;
+	sc->c = c;
+	sc->xscfd = xrt_swapchain_fd(xsc);
+
+	for (uint32_t i = 0; i < num_images; i++) {
+		ret = vk_create_image_from_fd(&c->vk, format, width, height,
+		                              mip_count, &sc->xscfd->images[i],
+		                              &sc->base.images[i],
+		                              &sc->base.mems[i]);
+		if (ret != VK_SUCCESS) {
+			return NULL;
+		}
+
+		vk_set_image_layout(&c->vk, cmd_buffer, sc->base.images[i], 0,
+		                    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+		                    VK_IMAGE_LAYOUT_UNDEFINED,
+		                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+		                    subresource_range);
+	}
+
+	ret = vk_submit_cmd_buffer(&c->vk, cmd_buffer);
+	if (ret != VK_SUCCESS) {
+		return NULL;
+	}
+
+	return &sc->base.base;
+}
+
+struct client_vk_compositor *
+client_vk_compositor_create(struct xrt_compositor_fd *xcfd,
+                            VkInstance instance,
+                            PFN_vkGetInstanceProcAddr getProc,
+                            VkPhysicalDevice physicalDevice,
+                            VkDevice device,
+                            uint32_t queueFamilyIndex,
+                            uint32_t queueIndex)
+{
+	VkResult ret;
+	struct client_vk_compositor *c =
+	    calloc(1, sizeof(struct client_vk_compositor));
+
+	c->base.base.create_swapchain = client_vk_swapchain_create;
+	c->base.base.begin_session = client_vk_compositor_begin_session;
+	c->base.base.end_session = client_vk_compositor_end_session;
+	c->base.base.wait_frame = client_vk_compositor_wait_frame;
+	c->base.base.begin_frame = client_vk_compositor_begin_frame;
+	c->base.base.discard_frame = client_vk_compositor_discard_frame;
+	c->base.base.end_frame = client_vk_compositor_end_frame;
+	c->base.base.destroy = client_vk_compositor_destroy;
+
+	c->base.base.formats[0] = VK_FORMAT_B8G8R8A8_SRGB;
+	c->base.base.formats[1] = VK_FORMAT_R8G8B8A8_SRGB;
+	c->base.base.formats[2] = VK_FORMAT_B8G8R8A8_UNORM;
+	c->base.base.formats[3] = VK_FORMAT_R8G8B8A8_UNORM;
+	c->base.base.num_formats = 4;
+
+	c->xcfd = xcfd;
+
+	ret = vk_init_from_given(&c->vk, getProc, instance, physicalDevice,
+	                         device, queueFamilyIndex, queueIndex);
+	if (ret != VK_SUCCESS) {
+		goto err_free;
+	}
+
+	return c;
+
+err_free:
+	free(c);
+	return NULL;
+}
diff --git a/src/xrt/compositor/client/comp_vk_client.h b/src/xrt/compositor/client/comp_vk_client.h
new file mode 100644
index 000000000..861daa779
--- /dev/null
+++ b/src/xrt/compositor/client/comp_vk_client.h
@@ -0,0 +1,103 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Vulkan client side glue to compositor header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp_client
+ */
+
+#pragma once
+
+#include "common/comp_vk.h"
+#include "xrt/xrt_gfx_vk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+struct client_vk_compositor;
+
+/*!
+ * Wraps the real compositor swapchain providing a Vulkan based interface.
+ *
+ * Almost a one to one mapping to a OpenXR swapchain.
+ *
+ * @ingroup comp_client
+ */
+struct client_vk_swapchain
+{
+	struct xrt_swapchain_vk base;
+	struct xrt_swapchain_fd *xscfd;
+	struct client_vk_compositor *c;
+};
+
+/*!
+ * Wraps the real compositor providing a Vulkan based interface.
+ *
+ * @ingroup comp_client
+ */
+struct client_vk_compositor
+{
+	struct xrt_compositor_vk base;
+
+	struct xrt_compositor_fd *xcfd;
+
+	struct vk_bundle vk;
+};
+
+
+/*
+ *
+ * Functions and helpers.
+ *
+ */
+
+/*!
+ * Convinence function to convert a xrt_swapchain to a client_vk_swapchain.
+ *
+ * @ingroup comp_client
+ */
+XRT_MAYBE_UNUSED static struct client_vk_swapchain *
+client_vk_swapchain(struct xrt_swapchain *xsc)
+{
+	return (struct client_vk_swapchain *)xsc;
+}
+
+/*!
+ * Convinence function to convert a xrt_compositor to a client_vk_compositor.
+ *
+ * @ingroup comp_client
+ */
+XRT_MAYBE_UNUSED static struct client_vk_compositor *
+client_vk_compositor(struct xrt_compositor *xc)
+{
+	return (struct client_vk_compositor *)xc;
+}
+
+/*!
+ * Create a new client_vk_compositor.
+ *
+ * @ingroup comp_client
+ */
+struct client_vk_compositor *
+client_vk_compositor_create(struct xrt_compositor_fd *c,
+                            VkInstance instance,
+                            PFN_vkGetInstanceProcAddr getProc,
+                            VkPhysicalDevice physicalDevice,
+                            VkDevice device,
+                            uint32_t queueFamilyIndex,
+                            uint32_t queueIndex);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/client/comp_xlib_client.c b/src/xrt/compositor/client/comp_xlib_client.c
new file mode 100644
index 000000000..6e9a0ca45
--- /dev/null
+++ b/src/xrt/compositor/client/comp_xlib_client.c
@@ -0,0 +1,51 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Xlib client side glue to compositor implementation.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+
+#include "client/comp_xlib_client.h"
+
+
+static void
+client_xlib_compositor_destroy(struct xrt_compositor *xc)
+{
+	struct client_xlib_compositor *c = client_xlib_compositor(xc);
+	// Pipe down call into fd compositor.
+	c->base.xcfd->base.destroy(&c->base.xcfd->base);
+	free(c);
+}
+
+typedef void (*void_ptr_func)();
+
+void_ptr_func
+glXGetProcAddress(const char *procName);
+
+struct client_xlib_compositor *
+client_xlib_compositor_create(struct xrt_compositor_fd *xcfd,
+                              Display *xDisplay,
+                              uint32_t visualid,
+                              GLXFBConfig glxFBConfig,
+                              GLXDrawable glxDrawable,
+                              GLXContext glxContext)
+{
+	struct client_xlib_compositor *c =
+	    calloc(1, sizeof(struct client_xlib_compositor));
+
+	if (!client_gl_compositor_init(&c->base, xcfd, glXGetProcAddress)) {
+		free(c);
+		return NULL;
+	}
+
+	c->base.base.base.destroy = client_xlib_compositor_destroy;
+
+	return c;
+}
diff --git a/src/xrt/compositor/client/comp_xlib_client.h b/src/xrt/compositor/client/comp_xlib_client.h
new file mode 100644
index 000000000..becd60ef2
--- /dev/null
+++ b/src/xrt/compositor/client/comp_xlib_client.h
@@ -0,0 +1,58 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Xlib client side glue to compositor header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#pragma once
+
+#include "xrt/xrt_gfx_xlib.h"
+#include "client/comp_gl_client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * A client facing xlib base compositor.
+ *
+ * @ingroup comp_client
+ */
+struct client_xlib_compositor
+{
+	//! OpenGL compositor wrapper base.
+	struct client_gl_compositor base;
+};
+
+/*!
+ * Convinence function to convert a xrt_compositor to a client_xlib_compositor.
+ *
+ * @ingroup comp_client
+ */
+XRT_MAYBE_UNUSED static struct client_xlib_compositor *
+client_xlib_compositor(struct xrt_compositor *xc)
+{
+	return (struct client_xlib_compositor *)xc;
+}
+
+/*!
+ * Create a new client_xlib_compositor_create.
+ *
+ * @ingroup comp_client
+ */
+struct client_xlib_compositor *
+client_xlib_compositor_create(struct xrt_compositor_fd *xcfd,
+                              Display *xDisplay,
+                              uint32_t visualid,
+                              GLXFBConfig glxFBConfig,
+                              GLXDrawable glxDrawable,
+                              GLXContext glxContext);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/common/comp_vk.c b/src/xrt/compositor/common/comp_vk.c
new file mode 100644
index 000000000..f9ce1b845
--- /dev/null
+++ b/src/xrt/compositor/common/comp_vk.c
@@ -0,0 +1,1003 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Common Vulkan code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp_common
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util/u_debug.h"
+#include "common/comp_vk.h"
+
+
+/*
+ *
+ * String helper functions.
+ *
+ */
+
+#define ENUM_TO_STR(r)                                                         \
+	case r: return #r
+
+const char *
+vk_result_string(VkResult code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_SUCCESS);
+		ENUM_TO_STR(VK_NOT_READY);
+		ENUM_TO_STR(VK_TIMEOUT);
+		ENUM_TO_STR(VK_EVENT_SET);
+		ENUM_TO_STR(VK_EVENT_RESET);
+		ENUM_TO_STR(VK_INCOMPLETE);
+		ENUM_TO_STR(VK_ERROR_OUT_OF_HOST_MEMORY);
+		ENUM_TO_STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
+		ENUM_TO_STR(VK_ERROR_INITIALIZATION_FAILED);
+		ENUM_TO_STR(VK_ERROR_DEVICE_LOST);
+		ENUM_TO_STR(VK_ERROR_MEMORY_MAP_FAILED);
+		ENUM_TO_STR(VK_ERROR_LAYER_NOT_PRESENT);
+		ENUM_TO_STR(VK_ERROR_EXTENSION_NOT_PRESENT);
+		ENUM_TO_STR(VK_ERROR_FEATURE_NOT_PRESENT);
+		ENUM_TO_STR(VK_ERROR_INCOMPATIBLE_DRIVER);
+		ENUM_TO_STR(VK_ERROR_TOO_MANY_OBJECTS);
+		ENUM_TO_STR(VK_ERROR_FORMAT_NOT_SUPPORTED);
+		ENUM_TO_STR(VK_ERROR_SURFACE_LOST_KHR);
+		ENUM_TO_STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
+		ENUM_TO_STR(VK_SUBOPTIMAL_KHR);
+		ENUM_TO_STR(VK_ERROR_OUT_OF_DATE_KHR);
+		ENUM_TO_STR(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
+		ENUM_TO_STR(VK_ERROR_VALIDATION_FAILED_EXT);
+		ENUM_TO_STR(VK_ERROR_INVALID_SHADER_NV);
+		ENUM_TO_STR(VK_ERROR_INVALID_EXTERNAL_HANDLE);
+	default: return "UNKNOWN RESULT";
+	}
+}
+
+const char *
+vk_color_format_string(VkFormat code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_FORMAT_B8G8R8A8_UNORM);
+		ENUM_TO_STR(VK_FORMAT_UNDEFINED);
+		ENUM_TO_STR(VK_FORMAT_R8G8B8A8_SRGB);
+		ENUM_TO_STR(VK_FORMAT_B8G8R8A8_SRGB);
+		ENUM_TO_STR(VK_FORMAT_R8G8B8_SRGB);
+		ENUM_TO_STR(VK_FORMAT_B8G8R8_SRGB);
+		ENUM_TO_STR(VK_FORMAT_R5G6B5_UNORM_PACK16);
+		ENUM_TO_STR(VK_FORMAT_B5G6R5_UNORM_PACK16);
+		ENUM_TO_STR(VK_FORMAT_D32_SFLOAT_S8_UINT);
+		ENUM_TO_STR(VK_FORMAT_D32_SFLOAT);
+		ENUM_TO_STR(VK_FORMAT_D24_UNORM_S8_UINT);
+		ENUM_TO_STR(VK_FORMAT_D16_UNORM_S8_UINT);
+		ENUM_TO_STR(VK_FORMAT_D16_UNORM);
+	default: return "UNKNOWN FORMAT";
+	}
+}
+
+const char *
+vk_present_mode_string(VkPresentModeKHR code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_PRESENT_MODE_FIFO_KHR);
+		ENUM_TO_STR(VK_PRESENT_MODE_MAILBOX_KHR);
+		ENUM_TO_STR(VK_PRESENT_MODE_IMMEDIATE_KHR);
+		ENUM_TO_STR(VK_PRESENT_MODE_FIFO_RELAXED_KHR);
+		ENUM_TO_STR(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
+		ENUM_TO_STR(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR);
+	default: return "UNKNOWN MODE";
+	}
+}
+
+const char *
+vk_power_state_string(VkDisplayPowerStateEXT code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_DISPLAY_POWER_STATE_OFF_EXT);
+		ENUM_TO_STR(VK_DISPLAY_POWER_STATE_SUSPEND_EXT);
+		ENUM_TO_STR(VK_DISPLAY_POWER_STATE_ON_EXT);
+	default: return "UNKNOWN MODE";
+	}
+}
+
+const char *
+vk_color_space_string(VkColorSpaceKHR code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_COLORSPACE_SRGB_NONLINEAR_KHR);
+	default: return "UNKNOWN COLOR SPACE";
+	}
+}
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+bool
+vk_get_memory_type(struct vk_bundle *vk,
+                   uint32_t type_bits,
+                   VkMemoryPropertyFlags memory_props,
+                   uint32_t *out_type_id)
+{
+
+	for (uint32_t i = 0; i < vk->device_memory_props.memoryTypeCount; i++) {
+		uint32_t propertyFlags =
+		    vk->device_memory_props.memoryTypes[i].propertyFlags;
+		if ((type_bits & 1) == 1) {
+			if ((propertyFlags & memory_props) == memory_props) {
+				*out_type_id = i;
+				return true;
+			}
+		}
+		type_bits >>= 1;
+	}
+
+	VK_DEBUG(vk, "Could not find memory type!");
+
+	return false;
+}
+
+VkResult
+vk_create_image_simple(struct vk_bundle *vk,
+                       uint32_t width,
+                       uint32_t height,
+                       VkFormat format,
+                       VkDeviceMemory *out_mem,
+                       VkImage *out_image)
+{
+	VkImageUsageFlags usage_flags;
+	VkDeviceMemory memory;
+	VkImage image;
+	VkResult ret;
+
+	usage_flags = 0;
+	usage_flags |= VK_IMAGE_USAGE_SAMPLED_BIT;
+	usage_flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+
+	VkImageCreateInfo image_info = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .imageType = VK_IMAGE_TYPE_2D,
+	    .format = format,
+	    .extent =
+	        {
+	            .width = width,
+	            .height = height,
+	            .depth = 1,
+	        },
+	    .mipLevels = 1,
+	    .arrayLayers = 1,
+	    .samples = VK_SAMPLE_COUNT_1_BIT,
+	    .tiling = VK_IMAGE_TILING_LINEAR,
+	    .usage = usage_flags,
+	    .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+	    .queueFamilyIndexCount = 0,
+	    .pQueueFamilyIndices = NULL,
+	    .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+	};
+
+	ret = vk->vkCreateImage(vk->device, &image_info, NULL, &image);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateImage: %s", vk_result_string(ret));
+		goto err;
+	}
+
+	VkMemoryRequirements memory_requirements;
+	vk->vkGetImageMemoryRequirements(vk->device, image,
+	                                 &memory_requirements);
+
+	uint32_t memory_type_index;
+	vk_get_memory_type(vk, memory_requirements.memoryTypeBits,
+	                   VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+	                   &memory_type_index);
+
+	VkMemoryAllocateInfo alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+	    .pNext = NULL,
+	    .allocationSize = memory_requirements.size,
+	    .memoryTypeIndex = memory_type_index,
+	};
+
+	ret = vk->vkAllocateMemory(vk->device, &alloc_info, NULL, &memory);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkAllocateMemory: %s", vk_result_string(ret));
+		goto err_image;
+	}
+
+	// Bind the memory to the image.
+	ret = vk->vkBindImageMemory(vk->device, image, memory, 0);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkBindImageMemory: %s", vk_result_string(ret));
+		goto err_mem;
+	}
+
+	*out_image = image;
+	*out_mem = memory;
+
+	return ret;
+
+err_mem:
+	vk->vkFreeMemory(vk->device, memory, NULL);
+err_image:
+	vk->vkDestroyImage(vk->device, image, NULL);
+err:
+	return ret;
+}
+
+VkResult
+vk_create_image_from_fd(struct vk_bundle *vk,
+                        int64_t format,
+                        uint32_t width,
+                        uint32_t height,
+                        uint32_t mip_count,
+                        struct xrt_image_fd *image_fd,
+                        VkImage *out_image,
+                        VkDeviceMemory *out_mem)
+{
+	VkMemoryRequirements memory_requirements;
+	VkImageUsageFlagBits image_usage = 0;
+	VkDeviceMemory device_memory = NULL;
+	uint32_t memory_type_index = UINT32_MAX;
+	VkImage image = NULL;
+	VkResult ret = VK_SUCCESS;
+
+	VkExternalMemoryImageCreateInfoKHR external_memory_image_create_info = {
+	    .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
+	    .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
+	};
+
+	image_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+	image_usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+	image_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+	VkImageCreateInfo info = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+	    .pNext = &external_memory_image_create_info,
+	    .imageType = VK_IMAGE_TYPE_2D,
+	    .format = format,
+	    .extent = {.width = width, .height = height, .depth = 1},
+	    .mipLevels = mip_count,
+	    .arrayLayers = 1,
+	    .samples = VK_SAMPLE_COUNT_1_BIT,
+	    .tiling = VK_IMAGE_TILING_OPTIMAL,
+	    .usage = image_usage,
+	    .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+	    .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+	};
+
+	ret = vk->vkCreateImage(vk->device, &info, NULL, &image);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateImage: %s", vk_result_string(ret));
+		goto err;
+	}
+
+	vk->vkGetImageMemoryRequirements(vk->device, image,
+	                                 &memory_requirements);
+	if (memory_requirements.size > image_fd->size) {
+		VK_ERROR(vk,
+		         "client_vk_swapchain - Got too little memory "
+		         "%u vs %u\n",
+		         (uint32_t)memory_requirements.size,
+		         (uint32_t)image_fd->size);
+	}
+
+	if (!vk_get_memory_type(vk, memory_requirements.memoryTypeBits,
+	                        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+	                        &memory_type_index)) {
+		VK_ERROR(c, "vk_get_memory_type failed!");
+		ret = VK_ERROR_OUT_OF_DEVICE_MEMORY;
+		goto err_image;
+	}
+
+	VkMemoryDedicatedAllocateInfoKHR dedicated_memory_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
+	    .pNext = NULL,
+	    .image = image,
+	    .buffer = VK_NULL_HANDLE,
+	};
+
+	VkImportMemoryFdInfoKHR import_memory_info = {
+	    .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
+	    .pNext = &dedicated_memory_info,
+	    .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
+	    .fd = image_fd->fd,
+	};
+
+	VkMemoryAllocateInfo alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+	    .pNext = &import_memory_info,
+	    .allocationSize = memory_requirements.size,
+	    .memoryTypeIndex = memory_type_index,
+	};
+
+	ret =
+	    vk->vkAllocateMemory(vk->device, &alloc_info, NULL, &device_memory);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkAllocateMemory: %s", vk_result_string(ret));
+		goto err_image;
+	}
+
+	// Bind the memory to the image.
+	ret = vk->vkBindImageMemory(vk->device, image, device_memory, 0);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkBindImageMemory: %s", vk_result_string(ret));
+		goto err_mem;
+	}
+
+	*out_image = image;
+	*out_mem = device_memory;
+
+	return ret;
+
+err_mem:
+	vk->vkFreeMemory(vk->device, device_memory, NULL);
+err_image:
+	vk->vkDestroyImage(vk->device, image, NULL);
+err:
+	return ret;
+}
+
+VkResult
+vk_create_sampler(struct vk_bundle *vk, VkSampler *out_sampler)
+{
+	VkSampler sampler;
+	VkResult ret;
+
+	VkSamplerCreateInfo info = {
+	    .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .magFilter = VK_FILTER_NEAREST,
+	    .minFilter = VK_FILTER_NEAREST,
+	    .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
+	    .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
+	    .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
+	    .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
+	    .mipLodBias = 0.0f,
+	    .anisotropyEnable = VK_FALSE,
+	    .maxAnisotropy = 1.0f,
+	    .compareEnable = VK_FALSE,
+	    .compareOp = VK_COMPARE_OP_NEVER,
+	    .minLod = 0.0f,
+	    .maxLod = 1.0f,
+	    .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
+	    .unnormalizedCoordinates = VK_FALSE,
+	};
+
+	ret = vk->vkCreateSampler(vk->device, &info, NULL, &sampler);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateSampler: %s", vk_result_string(ret));
+		return ret;
+	}
+
+	*out_sampler = sampler;
+
+	return VK_SUCCESS;
+}
+
+VkResult
+vk_create_view(struct vk_bundle *vk,
+               VkImage image,
+               VkFormat format,
+               VkImageView *out_view)
+{
+	VkImageView view;
+	VkResult ret;
+
+	VkImageViewCreateInfo imageView = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .image = image,
+	    .viewType = VK_IMAGE_VIEW_TYPE_2D,
+	    .format = format,
+	    .components =
+	        {
+	            .r = VK_COMPONENT_SWIZZLE_R,
+	            .g = VK_COMPONENT_SWIZZLE_G,
+	            .b = VK_COMPONENT_SWIZZLE_B,
+	            .a = VK_COMPONENT_SWIZZLE_A,
+	        },
+	    .subresourceRange =
+	        {
+	            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	            .baseMipLevel = 0,
+	            .levelCount = 1,
+	            .baseArrayLayer = 0,
+	            .layerCount = 1,
+	        },
+	};
+
+	ret = vk->vkCreateImageView(vk->device, &imageView, NULL, &view);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(c, "vkCreateImageView: %s", vk_result_string(ret));
+		return ret;
+	}
+
+	*out_view = view;
+
+	return VK_SUCCESS;
+}
+
+
+/*
+ *
+ * Command buffer code.
+ *
+ */
+
+VkResult
+vk_init_cmd_buffer(struct vk_bundle *vk, VkCommandBuffer *out_cmd_buffer)
+{
+	VkCommandBuffer cmd_buffer;
+	VkResult ret;
+
+	// Allocate the command buffer.
+	VkCommandBufferAllocateInfo cmd_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+	    .commandPool = vk->cmd_pool,
+	    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+	    .commandBufferCount = 1,
+	};
+
+	ret = vk->vkAllocateCommandBuffers(vk->device, &cmd_buffer_info,
+	                                   &cmd_buffer);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkAllocateCommandBuffers: %s",
+		         vk_result_string(ret));
+		goto err;
+	}
+
+	// Start the command buffer as well.
+	VkCommandBufferBeginInfo begin_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+	};
+	ret = vk->vkBeginCommandBuffer(cmd_buffer, &begin_info);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkBeginCommandBuffer: %s", vk_result_string(ret));
+		goto err_buffer;
+	}
+
+	*out_cmd_buffer = cmd_buffer;
+
+	return VK_SUCCESS;
+
+
+err_buffer:
+	vk->vkFreeCommandBuffers(vk->device, vk->cmd_pool, 1, &cmd_buffer);
+
+err:
+	return ret;
+}
+
+VkResult
+vk_set_image_layout(struct vk_bundle *vk,
+                    VkCommandBuffer cmd_buffer,
+                    VkImage image,
+                    VkAccessFlags src_access_mask,
+                    VkAccessFlags dst_access_mask,
+                    VkImageLayout old_layout,
+                    VkImageLayout new_layout,
+                    VkImageSubresourceRange subresource_range)
+{
+	VkImageMemoryBarrier barrier = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+	    .srcAccessMask = src_access_mask,
+	    .dstAccessMask = dst_access_mask,
+	    .oldLayout = old_layout,
+	    .newLayout = new_layout,
+	    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+	    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+	    .image = image,
+	    .subresourceRange = subresource_range,
+	};
+
+	vk->vkCmdPipelineBarrier(cmd_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+	                         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL,
+	                         0, NULL, 1, &barrier);
+
+	return VK_SUCCESS;
+}
+
+VkResult
+vk_submit_cmd_buffer(struct vk_bundle *vk, VkCommandBuffer cmd_buffer)
+{
+	VkResult ret = VK_SUCCESS;
+	VkQueue queue;
+	VkFence fence;
+
+	// Finish the command buffer first.
+	ret = vk->vkEndCommandBuffer(cmd_buffer);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkEndCommandBuffer: %s", vk_result_string(ret));
+		goto out;
+	}
+
+	// Get the queue.
+	vk->vkGetDeviceQueue(vk->device, vk->queue_family_index, 0, &queue);
+
+	// Create the fence.
+	VkFenceCreateInfo fence_info = {
+	    .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+	};
+	ret = vk->vkCreateFence(vk->device, &fence_info, NULL, &fence);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateFence: %s", vk_result_string(ret));
+		goto out;
+	}
+
+	// Do the actual submitting.
+	VkSubmitInfo submitInfo = {
+	    .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+	    .commandBufferCount = 1,
+	    .pCommandBuffers = &cmd_buffer,
+	};
+
+	ret = vk->vkQueueSubmit(queue, 1, &submitInfo, fence);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "Error: Could not submit queue.\n");
+		goto out_fence;
+	}
+
+	// Then wait for the fence.
+	ret = vk->vkWaitForFences(vk->device, 1, &fence, VK_TRUE, 1000000000);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkWaitForFences: %s", vk_result_string(ret));
+		goto out_fence;
+	}
+
+	// Yes fall through.
+
+out_fence:
+	vk->vkDestroyFence(vk->device, fence, NULL);
+out:
+	vk->vkFreeCommandBuffers(vk->device, vk->cmd_pool, 1, &cmd_buffer);
+
+	return ret;
+}
+
+VkResult
+vk_init_cmd_pool(struct vk_bundle *vk)
+{
+	VkCommandPoolCreateInfo cmd_pool_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
+	    .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
+	    .queueFamilyIndex = vk->queue_family_index,
+	};
+
+	VkResult ret;
+	ret = vk->vkCreateCommandPool(vk->device, &cmd_pool_info, NULL,
+	                              &vk->cmd_pool);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateCommandPool: %s", vk_result_string(ret));
+	}
+
+	return ret;
+}
+
+
+/*
+ *
+ * Debug code.
+ *
+ */
+
+#define ENUM_TO_STR(r)                                                         \
+	case r: return #r
+
+static const char *
+vk_debug_report_string(VkDebugReportFlagBitsEXT code)
+{
+	switch (code) {
+		ENUM_TO_STR(VK_DEBUG_REPORT_INFORMATION_BIT_EXT);
+		ENUM_TO_STR(VK_DEBUG_REPORT_WARNING_BIT_EXT);
+		ENUM_TO_STR(VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT);
+		ENUM_TO_STR(VK_DEBUG_REPORT_ERROR_BIT_EXT);
+		ENUM_TO_STR(VK_DEBUG_REPORT_DEBUG_BIT_EXT);
+		ENUM_TO_STR(VK_DEBUG_REPORT_FLAG_BITS_MAX_ENUM_EXT);
+	}
+	return "UNKNOWN REPORT";
+}
+
+static VkBool32 VKAPI_PTR
+_validation_cb(VkDebugReportFlagsEXT flags,
+               VkDebugReportObjectTypeEXT object_type,
+               uint64_t object,
+               size_t location,
+               int32_t message_code,
+               const char *layer_prefix,
+               const char *message,
+               void *user_data)
+{
+	fprintf(stderr, "%s %s %lu:%d: %s\n", vk_debug_report_string(flags),
+	        layer_prefix, location, message_code, message);
+	return VK_FALSE;
+}
+
+DEBUG_GET_ONCE_BOOL_OPTION(vulkan_spew, "XRT_COMPOSITOR_VULKAN_SPEW", false)
+
+void
+vk_init_validation_callback(struct vk_bundle *vk)
+{
+	VkDebugReportFlagsEXT flags = 0;
+	flags |= VK_DEBUG_REPORT_ERROR_BIT_EXT;
+	flags |= VK_DEBUG_REPORT_WARNING_BIT_EXT;
+
+	if (debug_get_bool_option_vulkan_spew()) {
+		flags |= VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
+		flags |= VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
+		flags |= VK_DEBUG_REPORT_DEBUG_BIT_EXT;
+	}
+
+	VkDebugReportCallbackCreateInfoEXT info = {
+	    .sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT,
+	    .flags = flags,
+	    .pfnCallback = _validation_cb,
+	};
+
+	vk->vkCreateDebugReportCallbackEXT(vk->instance, &info, NULL,
+	                                   &vk->debug_report_cb);
+}
+
+void
+vk_destroy_validation_callback(struct vk_bundle *vk)
+{
+	if (vk->debug_report_cb != VK_NULL_HANDLE) {
+		vk->vkDestroyDebugReportCallbackEXT(vk->instance,
+		                                    vk->debug_report_cb, NULL);
+		vk->debug_report_cb = VK_NULL_HANDLE;
+	}
+}
+
+/*
+ *
+ * Function getting code.
+ *
+ */
+
+#define GET_PROC(vk, name) (PFN_##name) vk->vkGetInstanceProcAddr(NULL, #name);
+
+#define GET_INS_PROC(vk, name)                                                 \
+	(PFN_##name) vk->vkGetInstanceProcAddr(vk->instance, #name);
+
+#define GET_DEV_PROC(vk, name)                                                 \
+	(PFN_##name) vk->vkGetDeviceProcAddr(vk->device, #name);
+
+VkResult
+vk_get_instance_functions(struct vk_bundle *vk)
+{
+	// clang-format off
+	vk->vkDestroyInstance                         = GET_INS_PROC(vk, vkDestroyInstance);
+	vk->vkGetDeviceProcAddr                       = GET_INS_PROC(vk, vkGetDeviceProcAddr);
+	vk->vkCreateDevice                            = GET_INS_PROC(vk, vkCreateDevice);
+	vk->vkEnumeratePhysicalDevices                = GET_INS_PROC(vk, vkEnumeratePhysicalDevices);
+	vk->vkGetPhysicalDeviceProperties             = GET_INS_PROC(vk, vkGetPhysicalDeviceProperties);
+	vk->vkGetPhysicalDeviceMemoryProperties       = GET_INS_PROC(vk, vkGetPhysicalDeviceMemoryProperties);
+	vk->vkGetPhysicalDeviceQueueFamilyProperties  = GET_INS_PROC(vk, vkGetPhysicalDeviceQueueFamilyProperties);
+	vk->vkCreateDebugReportCallbackEXT            = GET_INS_PROC(vk, vkCreateDebugReportCallbackEXT);
+	vk->vkDestroyDebugReportCallbackEXT           = GET_INS_PROC(vk, vkDestroyDebugReportCallbackEXT);
+	vk->vkDestroySurfaceKHR                       = GET_INS_PROC(vk, vkDestroySurfaceKHR);
+	vk->vkGetPhysicalDeviceSurfaceCapabilitiesKHR = GET_INS_PROC(vk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
+	vk->vkGetPhysicalDeviceSurfaceFormatsKHR      = GET_INS_PROC(vk, vkGetPhysicalDeviceSurfaceFormatsKHR);
+	vk->vkGetPhysicalDeviceSurfacePresentModesKHR = GET_INS_PROC(vk, vkGetPhysicalDeviceSurfacePresentModesKHR);
+	vk->vkGetPhysicalDeviceSurfaceSupportKHR      = GET_INS_PROC(vk, vkGetPhysicalDeviceSurfaceSupportKHR);
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+	vk->vkCreateXcbSurfaceKHR = GET_INS_PROC(vk, vkCreateXcbSurfaceKHR);
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+	vk->vkCreateWaylandSurfaceKHR = GET_INS_PROC(vk, vkCreateWaylandSurfaceKHR);
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+	vk->vkCreateDisplayPlaneSurfaceKHR               = GET_INS_PROC(vk, vkCreateDisplayPlaneSurfaceKHR);
+	vk->vkGetDisplayPlaneCapabilitiesKHR             = GET_INS_PROC(vk, vkGetDisplayPlaneCapabilitiesKHR);
+	vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR = GET_INS_PROC(vk, vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
+	vk->vkGetDisplayModePropertiesKHR                = GET_INS_PROC(vk, vkGetDisplayModePropertiesKHR);
+	vk->vkAcquireXlibDisplayEXT                      = GET_INS_PROC(vk, vkAcquireXlibDisplayEXT);
+	vk->vkReleaseDisplayEXT                          = GET_INS_PROC(vk, vkReleaseDisplayEXT);
+	vk->vkGetRandROutputDisplayEXT                   = GET_INS_PROC(vk, vkGetRandROutputDisplayEXT);
+#endif
+	// clang-format on
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+vk_get_device_functions(struct vk_bundle *vk)
+{
+	// clang-format off
+	vk->vkDestroyDevice               = GET_DEV_PROC(vk, vkDestroyDevice);
+	vk->vkDeviceWaitIdle              = GET_DEV_PROC(vk, vkDeviceWaitIdle);
+	vk->vkAllocateMemory              = GET_DEV_PROC(vk, vkAllocateMemory);
+	vk->vkFreeMemory                  = GET_DEV_PROC(vk, vkFreeMemory);
+	vk->vkMapMemory                   = GET_DEV_PROC(vk, vkMapMemory);
+	vk->vkUnmapMemory                 = GET_DEV_PROC(vk, vkUnmapMemory);
+	vk->vkGetMemoryFdKHR              = GET_DEV_PROC(vk, vkGetMemoryFdKHR);
+	vk->vkCreateBuffer                = GET_DEV_PROC(vk, vkCreateBuffer);
+	vk->vkDestroyBuffer               = GET_DEV_PROC(vk, vkDestroyBuffer);
+	vk->vkBindBufferMemory            = GET_DEV_PROC(vk, vkBindBufferMemory);
+	vk->vkGetBufferMemoryRequirements = GET_DEV_PROC(vk, vkGetBufferMemoryRequirements);
+	vk->vkCreateImage                 = GET_DEV_PROC(vk, vkCreateImage);
+	vk->vkGetImageMemoryRequirements  = GET_DEV_PROC(vk, vkGetImageMemoryRequirements);
+	vk->vkBindImageMemory             = GET_DEV_PROC(vk, vkBindImageMemory);
+	vk->vkDestroyImage                = GET_DEV_PROC(vk, vkDestroyImage);
+	vk->vkCreateImageView             = GET_DEV_PROC(vk, vkCreateImageView);
+	vk->vkDestroyImageView            = GET_DEV_PROC(vk, vkDestroyImageView);
+	vk->vkCreateSampler               = GET_DEV_PROC(vk, vkCreateSampler);
+	vk->vkDestroySampler              = GET_DEV_PROC(vk, vkDestroySampler);
+	vk->vkCreateShaderModule          = GET_DEV_PROC(vk, vkCreateShaderModule);
+	vk->vkDestroyShaderModule         = GET_DEV_PROC(vk, vkDestroyShaderModule);
+	vk->vkCreateCommandPool           = GET_DEV_PROC(vk, vkCreateCommandPool);
+	vk->vkDestroyCommandPool          = GET_DEV_PROC(vk, vkDestroyCommandPool);
+	vk->vkAllocateCommandBuffers      = GET_DEV_PROC(vk, vkAllocateCommandBuffers);
+	vk->vkBeginCommandBuffer          = GET_DEV_PROC(vk, vkBeginCommandBuffer);
+	vk->vkCmdPipelineBarrier          = GET_DEV_PROC(vk, vkCmdPipelineBarrier);
+	vk->vkCmdBeginRenderPass          = GET_DEV_PROC(vk, vkCmdBeginRenderPass);
+	vk->vkCmdSetScissor               = GET_DEV_PROC(vk, vkCmdSetScissor);
+	vk->vkCmdSetViewport              = GET_DEV_PROC(vk, vkCmdSetViewport);
+	vk->vkCmdClearColorImage          = GET_DEV_PROC(vk, vkCmdClearColorImage);
+	vk->vkCmdEndRenderPass            = GET_DEV_PROC(vk, vkCmdEndRenderPass);
+	vk->vkCmdBindDescriptorSets       = GET_DEV_PROC(vk, vkCmdBindDescriptorSets);
+	vk->vkCmdBindPipeline             = GET_DEV_PROC(vk, vkCmdBindPipeline);
+	vk->vkCmdDraw                     = GET_DEV_PROC(vk, vkCmdDraw);
+	vk->vkEndCommandBuffer            = GET_DEV_PROC(vk, vkEndCommandBuffer);
+	vk->vkFreeCommandBuffers          = GET_DEV_PROC(vk, vkFreeCommandBuffers);
+	vk->vkCreateRenderPass            = GET_DEV_PROC(vk, vkCreateRenderPass);
+	vk->vkDestroyRenderPass           = GET_DEV_PROC(vk, vkDestroyRenderPass);
+	vk->vkCreateFramebuffer           = GET_DEV_PROC(vk, vkCreateFramebuffer);
+	vk->vkDestroyFramebuffer          = GET_DEV_PROC(vk, vkDestroyFramebuffer);
+	vk->vkCreatePipelineCache         = GET_DEV_PROC(vk, vkCreatePipelineCache);
+	vk->vkDestroyPipelineCache        = GET_DEV_PROC(vk, vkDestroyPipelineCache);
+	vk->vkCreateDescriptorPool        = GET_DEV_PROC(vk, vkCreateDescriptorPool);
+	vk->vkDestroyDescriptorPool       = GET_DEV_PROC(vk, vkDestroyDescriptorPool);
+	vk->vkAllocateDescriptorSets      = GET_DEV_PROC(vk, vkAllocateDescriptorSets);
+	vk->vkCreateGraphicsPipelines     = GET_DEV_PROC(vk, vkCreateGraphicsPipelines);
+	vk->vkDestroyPipeline             = GET_DEV_PROC(vk, vkDestroyPipeline);
+	vk->vkCreatePipelineLayout        = GET_DEV_PROC(vk, vkCreatePipelineLayout);
+	vk->vkDestroyPipelineLayout       = GET_DEV_PROC(vk, vkDestroyPipelineLayout);
+	vk->vkCreateDescriptorSetLayout   = GET_DEV_PROC(vk, vkCreateDescriptorSetLayout);
+	vk->vkUpdateDescriptorSets        = GET_DEV_PROC(vk, vkUpdateDescriptorSets);
+	vk->vkDestroyDescriptorSetLayout  = GET_DEV_PROC(vk, vkDestroyDescriptorSetLayout);
+	vk->vkGetDeviceQueue              = GET_DEV_PROC(vk, vkGetDeviceQueue);
+	vk->vkQueueSubmit                 = GET_DEV_PROC(vk, vkQueueSubmit);
+	vk->vkQueueWaitIdle               = GET_DEV_PROC(vk, vkQueueWaitIdle);
+	vk->vkCreateSemaphore             = GET_DEV_PROC(vk, vkCreateSemaphore);
+	vk->vkDestroySemaphore            = GET_DEV_PROC(vk, vkDestroySemaphore);
+	vk->vkCreateFence                 = GET_DEV_PROC(vk, vkCreateFence);
+	vk->vkWaitForFences               = GET_DEV_PROC(vk, vkWaitForFences);
+	vk->vkDestroyFence                = GET_DEV_PROC(vk, vkDestroyFence);
+	vk->vkCreateSwapchainKHR          = GET_DEV_PROC(vk, vkCreateSwapchainKHR);
+	vk->vkDestroySwapchainKHR         = GET_DEV_PROC(vk, vkDestroySwapchainKHR);
+	vk->vkGetSwapchainImagesKHR       = GET_DEV_PROC(vk, vkGetSwapchainImagesKHR);
+	vk->vkAcquireNextImageKHR         = GET_DEV_PROC(vk, vkAcquireNextImageKHR);
+	vk->vkQueuePresentKHR             = GET_DEV_PROC(vk, vkQueuePresentKHR);
+	// clang-format on
+
+	return VK_SUCCESS;
+}
+
+
+/*
+ *
+ * Creation code.
+ *
+ */
+
+static VkResult
+vk_select_physical_device(struct vk_bundle *vk)
+{
+	VkPhysicalDevice physical_devices[16];
+	uint32_t gpu_count = ARRAY_SIZE(physical_devices);
+	VkResult ret;
+
+	ret = vk->vkEnumeratePhysicalDevices(vk->instance, &gpu_count,
+	                                     physical_devices);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkEnumeratePhysicalDevices: %s",
+		         vk_result_string(ret));
+		return ret;
+	}
+
+	if (gpu_count < 1) {
+		VK_DEBUG(vk, "No physical device found!");
+		return VK_ERROR_DEVICE_LOST;
+	}
+
+	if (gpu_count > 1) {
+		VK_DEBUG(vk, "Can not deal well with multiple devices.");
+	}
+
+	// as a first-step to 'intelligent' selection, prefer a 'discrete' gpu
+	// if it is present
+	uint32_t gpu_index = 0;
+	for (uint32_t i = 0; i < gpu_count; i++) {
+		VkPhysicalDeviceProperties pdp;
+		vk->vkGetPhysicalDeviceProperties(physical_devices[i], &pdp);
+		if (pdp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+			gpu_index = i;
+		}
+	}
+
+	vk->physical_device = physical_devices[gpu_index];
+
+
+	// Fill out the device memory props as well.
+	vk->vkGetPhysicalDeviceMemoryProperties(vk->physical_device,
+	                                        &vk->device_memory_props);
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+vk_find_graphics_queue(struct vk_bundle *vk, uint32_t *out_graphics_queue)
+{
+	/* Find the first graphics queue */
+	uint32_t num_queues = 0;
+	vk->vkGetPhysicalDeviceQueueFamilyProperties(vk->physical_device,
+	                                             &num_queues, NULL);
+
+	VkQueueFamilyProperties *queue_family_props =
+	    (VkQueueFamilyProperties *)malloc(sizeof(VkQueueFamilyProperties) *
+	                                      num_queues);
+
+	vk->vkGetPhysicalDeviceQueueFamilyProperties(
+	    vk->physical_device, &num_queues, queue_family_props);
+
+	if (num_queues == 0) {
+		VK_DEBUG(vk, "Failed to get queue properties");
+		goto err_free;
+	}
+
+	uint32_t i = 0;
+	for (i = 0; i < num_queues; i++) {
+		if (queue_family_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+			break;
+		}
+	}
+
+	if (i >= num_queues) {
+		VK_DEBUG(vk, "No graphics queue found");
+		goto err_free;
+	}
+
+	*out_graphics_queue = i;
+
+	free(queue_family_props);
+
+	return VK_SUCCESS;
+
+err_free:
+	free(queue_family_props);
+	return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+VkResult
+vk_create_device(struct vk_bundle *vk)
+{
+	VkResult ret;
+
+	ret = vk_select_physical_device(vk);
+	if (ret != VK_SUCCESS) {
+		return ret;
+	}
+
+	VkPhysicalDeviceFeatures *enabled_features = NULL;
+
+	float queue_priority = 0.0f;
+	VkDeviceQueueCreateInfo queue_create_info = {
+	    .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+	    .queueCount = 1,
+	    .pQueuePriorities = &queue_priority,
+	};
+
+	ret = vk_find_graphics_queue(vk, &queue_create_info.queueFamilyIndex);
+	if (ret != VK_SUCCESS) {
+		return ret;
+	}
+
+	const char *device_extensions[] = {
+	    VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+	    VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
+	    VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
+	    VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
+	    // VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
+	};
+
+	VkDeviceCreateInfo device_create_info = {
+	    .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+	    .queueCreateInfoCount = 1,
+	    .pQueueCreateInfos = &queue_create_info,
+	    .pEnabledFeatures = enabled_features,
+	    .enabledExtensionCount = ARRAY_SIZE(device_extensions),
+	    .ppEnabledExtensionNames = device_extensions,
+	};
+
+	ret = vk->vkCreateDevice(vk->physical_device, &device_create_info, NULL,
+	                         &vk->device);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkCreateDevice: %s", vk_result_string(ret));
+		return ret;
+	}
+
+	ret = vk_get_device_functions(vk);
+	if (ret != VK_SUCCESS) {
+		goto err_destroy;
+	}
+
+	return ret;
+
+err_destroy:
+	vk->vkDestroyDevice(vk->device, NULL);
+	vk->device = NULL;
+
+	return ret;
+}
+
+VkResult
+vk_init_from_given(struct vk_bundle *vk,
+                   PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
+                   VkInstance instance,
+                   VkPhysicalDevice physical_device,
+                   VkDevice device,
+                   uint32_t queue_family_index,
+                   uint32_t queue_index)
+{
+	VkResult ret;
+
+	// First memset it clear.
+	memset(vk, 0, sizeof(*vk));
+
+	vk->vkGetInstanceProcAddr = vkGetInstanceProcAddr;
+	vk->instance = instance;
+	vk->physical_device = physical_device;
+	vk->device = device;
+	vk->queue_family_index = queue_family_index;
+	vk->queue_index = queue_index;
+
+	// Not really needed but just in case.
+	vk->vkCreateInstance = GET_PROC(vk, vkCreateInstance);
+
+	// Fill in all instance functions.
+	ret = vk_get_instance_functions(vk);
+	if (ret != VK_SUCCESS) {
+		goto err_memset;
+	}
+
+	// Fill out the device memory props here, as we are
+	// passed a vulkan context and do not call selectPhysicalDevice()
+	vk->vkGetPhysicalDeviceMemoryProperties(vk->physical_device,
+	                                        &vk->device_memory_props);
+
+	// Fill in all device functions.
+	ret = vk_get_device_functions(vk);
+	if (ret != VK_SUCCESS) {
+		goto err_memset;
+	}
+
+	// Create the pool.
+	ret = vk_init_cmd_pool(vk);
+	if (ret != VK_SUCCESS) {
+		goto err_memset;
+	}
+
+	return VK_SUCCESS;
+
+err_memset:
+	memset(vk, 0, sizeof(*vk));
+	return ret;
+}
diff --git a/src/xrt/compositor/common/comp_vk.h b/src/xrt/compositor/common/comp_vk.h
new file mode 100644
index 000000000..d917e09c0
--- /dev/null
+++ b/src/xrt/compositor/common/comp_vk.h
@@ -0,0 +1,339 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Common Vulkan code header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp_common
+ */
+
+#pragma once
+
+#include "xrt/xrt_compositor.h"
+#include "xrt/xrt_vulkan_includes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+/*!
+ * A bundle of Vulkan functions and objects, shared between @ref comp and
+ * @ref comp_client.
+ *
+ * @ingroup comp_common
+ */
+struct vk_bundle
+{
+	bool print;
+
+	VkInstance instance;
+	VkPhysicalDevice physical_device;
+	VkDevice device;
+	uint32_t queue_family_index;
+	uint32_t queue_index;
+
+	VkDebugReportCallbackEXT debug_report_cb;
+
+	VkPhysicalDeviceMemoryProperties device_memory_props;
+
+	VkCommandPool cmd_pool;
+
+	// clang-format off
+	// Loader functions
+	PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
+	PFN_vkCreateInstance vkCreateInstance;
+
+	// Instance functions.
+	PFN_vkDestroyInstance vkDestroyInstance;
+	PFN_vkCreateDevice vkCreateDevice;
+	PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT;
+	PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT;
+	PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
+	PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+	PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR;
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+	PFN_vkCreateWaylandSurfaceKHR vkCreateWaylandSurfaceKHR;
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+	PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR;
+	PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR;
+	PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR;
+	PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR;
+	PFN_vkAcquireXlibDisplayEXT vkAcquireXlibDisplayEXT;
+	PFN_vkReleaseDisplayEXT vkReleaseDisplayEXT;
+	PFN_vkGetRandROutputDisplayEXT vkGetRandROutputDisplayEXT;
+#endif
+
+
+	// Physical device functions.
+	PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
+	PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
+	PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
+
+	PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+	PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
+	PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
+	PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
+
+
+	// Device functions.
+	PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
+	PFN_vkDestroyDevice vkDestroyDevice;
+	PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
+
+	PFN_vkAllocateMemory vkAllocateMemory;
+	PFN_vkFreeMemory vkFreeMemory;
+	PFN_vkMapMemory vkMapMemory;
+	PFN_vkUnmapMemory vkUnmapMemory;
+	PFN_vkGetMemoryFdKHR vkGetMemoryFdKHR;
+
+	PFN_vkCreateBuffer vkCreateBuffer;
+	PFN_vkDestroyBuffer vkDestroyBuffer;
+	PFN_vkBindBufferMemory vkBindBufferMemory;
+	PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
+
+	PFN_vkCreateImage vkCreateImage;
+	PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
+	PFN_vkBindImageMemory vkBindImageMemory;
+	PFN_vkDestroyImage vkDestroyImage;
+	PFN_vkCreateImageView vkCreateImageView;
+	PFN_vkDestroyImageView vkDestroyImageView;
+
+	PFN_vkCreateSampler vkCreateSampler;
+	PFN_vkDestroySampler vkDestroySampler;
+
+	PFN_vkCreateShaderModule vkCreateShaderModule;
+	PFN_vkDestroyShaderModule vkDestroyShaderModule;
+
+	PFN_vkCreateCommandPool vkCreateCommandPool;
+	PFN_vkDestroyCommandPool vkDestroyCommandPool;
+	PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
+	PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
+	PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
+	PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
+	PFN_vkCmdSetScissor vkCmdSetScissor;
+	PFN_vkCmdSetViewport vkCmdSetViewport;
+	PFN_vkCmdClearColorImage vkCmdClearColorImage;
+	PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
+	PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
+	PFN_vkCmdBindPipeline vkCmdBindPipeline;
+	PFN_vkCmdDraw vkCmdDraw;
+	PFN_vkEndCommandBuffer vkEndCommandBuffer;
+	PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
+
+	PFN_vkCreateRenderPass vkCreateRenderPass;
+	PFN_vkDestroyRenderPass vkDestroyRenderPass;
+	PFN_vkCreateFramebuffer vkCreateFramebuffer;
+	PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
+	PFN_vkCreatePipelineCache vkCreatePipelineCache;
+	PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
+	PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
+	PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
+	PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
+	PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
+	PFN_vkDestroyPipeline vkDestroyPipeline;
+	PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
+	PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
+	PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
+	PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
+	PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
+
+	PFN_vkGetDeviceQueue vkGetDeviceQueue;
+	PFN_vkQueueSubmit vkQueueSubmit;
+	PFN_vkQueueWaitIdle vkQueueWaitIdle;
+
+	PFN_vkCreateSemaphore vkCreateSemaphore;
+	PFN_vkDestroySemaphore vkDestroySemaphore;
+
+	PFN_vkCreateFence vkCreateFence;
+	PFN_vkWaitForFences vkWaitForFences;
+	PFN_vkDestroyFence vkDestroyFence;
+
+	PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
+	PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
+	PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
+	PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
+	PFN_vkQueuePresentKHR vkQueuePresentKHR;
+	// clang-format on
+};
+
+
+/*
+ *
+ * String helper functions.
+ *
+ */
+
+const char *
+vk_result_string(VkResult code);
+
+const char *
+vk_color_format_string(VkFormat code);
+
+const char *
+vk_present_mode_string(VkPresentModeKHR code);
+
+const char *
+vk_power_state_string(VkDisplayPowerStateEXT code);
+
+const char *
+vk_color_space_string(VkColorSpaceKHR code);
+
+
+/*
+ *
+ * Function and helpers.
+ *
+ */
+
+#define VK_DEBUG(vk, ...)                                                      \
+	do {                                                                   \
+		if (vk->print) {                                               \
+			fprintf(stderr, "%s - ", __func__);                    \
+			fprintf(stderr, __VA_ARGS__);                          \
+			fprintf(stderr, "\n");                                 \
+		}                                                              \
+	} while (false)
+
+#define VK_ERROR(vk, ...)                                                      \
+	do {                                                                   \
+		fprintf(stderr, "%s - ", __func__);                            \
+		fprintf(stderr, __VA_ARGS__);                                  \
+		fprintf(stderr, "\n");                                         \
+	} while (false)
+
+/*!
+ * @ingroup comp_common
+ */
+void
+vk_init_validation_callback(struct vk_bundle *vk);
+
+/*!
+ * @ingroup comp_common
+ */
+void
+vk_destroy_validation_callback(struct vk_bundle *vk);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_get_instance_functions(struct vk_bundle *vk);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_init_cmd_pool(struct vk_bundle *vk);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_create_device(struct vk_bundle *vk);
+
+/*!
+ * Initialize a bundle with objects given to us by client code,
+ * used by @ref client_vk_compositor in @ref comp_client.
+ *
+ * @ingroup comp_common
+ */
+VkResult
+vk_init_from_given(struct vk_bundle *vk,
+                   PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr,
+                   VkInstance instance,
+                   VkPhysicalDevice physical_device,
+                   VkDevice device,
+                   uint32_t queue_family_index,
+                   uint32_t queue_index);
+
+/*!
+ * @ingroup comp_common
+ */
+bool
+vk_get_memory_type(struct vk_bundle *vk,
+                   uint32_t type_bits,
+                   VkMemoryPropertyFlags memory_props,
+                   uint32_t *out_type_id);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_create_image_from_fd(struct vk_bundle *vk,
+                        int64_t format,
+                        uint32_t width,
+                        uint32_t height,
+                        uint32_t mip_count,
+                        struct xrt_image_fd *image_fd,
+                        VkImage *out_image,
+                        VkDeviceMemory *out_mem);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_create_image_simple(struct vk_bundle *vk,
+                       uint32_t width,
+                       uint32_t height,
+                       VkFormat format,
+                       VkDeviceMemory *out_mem,
+                       VkImage *out_image);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_create_sampler(struct vk_bundle *vk, VkSampler *out_sampler);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_create_view(struct vk_bundle *vk,
+               VkImage image,
+               VkFormat format,
+               VkImageView *out_view);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_init_cmd_buffer(struct vk_bundle *vk, VkCommandBuffer *out_cmd_buffer);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_set_image_layout(struct vk_bundle *vk,
+                    VkCommandBuffer cmd_buffer,
+                    VkImage image,
+                    VkAccessFlags src_access_mask,
+                    VkAccessFlags dst_access_mask,
+                    VkImageLayout old_layout,
+                    VkImageLayout new_layout,
+                    VkImageSubresourceRange subresource_range);
+
+/*!
+ * @ingroup comp_common
+ */
+VkResult
+vk_submit_cmd_buffer(struct vk_bundle *vk, VkCommandBuffer cmd_buffer);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/common/comp_vk_swapchain.c b/src/xrt/compositor/common/comp_vk_swapchain.c
new file mode 100644
index 000000000..1a6c95207
--- /dev/null
+++ b/src/xrt/compositor/common/comp_vk_swapchain.c
@@ -0,0 +1,389 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Vulkan swapchain code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "comp_vk_swapchain.h"
+
+
+/*
+ *
+ * Pre declare functions.
+ *
+ */
+
+static void
+vk_swapchain_create_image_view(struct vk_bundle *vk,
+                               VkImage image,
+                               VkFormat format,
+                               VkImageView *view);
+
+static void
+vk_swapchain_create_image_views(struct vk_swapchain *sc);
+
+static void
+vk_swapchain_destroy_old(struct vk_swapchain *sc, VkSwapchainKHR old);
+
+static VkExtent2D
+vk_swapchain_select_extent(struct vk_swapchain *sc,
+                           VkSurfaceCapabilitiesKHR caps,
+                           uint32_t width,
+                           uint32_t height);
+
+static bool
+_find_surface_format(struct vk_swapchain *sc,
+                     VkSurfaceKHR surface,
+                     VkSurfaceFormatKHR *format);
+
+static bool
+_check_surface_present_mode(struct vk_bundle *vk,
+                            VkSurfaceKHR surface,
+                            VkPresentModeKHR present_mode);
+
+
+/*
+ *
+ * Functions!
+ *
+ */
+
+void
+vk_swapchain_init(struct vk_swapchain *sc,
+                  struct vk_bundle *vk,
+                  vk_swapchain_cb dimension_cb,
+                  void *priv)
+{
+	sc->vk = vk;
+	sc->cb_priv = priv;
+	sc->dimension_cb = dimension_cb;
+}
+
+void
+vk_swapchain_create(struct vk_swapchain *sc,
+                    uint32_t width,
+                    uint32_t height,
+                    VkFormat color_format,
+                    VkColorSpaceKHR color_space,
+                    VkPresentModeKHR present_mode)
+{
+	VkBool32 supported;
+	VkResult ret;
+
+	sc->image_count = 0;
+	sc->swap_chain = VK_NULL_HANDLE;
+	sc->color_format = color_format;
+	sc->color_space = color_space;
+	sc->present_mode = present_mode;
+
+	// Sanity check.
+	sc->vk->vkGetPhysicalDeviceSurfaceSupportKHR(sc->vk->physical_device, 0,
+	                                             sc->surface, &supported);
+	if (!supported) {
+		VK_ERROR(sc->vk,
+		         "vkGetPhysicalDeviceSurfaceSupportKHR: "
+		         "surface not supported!");
+	}
+
+
+	// More sanity checks.
+	if (!_check_surface_present_mode(sc->vk, sc->surface,
+	                                 sc->present_mode)) {
+		return;
+	}
+
+	// Find the correct format.
+	if (!_find_surface_format(sc, sc->surface, &sc->surface_format)) {
+		return;
+	}
+
+	// Get the caps first.
+	VkSurfaceCapabilitiesKHR surface_caps;
+	ret = sc->vk->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+	    sc->vk->physical_device, sc->surface, &surface_caps);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(sc->vk,
+		         "vkGetPhysicalDeviceSurfaceCapabilitiesKHR: %s",
+		         vk_result_string(ret));
+		return;
+	}
+
+
+	VkSwapchainKHR old_swap_chain = sc->swap_chain;
+	VkExtent2D extent =
+	    vk_swapchain_select_extent(sc, surface_caps, width, height);
+
+	VkSwapchainCreateInfoKHR swap_chain_info = {
+	    .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
+	    .surface = sc->surface,
+	    .minImageCount = surface_caps.minImageCount,
+	    .imageFormat = sc->surface_format.format,
+	    .imageColorSpace = sc->surface_format.colorSpace,
+	    .imageExtent =
+	        {
+	            .width = extent.width,
+	            .height = extent.height,
+	        },
+	    .imageArrayLayers = 1,
+	    .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+	    .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
+	    .queueFamilyIndexCount = 0,
+	    .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+	    .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
+	    .presentMode = sc->present_mode,
+	    .clipped = VK_TRUE,
+	    .oldSwapchain = old_swap_chain,
+	};
+
+	ret = sc->vk->vkCreateSwapchainKHR(sc->vk->device, &swap_chain_info,
+	                                   NULL, &sc->swap_chain);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(sc->vk, "vkCreateSwapchainKHR: %s",
+		         vk_result_string(ret));
+		return;
+	}
+
+	if (old_swap_chain != VK_NULL_HANDLE) {
+		vk_swapchain_destroy_old(sc, old_swap_chain);
+	}
+
+	vk_swapchain_create_image_views(sc);
+}
+
+static VkExtent2D
+vk_swapchain_select_extent(struct vk_swapchain *sc,
+                           VkSurfaceCapabilitiesKHR caps,
+                           uint32_t width,
+                           uint32_t height)
+{
+	VkExtent2D extent;
+	memset(&extent, 0, sizeof(extent));
+
+	// If width (and height) equals the special value 0xFFFFFFFF,
+	// the size of the surface will be set by the swapchain
+	if (caps.currentExtent.width == (uint32_t)-1) {
+		extent.width = width;
+		extent.height = height;
+	} else {
+		extent = caps.currentExtent;
+		if (caps.currentExtent.width != width ||
+		    caps.currentExtent.height != height) {
+			VK_DEBUG(sc->vk,
+			         "Using swap chain extent dimensions %dx%d "
+			         "instead of requested %dx%d.",
+			         caps.currentExtent.width,
+			         caps.currentExtent.height, width, height);
+			sc->dimension_cb(caps.currentExtent.width,
+			                 caps.currentExtent.height,
+			                 sc->cb_priv);
+		}
+	}
+	return extent;
+}
+
+static void
+vk_swapchain_destroy_old(struct vk_swapchain *sc, VkSwapchainKHR old)
+{
+	for (uint32_t i = 0; i < sc->image_count; i++) {
+		sc->vk->vkDestroyImageView(sc->vk->device, sc->buffers[i].view,
+		                           NULL);
+	}
+
+	sc->vk->vkDestroySwapchainKHR(sc->vk->device, old, NULL);
+}
+
+VkResult
+vk_swapchain_acquire_next_image(struct vk_swapchain *sc,
+                                VkSemaphore semaphore,
+                                uint32_t *index)
+{
+	return sc->vk->vkAcquireNextImageKHR(sc->vk->device, sc->swap_chain,
+	                                     UINT64_MAX, semaphore,
+	                                     VK_NULL_HANDLE, index);
+}
+
+VkResult
+vk_swapchain_present(struct vk_swapchain *sc,
+                     VkQueue queue,
+                     uint32_t index,
+                     VkSemaphore semaphore)
+{
+	VkPresentInfoKHR presentInfo = {
+	    .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
+	    .waitSemaphoreCount = 1,
+	    .pWaitSemaphores = &semaphore,
+	    .swapchainCount = 1,
+	    .pSwapchains = &sc->swap_chain,
+	    .pImageIndices = &index,
+	};
+
+	return sc->vk->vkQueuePresentKHR(queue, &presentInfo);
+}
+
+static bool
+_find_surface_format(struct vk_swapchain *sc,
+                     VkSurfaceKHR surface,
+                     VkSurfaceFormatKHR *format)
+{
+	uint32_t num_formats;
+	VkSurfaceFormatKHR *formats = NULL;
+	sc->vk->vkGetPhysicalDeviceSurfaceFormatsKHR(
+	    sc->vk->physical_device, surface, &num_formats, NULL);
+
+	if (num_formats != 0) {
+		formats = (VkSurfaceFormatKHR *)malloc(
+		    sizeof(VkSurfaceFormatKHR) * num_formats);
+		sc->vk->vkGetPhysicalDeviceSurfaceFormatsKHR(
+		    sc->vk->physical_device, surface, &num_formats, formats);
+	} else {
+		VK_ERROR(sc->vk, "Could not enumerate surface formats.");
+		return false;
+	}
+
+	for (uint32_t i = 0; i < num_formats; i++) {
+		if (formats[i].format == sc->color_format &&
+		    formats[i].colorSpace == sc->color_space) {
+			format->format = formats[i].format;
+			format->colorSpace = formats[i].colorSpace;
+			free(formats);
+			return true;
+		}
+	}
+
+	free(formats);
+	VK_ERROR(sc->vk, "Requested format not supported.");
+	return false;
+}
+
+static bool
+_check_surface_present_mode(struct vk_bundle *vk,
+                            VkSurfaceKHR surface,
+                            VkPresentModeKHR present_mode)
+{
+	uint32_t num_present_modes;
+	VkPresentModeKHR *present_modes;
+	vk->vkGetPhysicalDeviceSurfacePresentModesKHR(
+	    vk->physical_device, surface, &num_present_modes, NULL);
+
+	if (num_present_modes != 0) {
+		present_modes = (VkPresentModeKHR *)malloc(
+		    sizeof(VkPresentModeKHR) * num_present_modes);
+		vk->vkGetPhysicalDeviceSurfacePresentModesKHR(
+		    vk->physical_device, surface, &num_present_modes,
+		    present_modes);
+	} else {
+		VK_ERROR(vk, "Could not enumerate present modes.");
+		return false;
+	}
+
+	for (uint32_t i = 0; i < num_present_modes; i++) {
+		if (present_modes[i] == present_mode) {
+			free(present_modes);
+			return true;
+		}
+	}
+
+	free(present_modes);
+	VK_ERROR(vk, "Requested present mode not supported.\n");
+	return false;
+}
+
+static void
+vk_swapchain_create_image_views(struct vk_swapchain *sc)
+{
+	sc->vk->vkGetSwapchainImagesKHR(sc->vk->device, sc->swap_chain,
+	                                &sc->image_count, NULL);
+	assert(sc->image_count > 0);
+	VK_DEBUG(sc->vk, "Creating %d image views.", sc->image_count);
+
+	VkImage *images = (VkImage *)malloc(sizeof(VkImage) * sc->image_count);
+	sc->vk->vkGetSwapchainImagesKHR(sc->vk->device, sc->swap_chain,
+	                                &sc->image_count, images);
+
+	if (sc->buffers != NULL) {
+		free(sc->buffers);
+	}
+
+	sc->buffers = (struct vk_swapchain_buffer *)malloc(
+	    sizeof(struct vk_swapchain_buffer) * sc->image_count);
+
+	for (uint32_t i = 0; i < sc->image_count; i++) {
+		sc->buffers[i].image = images[i];
+		vk_swapchain_create_image_view(sc->vk, sc->buffers[i].image,
+		                               sc->surface_format.format,
+		                               &sc->buffers[i].view);
+	}
+
+	free(images);
+}
+
+void
+vk_swapchain_cleanup(struct vk_swapchain *sc)
+{
+	for (uint32_t i = 0; i < sc->image_count; i++) {
+		if (sc->buffers[i].view) {
+			sc->vk->vkDestroyImageView(sc->vk->device,
+			                           sc->buffers[i].view, NULL);
+			sc->buffers[i].view = VK_NULL_HANDLE;
+		}
+	}
+
+
+	if (sc->swap_chain != VK_NULL_HANDLE) {
+		sc->vk->vkDestroySwapchainKHR(sc->vk->device, sc->swap_chain,
+		                              NULL);
+		sc->swap_chain = VK_NULL_HANDLE;
+	}
+
+	if (sc->surface != VK_NULL_HANDLE) {
+		sc->vk->vkDestroySurfaceKHR(sc->vk->instance, sc->surface,
+		                            NULL);
+		sc->swap_chain = VK_NULL_HANDLE;
+	}
+}
+
+static void
+vk_swapchain_create_image_view(struct vk_bundle *vk,
+                               VkImage image,
+                               VkFormat format,
+                               VkImageView *view)
+{
+	VkResult ret;
+
+	VkImageViewCreateInfo view_create_info = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
+	    .image = image,
+	    .viewType = VK_IMAGE_VIEW_TYPE_2D,
+	    .format = format,
+	    .components =
+	        {
+	            .r = VK_COMPONENT_SWIZZLE_R,
+	            .g = VK_COMPONENT_SWIZZLE_G,
+	            .b = VK_COMPONENT_SWIZZLE_B,
+	            .a = VK_COMPONENT_SWIZZLE_A,
+	        },
+	    .subresourceRange =
+	        {
+	            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	            .baseMipLevel = 0,
+	            .levelCount = 1,
+	            .baseArrayLayer = 0,
+	            .layerCount = 1,
+	        },
+	};
+
+	ret = vk->vkCreateImageView(vk->device, &view_create_info, NULL, view);
+	if (ret != VK_SUCCESS) {
+		VK_ERROR(vk, "vkCreateImageView: %s", vk_result_string(ret));
+	}
+}
diff --git a/src/xrt/compositor/common/comp_vk_swapchain.h b/src/xrt/compositor/common/comp_vk_swapchain.h
new file mode 100644
index 000000000..5e9d86b9f
--- /dev/null
+++ b/src/xrt/compositor/common/comp_vk_swapchain.h
@@ -0,0 +1,133 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Vulkan swapchain code header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp_client
+ */
+
+#pragma once
+
+#include "common/comp_vk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs.
+ *
+ */
+
+/*!
+ * Callback when a @ref vk_swapchain changes size.
+ *
+ * @ingroup comp_common
+ */
+typedef void (*vk_swapchain_cb)(uint32_t width, uint32_t height, void *priv);
+
+/*!
+ * A pair of VkImage and VkImageView.
+ *
+ * @ingroup comp_common
+ */
+struct vk_swapchain_buffer
+{
+	VkImage image;
+	VkImageView view;
+};
+
+/*!
+ * Wraps and manage VkSwapchainKHR and VkSurfaceKHR, used by @ref comp code.
+ *
+ * @ingroup comp_common
+ */
+struct vk_swapchain
+{
+	struct vk_bundle *vk;
+
+	VkSwapchainKHR swap_chain;
+
+	VkSurfaceKHR surface;
+	VkSurfaceFormatKHR surface_format;
+
+	struct vk_swapchain_buffer *buffers;
+	uint32_t image_count;
+
+	VkFormat color_format;
+	VkColorSpaceKHR color_space;
+	VkPresentModeKHR present_mode;
+
+	void *cb_priv;
+	vk_swapchain_cb dimension_cb;
+};
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+/*!
+ * Wraps and manage VkSwapchainKHR and VkSurfaceKHR, used by @ref comp code.
+ *
+ * @ingroup comp_common
+ */
+void
+vk_swapchain_init(struct vk_swapchain *sc,
+                  struct vk_bundle *vk,
+                  vk_swapchain_cb dimension_cb,
+                  void *priv);
+
+/*!
+ * Initialize the given @ref vk_swapchain, does not allocate.
+ *
+ * @ingroup comp_common
+ */
+void
+vk_swapchain_create(struct vk_swapchain *sc,
+                    uint32_t width,
+                    uint32_t height,
+                    VkFormat color_format,
+                    VkColorSpaceKHR color_space,
+                    VkPresentModeKHR present_mode);
+
+/*!
+ * Acquire a image index from the given @ref vk_swapchain for rendering.
+ *
+ * @ingroup comp_common
+ */
+VkResult
+vk_swapchain_acquire_next_image(struct vk_swapchain *sc,
+                                VkSemaphore semaphore,
+                                uint32_t *index);
+
+/*!
+ * Make the given @ref vk_swapchain present the next acquired image.
+ *
+ * @ingroup comp_common
+ */
+VkResult
+vk_swapchain_present(struct vk_swapchain *sc,
+                     VkQueue queue,
+                     uint32_t index,
+                     VkSemaphore semaphore);
+
+/*!
+ * Free all managed resources on the given @ref vk_swapchain,
+ * does not free the struct itself.
+ *
+ * @ingroup comp_common
+ */
+void
+vk_swapchain_cleanup(struct vk_swapchain *sc);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_client_interface.h b/src/xrt/compositor/main/comp_client_interface.h
new file mode 100644
index 000000000..d22f46914
--- /dev/null
+++ b/src/xrt/compositor/main/comp_client_interface.h
@@ -0,0 +1,30 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interface for client code to compositor.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_compositor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * Create the compositor instance using the given device. Used by the client
+ * code and implemented by the main compositor code.
+ */
+struct xrt_compositor_fd*
+comp_compositor_create(struct xrt_device* xdev, bool flip_y);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c
new file mode 100644
index 000000000..d1a04399a
--- /dev/null
+++ b/src/xrt/compositor/main/comp_compositor.c
@@ -0,0 +1,505 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Main compositor written using Vulkan implementation.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "util/u_debug.h"
+
+#include "main/comp_compositor.h"
+#include "main/comp_client_interface.h"
+
+
+static void
+compositor_destroy(struct xrt_compositor *xc)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	struct vk_bundle *vk = &c->vk;
+
+	COMP_DEBUG(c, "DESTROY");
+
+	if (c->r) {
+		comp_renderer_destroy(c->r);
+		c->r = NULL;
+	}
+
+	vk_swapchain_cleanup(&c->window->swapchain);
+
+	if (c->window != NULL) {
+		c->window->destroy(c->window);
+		c->window = NULL;
+	}
+
+	if (vk->cmd_pool != VK_NULL_HANDLE) {
+		vk->vkDestroyCommandPool(vk->device, vk->cmd_pool, NULL);
+		vk->cmd_pool = VK_NULL_HANDLE;
+	}
+
+	if (vk->device != VK_NULL_HANDLE) {
+		vk->vkDestroyDevice(vk->device, NULL);
+		vk->device = VK_NULL_HANDLE;
+	}
+
+	vk_destroy_validation_callback(vk);
+
+	if (vk->instance != VK_NULL_HANDLE) {
+		vk->vkDestroyInstance(vk->instance, NULL);
+		vk->instance = VK_NULL_HANDLE;
+	}
+
+	free(c);
+}
+
+static void
+compositor_begin_session(struct xrt_compositor *xc, enum xrt_view_type type)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_DEBUG(c, "BEGIN_SESSION");
+}
+
+static void
+compositor_end_session(struct xrt_compositor *xc)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_DEBUG(c, "END_SESSION");
+}
+
+static void
+compositor_wait_frame(struct xrt_compositor *xc,
+                      int64_t *predicted_display_time,
+                      int64_t *predicted_display_period)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_SPEW(c, "WAIT_FRAME");
+
+	//! @todo set *predicted_display_time
+
+	// *predicted_display_time = 0;
+	// *predicted_display_period = 0;
+}
+
+static void
+compositor_begin_frame(struct xrt_compositor *xc)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_SPEW(c, "BEGIN_FRAME");
+}
+
+static void
+compositor_discard_frame(struct xrt_compositor *xc)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_SPEW(c, "DISCARD_FRAME");
+}
+
+static void
+compositor_end_frame(struct xrt_compositor *xc,
+                     enum xrt_blend_mode blend_mode,
+                     struct xrt_swapchain **xscs,
+                     uint32_t *acquired_index,
+                     uint32_t num_swapchains)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	COMP_SPEW(c, "END_FRAME");
+
+	struct comp_swapchain_image *right;
+	struct comp_swapchain_image *left;
+
+	// Stereo!
+	if (num_swapchains == 2) {
+		left = &comp_swapchain(xscs[0])->images[acquired_index[0]];
+		right = &comp_swapchain(xscs[1])->images[acquired_index[1]];
+		comp_renderer_frame(c->r, left, right);
+	} else {
+		COMP_ERROR(c, "non-stereo rendering not supported");
+	}
+}
+
+
+/*
+ *
+ * Vulkan functions.
+ *
+ */
+
+#define GET_PROC(name) (PFN_##name) c->vk.vkGetInstanceProcAddr(NULL, #name);
+#define GET_DEV_PROC(c, name)                                                  \
+	(PFN_##name) c->vk.vkGetDeviceProcAddr(c->vk.device, #name);
+#define GET_INS_PROC(c, name)                                                  \
+	(PFN_##name) c->vk.vkGetInstanceProcAddr(c->vk.instance, #name);
+#define GET_DEV_PROC(c, name)                                                  \
+	(PFN_##name) c->vk.vkGetDeviceProcAddr(c->vk.device, #name);
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+vkGetInstanceProcAddr(VkInstance instance, const char *pName);
+
+static VkResult
+find_get_instance_proc_addr(struct comp_compositor *c)
+{
+	//! @todo Do any library loading here.
+	c->vk.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
+
+	// Fill in all loader functions.
+	// clang-format off
+	c->vk.vkCreateInstance = GET_PROC(vkCreateInstance);
+	// clang-format on
+
+	return VK_SUCCESS;
+}
+
+#ifdef XRT_ENABLE_VK_VALIDATION
+#define COMPOSITOR_DEBUG_VULKAN_EXTENSIONS VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
+#else
+#define COMPOSITOR_DEBUG_VULKAN_EXTENSIONS
+#endif
+
+#define COMPOSITOR_COMMON_VULKAN_EXTENSIONS                                    \
+	COMPOSITOR_DEBUG_VULKAN_EXTENSIONS                                     \
+	VK_KHR_SURFACE_EXTENSION_NAME,                                         \
+	    VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,            \
+	    VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,                \
+	    VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME,                 \
+	    VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME
+
+static const char *instance_extensions_none[] = {
+    COMPOSITOR_COMMON_VULKAN_EXTENSIONS};
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+static const char *instance_extensions_xcb[] = {
+    COMPOSITOR_COMMON_VULKAN_EXTENSIONS,
+    VK_KHR_XCB_SURFACE_EXTENSION_NAME,
+};
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+static const char *instance_extensions_wayland[] = {
+    COMPOSITOR_COMMON_VULKAN_EXTENSIONS,
+    VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
+};
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+static const char *instance_extensions_direct_mode[] = {
+    COMPOSITOR_COMMON_VULKAN_EXTENSIONS,
+    VK_KHR_DISPLAY_EXTENSION_NAME,
+    VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME,
+    VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME,
+};
+#endif
+
+static VkResult
+select_instances_extensions(struct comp_compositor *c,
+                            const char ***out_exts,
+                            uint32_t *out_num)
+{
+	switch (c->settings.window_type) {
+	case WINDOW_NONE:
+		*out_exts = instance_extensions_none;
+		*out_num = ARRAY_SIZE(instance_extensions_none);
+		break;
+#ifdef VK_USE_PLATFORM_XCB_KHR
+	case WINDOW_XCB:
+		*out_exts = instance_extensions_xcb;
+		*out_num = ARRAY_SIZE(instance_extensions_xcb);
+		break;
+#endif
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+	case WINDOW_WAYLAND:
+		*out_exts = instance_extensions_wayland;
+		*out_num = ARRAY_SIZE(instance_extensions_wayland);
+		break;
+#endif
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+	case WINDOW_DIRECT_MODE:
+		*out_exts = instance_extensions_direct_mode;
+		*out_num = ARRAY_SIZE(instance_extensions_direct_mode);
+		break;
+#endif
+	default: return VK_ERROR_INITIALIZATION_FAILED;
+	}
+
+	return VK_SUCCESS;
+}
+
+static VkResult
+create_instance(struct comp_compositor *c)
+{
+	const char **instance_extensions;
+	uint32_t num_extensions;
+	VkResult ret;
+
+	VkApplicationInfo app_info = {
+	    .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
+	    .pApplicationName = "Collabora Compositor",
+	    .pEngineName = "Monado",
+	    .apiVersion = VK_MAKE_VERSION(1, 0, 2),
+	};
+
+	ret = select_instances_extensions(c, &instance_extensions,
+	                                  &num_extensions);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "Failed to select instance extensions: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+#ifdef XRT_ENABLE_VK_VALIDATION
+	const char *instance_layers[] = {
+	    "VK_LAYER_LUNARG_standard_validation",
+	};
+#endif
+
+	VkInstanceCreateInfo instance_info = {
+	    .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
+	    .pApplicationInfo = &app_info,
+	    .enabledExtensionCount = num_extensions,
+	    .ppEnabledExtensionNames = instance_extensions,
+#ifdef XRT_ENABLE_VK_VALIDATION
+	    .enabledLayerCount = ARRAY_SIZE(instance_layers),
+	    .ppEnabledLayerNames = instance_layers,
+#endif
+	};
+
+	ret = c->vk.vkCreateInstance(&instance_info, NULL, &c->vk.instance);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "vkCreateInstance: %s\n", vk_result_string(ret));
+		COMP_ERROR(c, "Failed to create Vulkan instance");
+		return ret;
+	}
+
+	ret = vk_get_instance_functions(&c->vk);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "Failed to get Vulkan instance functions: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+#ifdef XRT_ENABLE_VK_VALIDATION
+	vk_init_validation_callback(&c->vk);
+#endif
+
+	return ret;
+}
+
+static bool
+compositor_init_vulkan(struct comp_compositor *c)
+{
+	VkResult ret;
+
+	ret = find_get_instance_proc_addr(c);
+	if (ret != VK_SUCCESS) {
+		return false;
+	}
+
+	ret = create_instance(c);
+	if (ret != VK_SUCCESS) {
+		return false;
+	}
+
+	ret = vk_create_device(&c->vk);
+	if (ret != VK_SUCCESS) {
+		return false;
+	}
+
+	ret = vk_init_cmd_pool(&c->vk);
+	if (ret != VK_SUCCESS) {
+		return false;
+	}
+
+	return true;
+}
+
+/*
+ *
+ * Other functions.
+ *
+ */
+
+void
+comp_compositor_print(struct comp_compositor *c,
+                      const char *func,
+                      const char *fmt,
+                      ...)
+{
+	fprintf(stderr, "%s - ", func);
+
+	va_list args;
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	fprintf(stderr, "\n");
+}
+
+static bool
+compositor_try_window(struct comp_compositor *c, struct comp_window *window)
+{
+	if (window == NULL) {
+		return false;
+	}
+
+	if (!window->init(window)) {
+		window->destroy(window);
+		return false;
+	} else {
+		COMP_DEBUG(c, "Window backend %s initialized!", window->name);
+		c->window = window;
+		return true;
+	}
+}
+
+static bool
+compositor_init_window(struct comp_compositor *c)
+{
+	// Setup the initial width from the settings.
+	c->current.width = c->settings.width;
+	c->current.height = c->settings.height;
+
+	switch (c->settings.window_type) {
+	case WINDOW_AUTO:
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+		if (compositor_try_window(c, comp_window_direct_create(c))) {
+			c->settings.window_type = WINDOW_DIRECT_MODE;
+			return true;
+		}
+#endif
+#ifdef VK_USE_PLATFORM_XCB_KHR
+		if (compositor_try_window(c, comp_window_xcb_create(c))) {
+			c->settings.window_type = WINDOW_XCB;
+			return true;
+		}
+#endif
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+		if (compositor_try_window(c, comp_window_wayland_create(c))) {
+			c->settings.window_type = WINDOW_WAYLAND;
+			return true;
+		}
+#endif
+		COMP_ERROR(c, "Failed to auto detect window support!");
+		break;
+	case WINDOW_XCB:
+#ifdef VK_USE_PLATFORM_XCB_KHR
+		compositor_try_window(c, comp_window_xcb_create(c));
+#else
+		COMP_ERROR(c, "XCB support not compiled in!");
+#endif
+		break;
+	case WINDOW_WAYLAND:
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+		compositor_try_window(c, comp_window_wayland_create(c));
+#else
+		COMP_ERROR(c, "Wayland support not compiled in!");
+#endif
+		break;
+	case WINDOW_DIRECT_MODE:
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+		compositor_try_window(c, comp_window_direct_create(c));
+#else
+		COMP_ERROR(c, "Direct mode support not compiled in!");
+#endif
+		break;
+	default: COMP_ERROR(c, "Unknown window type!"); break;
+	}
+
+	// Failed to create?
+	if (c->window == NULL) {
+		return false;
+	}
+
+	return true;
+}
+
+
+static void
+_sc_dimension_cb(uint32_t width, uint32_t height, void *ptr)
+{
+	struct comp_compositor *c = (struct comp_compositor *)ptr;
+
+	COMP_DEBUG(c, "_sc_dimension_cb %dx%d", width, height);
+
+	c->current.width = width;
+	c->current.height = height;
+}
+
+static bool
+compositor_init_swapchain(struct comp_compositor *c)
+{
+	//! @todo Make c->window->init_swachain call vk_swapchain_init and give
+	//!       _sc_dimension_cb to window or just have it call a function?
+	vk_swapchain_init(&c->window->swapchain, &c->vk, _sc_dimension_cb,
+	                  (void *)c);
+	if (!c->window->init_swapchain(c->window, c->current.width,
+	                               c->current.height)) {
+		COMP_ERROR(c, "Window init_swapchain failed!");
+		goto err_destroy;
+	}
+
+	return true;
+
+	// Error path.
+err_destroy:
+	c->window->destroy(c->window);
+	c->window = NULL;
+
+	return false;
+}
+
+static bool
+compositor_init_renderer(struct comp_compositor *c)
+{
+	c->r = comp_renderer_create(c);
+	if (c->r == NULL) {
+		return false;
+	}
+
+	return true;
+}
+
+struct xrt_compositor_fd *
+comp_compositor_create(struct xrt_device *xdev, bool flip_y)
+{
+	struct comp_compositor *c = calloc(1, sizeof(struct comp_compositor));
+
+	c->base.base.create_swapchain = comp_swapchain_create;
+	c->base.base.begin_session = compositor_begin_session;
+	c->base.base.end_session = compositor_end_session;
+	c->base.base.wait_frame = compositor_wait_frame;
+	c->base.base.begin_frame = compositor_begin_frame;
+	c->base.base.discard_frame = compositor_discard_frame;
+	c->base.base.end_frame = compositor_end_frame;
+	c->base.base.destroy = compositor_destroy;
+	c->xdev = xdev;
+
+	COMP_DEBUG(c, "Doing init %p", (void *)c);
+
+	// Init the settings to default.
+	comp_settings_init(&c->settings, xdev);
+
+	c->settings.flip_y = flip_y;
+
+	// Need to select window backend before creating Vulkan, then
+	// swapchain will initialize the window fully and the swapchain, and
+	// finally the renderer is created which renderers to window/swapchain.
+	// clang-format off
+	if (!compositor_init_window(c) ||
+	    !compositor_init_vulkan(c) ||
+	    !compositor_init_swapchain(c) ||
+	    !compositor_init_renderer(c)) {
+		COMP_DEBUG(c, "Failed to init compositor %p", (void *)c);
+		c->base.base.destroy(&c->base.base);
+		return NULL;
+	}
+	// clang-format on
+
+	COMP_DEBUG(c, "Done %p", (void *)c);
+
+	return &c->base;
+}
diff --git a/src/xrt/compositor/main/comp_compositor.h b/src/xrt/compositor/main/comp_compositor.h
new file mode 100644
index 000000000..c3ba6fb22
--- /dev/null
+++ b/src/xrt/compositor/main/comp_compositor.h
@@ -0,0 +1,234 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Main compositor written using Vulkan header.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "main/comp_settings.h"
+#include "main/comp_window.h"
+#include "main/comp_renderer.h"
+
+#include "xrt/xrt_gfx_vk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Documentation
+ *
+ */
+
+/*!
+ * @defgroup comp Compositor
+ * Main compositing code.
+ *
+ * @ingroup xrt
+ */
+
+/*!
+ * Glue code between client program to the main compositor.
+ *
+ * @defgroup comp_client Compositor client glue code
+ * @ingroup comp
+ */
+
+/*!
+ * Common compositor code shared between main and client code.
+ *
+ * @defgroup comp_common Common compositor code
+ * @ingroup comp
+ */
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+/*!
+ * A single swapchain image, holds the needed state for tracking image usage.
+ *
+ * @ingroup comp
+ */
+struct comp_swapchain_image
+{
+	//! Vulkan image to create view from.
+	VkImage image;
+	//! Exported memory backing the image.
+	VkDeviceMemory memory;
+	//! Sampler used by the renderer and distortion code.
+	VkSampler sampler;
+	//! View used by the renderer and distortion code.
+	VkImageView view;
+};
+
+/*!
+ * A swapchain that is almost a one to one mapping to a OpenXR swapchain.
+ *
+ * Not used by the window backend that uses the vk_swapchain to render to.
+ *
+ * @ingroup comp
+ */
+struct comp_swapchain
+{
+	struct xrt_swapchain_fd base;
+
+	struct comp_compositor *c;
+
+	struct comp_swapchain_image images[XRT_MAX_SWAPCHAIN_IMAGES];
+};
+
+/*!
+ * Main compositor struct tying everything in the compositor together.
+ *
+ * @ingroup comp
+ */
+struct comp_compositor
+{
+	struct xrt_compositor_fd base;
+
+	//! A link back to the compositor we are presenting to the client.
+	struct xrt_compositor *client;
+
+	//! Renderer helper.
+	struct comp_renderer *r;
+
+	//! The window or display we are using.
+	struct comp_window *window;
+
+	//! The device we are displaying to.
+	struct xrt_device *xdev;
+
+	//! The settings.
+	struct comp_settings settings;
+
+	// Vulkan bundle of things.
+	struct vk_bundle vk;
+
+	/*!
+	 * The current state we are tracking.
+	 *
+	 * Settings is supposed to be read only.
+	 */
+	struct
+	{
+		uint32_t width;
+		uint32_t height;
+	} current;
+};
+
+
+/*
+ *
+ * Functions and helpers.
+ *
+ */
+
+/*!
+ * Convinence function to convert a xrt_swapchain to a comp_swapchain.
+ *
+ * @ingroup comp
+ */
+XRT_MAYBE_UNUSED static struct comp_swapchain *
+comp_swapchain(struct xrt_swapchain *xsc)
+{
+	return (struct comp_swapchain *)xsc;
+}
+
+/*!
+ * Convinence function to convert a xrt_compositor to a comp_compositor.
+ *
+ * @ingroup comp
+ */
+XRT_MAYBE_UNUSED static struct comp_compositor *
+comp_compositor(struct xrt_compositor *xc)
+{
+	return (struct comp_compositor *)xc;
+}
+
+/*!
+ * A compositor function that is implemented in the swapchain code.
+ *
+ * @ingroup comp
+ */
+struct xrt_swapchain *
+comp_swapchain_create(struct xrt_compositor *xc,
+                      enum xrt_swapchain_create_flags create,
+                      enum xrt_swapchain_usage_bits bits,
+                      int64_t format,
+                      uint32_t sample_count,
+                      uint32_t width,
+                      uint32_t height,
+                      uint32_t face_count,
+                      uint32_t array_size,
+                      uint32_t mip_count);
+
+/*!
+ * Free and destroy any initialized fields on the given image, safe to pass in
+ * images that has one or all fields set to NULL.
+ *
+ * @ingroup comp
+ */
+void
+comp_swapchain_image_cleanup(struct vk_bundle *vk,
+                             struct comp_swapchain_image *image);
+
+/*!
+ * Printer helper.
+ *
+ * @ingroup comp
+ */
+void
+comp_compositor_print(struct comp_compositor *c,
+                      const char *func,
+                      const char *fmt,
+                      ...) XRT_PRINTF_FORMAT(3, 4);
+
+/*!
+ * Spew level logging.
+ *
+ * @ingroup comp
+ */
+#define COMP_SPEW(c, ...)                                                      \
+	do {                                                                   \
+		if (c->settings.print_spew) {                                  \
+			comp_compositor_print(c, __func__, __VA_ARGS__);       \
+		}                                                              \
+	} while (false)
+
+/*!
+ * Debug level logging.
+ *
+ * @ingroup comp
+ */
+#define COMP_DEBUG(c, ...)                                                     \
+	do {                                                                   \
+		if (c->settings.print_debug) {                                 \
+			comp_compositor_print(c, __func__, __VA_ARGS__);       \
+		}                                                              \
+	} while (false)
+
+/*!
+ * Error level logging.
+ *
+ * @ingroup comp
+ */
+#define COMP_ERROR(c, ...)                                                     \
+	do {                                                                   \
+		comp_compositor_print(c, __func__, __VA_ARGS__);               \
+	} while (false)
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_distortion.c b/src/xrt/compositor/main/comp_distortion.c
new file mode 100644
index 000000000..f3d55c6c8
--- /dev/null
+++ b/src/xrt/compositor/main/comp_distortion.c
@@ -0,0 +1,719 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Distortion shader code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "main/comp_settings.h"
+#include "main/comp_compositor.h"
+
+#include "comp_distortion.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wnewline-eof"
+
+#include "shaders/distortion.vert.h"
+#include "shaders/none.frag.h"
+#include "shaders/panotools.frag.h"
+#include "shaders/vive.frag.h"
+
+#pragma GCC diagnostic pop
+
+/*
+ *
+ * Pre declare functions.
+ *
+ */
+
+static void
+comp_distortion_update_uniform_buffer_warp(struct comp_distortion *d,
+                                           struct comp_compositor *c);
+
+static void
+comp_distortion_init_uniform_buffer(struct comp_distortion *d,
+                                    struct comp_compositor *c);
+
+XRT_MAYBE_UNUSED static void
+comp_distortion_update_descriptor_sets(struct comp_distortion *d,
+                                       VkSampler samplers[2],
+                                       VkImageView views[2]);
+
+static void
+comp_distortion_init_descriptor_set_layout(struct comp_distortion *d);
+
+static void
+comp_distortion_init_pipeline_layout(struct comp_distortion *d);
+
+static void
+comp_distortion_init_pipeline(struct comp_distortion *d,
+                              VkRenderPass render_pass,
+                              VkPipelineCache pipeline_cache,
+                              enum xrt_distortion_model distortion_model);
+
+static VkWriteDescriptorSet
+comp_distortion_get_uniform_write_descriptor_set(struct comp_distortion *d,
+                                                 uint32_t binding,
+                                                 uint32_t eye);
+
+static VkWriteDescriptorSet
+comp_distortion_get_uniform_write_descriptor_set_vp(struct comp_distortion *d,
+                                                    uint32_t binding,
+                                                    uint32_t eye);
+
+static VkWriteDescriptorSet
+comp_distortion_get_image_write_descriptor_set(
+    VkDescriptorSet descriptorSet,
+    VkDescriptorImageInfo *texDescriptorPosition,
+    uint32_t binding);
+
+static void
+comp_distortion_init_descriptor_sets(struct comp_distortion *d,
+                                     VkDescriptorPool descriptorPool);
+
+
+/*
+ *
+ * Buffer functions.
+ *
+ */
+
+static void
+_buffer_destroy(struct vk_bundle *vk, struct comp_uniform_buffer *buffer)
+{
+	vk->vkDestroyBuffer(buffer->device, buffer->buffer, NULL);
+	vk->vkFreeMemory(buffer->device, buffer->memory, NULL);
+}
+
+static VkResult
+_buffer_map(struct vk_bundle *vk,
+            struct comp_uniform_buffer *buffer,
+            VkDeviceSize size,
+            VkDeviceSize offset)
+{
+	return vk->vkMapMemory(vk->device, buffer->memory, offset, size, 0,
+	                       &buffer->mapped);
+}
+
+static void
+_buffer_unmap(struct vk_bundle *vk, struct comp_uniform_buffer *buffer)
+{
+	if (buffer->mapped) {
+		vk->vkUnmapMemory(vk->device, buffer->memory);
+		buffer->mapped = NULL;
+	}
+}
+
+static void
+_buffer_setup_descriptor(struct vk_bundle *vk,
+                         struct comp_uniform_buffer *buffer,
+                         VkDeviceSize size,
+                         VkDeviceSize offset)
+{
+	buffer->descriptor.offset = offset;
+	buffer->descriptor.buffer = buffer->buffer;
+	buffer->descriptor.range = size;
+}
+
+
+/*
+ *
+ * Shader functions.
+ *
+ */
+
+static VkPipelineShaderStageCreateInfo
+_shader_load(struct vk_bundle *vk,
+             const uint32_t *code,
+             size_t size,
+             VkShaderStageFlagBits flags)
+{
+	VkResult ret;
+
+	VkShaderModuleCreateInfo info = {
+	    .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
+	    .codeSize = size,
+	    .pCode = code,
+	};
+
+	VkShaderModule module;
+	ret = vk->vkCreateShaderModule(vk->device, &info, NULL, &module);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "vkCreateShaderModule failed %u", ret);
+	}
+
+	return (VkPipelineShaderStageCreateInfo){
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+	    .stage = flags,
+	    .module = module,
+	    .pName = "main",
+	};
+}
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+void
+comp_distortion_init(struct comp_distortion *d,
+                     struct comp_compositor *c,
+                     VkRenderPass render_pass,
+                     VkPipelineCache pipeline_cache,
+                     enum xrt_distortion_model distortion_model,
+                     VkDescriptorPool descriptor_pool,
+                     bool flip_y)
+{
+	d->vk = &c->vk;
+
+	d->ubo_vp_data[0].flip_y = flip_y;
+	d->ubo_vp_data[1].flip_y = flip_y;
+
+	comp_distortion_init_uniform_buffer(d, c);
+	comp_distortion_update_uniform_buffer_warp(d, c);
+	comp_distortion_init_descriptor_set_layout(d);
+	comp_distortion_init_pipeline_layout(d);
+	comp_distortion_init_pipeline(d, render_pass, pipeline_cache,
+	                              distortion_model);
+	comp_distortion_init_descriptor_sets(d, descriptor_pool);
+}
+
+void
+comp_distortion_destroy(struct comp_distortion *d)
+{
+	struct vk_bundle *vk = d->vk;
+
+
+	vk->vkDestroyDescriptorSetLayout(vk->device, d->descriptor_set_layout,
+	                                 NULL);
+
+	_buffer_destroy(vk, &d->ubo_handle);
+	_buffer_destroy(vk, &d->ubo_viewport_handles[0]);
+	_buffer_destroy(vk, &d->ubo_viewport_handles[1]);
+
+	vk->vkDestroyPipeline(vk->device, d->pipeline, NULL);
+	vk->vkDestroyPipelineLayout(vk->device, d->pipeline_layout, NULL);
+}
+
+static void
+comp_distortion_init_pipeline(struct comp_distortion *d,
+                              VkRenderPass render_pass,
+                              VkPipelineCache pipeline_cache,
+                              enum xrt_distortion_model distortion_model)
+{
+	struct vk_bundle *vk = d->vk;
+	VkResult ret;
+
+	VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
+	    .sType =
+	        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
+	    .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
+	    .primitiveRestartEnable = VK_FALSE,
+	};
+
+	VkPipelineRasterizationStateCreateInfo rasterization_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
+	    .depthClampEnable = VK_FALSE,
+	    .polygonMode = VK_POLYGON_MODE_FILL,
+	    .cullMode = VK_CULL_MODE_BACK_BIT,
+	    .frontFace = VK_FRONT_FACE_CLOCKWISE,
+	    .lineWidth = 1.0f,
+	};
+
+	VkPipelineColorBlendAttachmentState blend_attachment_state = {
+	    .blendEnable = VK_FALSE,
+	    .colorWriteMask = 0xf,
+	};
+
+	VkPipelineColorBlendStateCreateInfo color_blend_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
+	    .attachmentCount = 1,
+	    .pAttachments = &blend_attachment_state,
+	};
+
+	VkPipelineDepthStencilStateCreateInfo depth_stencil_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
+	    .depthTestEnable = VK_TRUE,
+	    .depthWriteEnable = VK_TRUE,
+	    .depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
+	    .front =
+	        {
+	            .compareOp = VK_COMPARE_OP_ALWAYS,
+	        },
+	    .back =
+	        {
+	            .compareOp = VK_COMPARE_OP_ALWAYS,
+	        },
+	};
+
+	VkPipelineViewportStateCreateInfo viewport_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
+	    .viewportCount = 1,
+	    .scissorCount = 1,
+	};
+
+	VkPipelineMultisampleStateCreateInfo multisample_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
+	    .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT};
+
+	VkDynamicState dynamic_states[] = {
+	    VK_DYNAMIC_STATE_VIEWPORT,
+	    VK_DYNAMIC_STATE_SCISSOR,
+	};
+
+	VkPipelineDynamicStateCreateInfo dynamic_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
+	    .dynamicStateCount = 2,
+	    .pDynamicStates = dynamic_states,
+	};
+
+
+
+	const uint32_t *fragment_shader_code;
+	size_t fragment_shader_size;
+
+	switch (distortion_model) {
+	case XRT_DISTORTION_MODEL_NONE:
+		fragment_shader_code = shaders_none_frag;
+		fragment_shader_size = sizeof(shaders_none_frag);
+		break;
+	case XRT_DISTORTION_MODEL_PANOTOOLS:
+		fragment_shader_code = shaders_panotools_frag;
+		fragment_shader_size = sizeof(shaders_panotools_frag);
+		break;
+	case XRT_DISTORTION_MODEL_VIVE:
+		fragment_shader_code = shaders_vive_frag;
+		fragment_shader_size = sizeof(shaders_vive_frag);
+		break;
+	default:
+		fragment_shader_code = shaders_panotools_frag;
+		fragment_shader_size = sizeof(shaders_panotools_frag);
+		break;
+	}
+
+	VkPipelineShaderStageCreateInfo shader_stages[2] = {
+	    _shader_load(d->vk, shaders_distortion_vert,
+	                 sizeof(shaders_distortion_vert),
+	                 VK_SHADER_STAGE_VERTEX_BIT),
+	    _shader_load(d->vk, fragment_shader_code, fragment_shader_size,
+	                 VK_SHADER_STAGE_FRAGMENT_BIT),
+	};
+
+	/*
+	 * We will generate positions and UVs for the full screen quad
+	 * from the gl_VertexIndex
+	 */
+	VkPipelineVertexInputStateCreateInfo empty_input_state = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+	};
+
+	VkGraphicsPipelineCreateInfo pipeline_info = {
+	    .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
+	    .flags = 0,
+	    .stageCount = ARRAY_SIZE(shader_stages),
+	    .pStages = shader_stages,
+	    .pVertexInputState = &empty_input_state,
+	    .pInputAssemblyState = &input_assembly_state,
+	    .pViewportState = &viewport_state,
+	    .pRasterizationState = &rasterization_state,
+	    .pMultisampleState = &multisample_state,
+	    .pDepthStencilState = &depth_stencil_state,
+	    .pColorBlendState = &color_blend_state,
+	    .pDynamicState = &dynamic_state,
+	    .layout = d->pipeline_layout,
+	    .renderPass = render_pass,
+	    .basePipelineHandle = VK_NULL_HANDLE,
+	    .basePipelineIndex = -1,
+	};
+
+	ret = vk->vkCreateGraphicsPipelines(vk->device, pipeline_cache, 1,
+	                                    &pipeline_info, NULL, &d->pipeline);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(d->vk, "vkCreateGraphicsPipelines failed %u!", ret);
+	}
+
+	vk->vkDestroyShaderModule(vk->device, shader_stages[0].module, NULL);
+	vk->vkDestroyShaderModule(vk->device, shader_stages[1].module, NULL);
+}
+
+static VkWriteDescriptorSet
+comp_distortion_get_uniform_write_descriptor_set(struct comp_distortion *d,
+                                                 uint32_t binding,
+                                                 uint32_t eye)
+{
+	return (VkWriteDescriptorSet){
+	    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+	    .dstSet = d->descriptor_sets[eye],
+	    .dstBinding = binding,
+	    .descriptorCount = 1,
+	    .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	    .pBufferInfo = &d->ubo_handle.descriptor,
+	};
+}
+
+static VkWriteDescriptorSet
+comp_distortion_get_uniform_write_descriptor_set_vp(struct comp_distortion *d,
+                                                    uint32_t binding,
+                                                    uint32_t eye)
+{
+	return (VkWriteDescriptorSet){
+	    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+	    .dstSet = d->descriptor_sets[eye],
+	    .dstBinding = binding,
+	    .descriptorCount = 1,
+	    .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	    .pBufferInfo = &d->ubo_viewport_handles[eye].descriptor,
+	};
+}
+
+static VkWriteDescriptorSet
+comp_distortion_get_image_write_descriptor_set(
+    VkDescriptorSet descriptor_set,
+    VkDescriptorImageInfo *descriptor_position,
+    uint32_t binding)
+{
+	return (VkWriteDescriptorSet){
+	    .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+	    .dstSet = descriptor_set,
+	    .dstBinding = binding,
+	    .descriptorCount = 1,
+	    .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	    .pImageInfo = descriptor_position,
+	};
+}
+
+static void
+comp_distortion_init_descriptor_sets(struct comp_distortion *d,
+                                     VkDescriptorPool descriptor_pool)
+{
+	struct vk_bundle *vk = d->vk;
+	VkResult ret;
+
+	VkDescriptorSetAllocateInfo alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+	    .descriptorPool = descriptor_pool,
+	    .descriptorSetCount = 1,
+	    .pSetLayouts = &d->descriptor_set_layout,
+	};
+
+	for (uint32_t i = 0; i < 2; i++) {
+		ret = vk->vkAllocateDescriptorSets(d->vk->device, &alloc_info,
+		                                   &d->descriptor_sets[i]);
+		if (ret != VK_SUCCESS) {
+			VK_DEBUG(d->vk, "vkAllocateDescriptorSets failed %u",
+			         ret);
+		}
+	}
+}
+
+void
+comp_distortion_update_descriptor_set(struct comp_distortion *d,
+                                      VkSampler sampler,
+                                      VkImageView view,
+                                      uint32_t eye)
+{
+	struct vk_bundle *vk = d->vk;
+
+	VkDescriptorImageInfo image_info = {
+	    .sampler = sampler,
+	    .imageView = view,
+	    .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+	};
+
+	VkWriteDescriptorSet write_descriptor_sets[3] = {
+	    // Binding 0 : Render texture target
+	    comp_distortion_get_image_write_descriptor_set(
+	        d->descriptor_sets[eye], &image_info, 0),
+	    // Binding 1 : Fragment shader uniform buffer
+	    comp_distortion_get_uniform_write_descriptor_set(d, 1, eye),
+	    // Binding 2 : view uniform buffer
+	    comp_distortion_get_uniform_write_descriptor_set_vp(d, 2, eye),
+	};
+
+	vk->vkUpdateDescriptorSets(vk->device,
+	                           ARRAY_SIZE(write_descriptor_sets),
+	                           write_descriptor_sets, 0, NULL);
+}
+
+static void
+comp_distortion_update_descriptor_sets(struct comp_distortion *d,
+                                       VkSampler samplers[2],
+                                       VkImageView views[2])
+{
+	for (uint32_t i = 0; i < 2; i++) {
+		comp_distortion_update_descriptor_set(d, samplers[i], views[i],
+		                                      i);
+	}
+}
+
+static void
+comp_distortion_init_descriptor_set_layout(struct comp_distortion *d)
+{
+	struct vk_bundle *vk = d->vk;
+	VkResult ret;
+
+	VkDescriptorSetLayoutBinding set_layout_bindings[3] = {
+	    // Binding 0 : Render texture target left
+	    {
+	        .binding = 0,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	        .descriptorCount = 1,
+	        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+	    },
+	    // Binding 1 : Fragment shader uniform buffer
+	    {
+	        .binding = 1,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .descriptorCount = 1,
+	        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
+	    },
+	    // binding 2: viewport index
+	    {
+	        .binding = 2,
+	        .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .descriptorCount = 1,
+	        .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
+	    },
+	};
+
+	VkDescriptorSetLayoutCreateInfo set_layout_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+	    .bindingCount = ARRAY_SIZE(set_layout_bindings),
+	    .pBindings = set_layout_bindings,
+	};
+
+	ret = vk->vkCreateDescriptorSetLayout(d->vk->device, &set_layout_info,
+	                                      NULL, &d->descriptor_set_layout);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(d->vk, "vkCreateDescriptorSetLayout failed %u", ret);
+	}
+}
+
+static void
+comp_distortion_init_pipeline_layout(struct comp_distortion *d)
+{
+	struct vk_bundle *vk = d->vk;
+	VkResult ret;
+
+	VkPipelineLayoutCreateInfo pipeline_layout_info = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
+	    .setLayoutCount = 1,
+	    .pSetLayouts = &d->descriptor_set_layout,
+	};
+
+	ret = vk->vkCreatePipelineLayout(d->vk->device, &pipeline_layout_info,
+	                                 NULL, &d->pipeline_layout);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(d->vk, "Failed to create pipeline layout!");
+	}
+}
+
+void
+comp_distortion_draw_quad(struct comp_distortion *d,
+                          VkCommandBuffer command_buffer,
+                          int eye)
+{
+	struct vk_bundle *vk = d->vk;
+
+	vk->vkCmdBindDescriptorSets(
+	    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, d->pipeline_layout,
+	    0, 1, &d->descriptor_sets[eye], 0, NULL);
+
+	vk->vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
+	                      d->pipeline);
+
+	/* Draw 3 verts from which we construct the fullscreen quad in
+	 * the shader*/
+	vk->vkCmdDraw(command_buffer, 3, 1, 0, 0);
+}
+
+// Update fragment shader hmd warp uniform block
+static void
+comp_distortion_update_uniform_buffer_warp(struct comp_distortion *d,
+                                           struct comp_compositor *c)
+{
+	/*
+	 * Pano vision fragment shader
+	 */
+
+	// clang-format off
+	d->ubo_data.hmd_warp_param[0] = c->xdev->distortion.pano.distortion_k[0];
+	d->ubo_data.hmd_warp_param[1] = c->xdev->distortion.pano.distortion_k[1];
+	d->ubo_data.hmd_warp_param[2] = c->xdev->distortion.pano.distortion_k[2];
+	d->ubo_data.hmd_warp_param[3] = c->xdev->distortion.pano.distortion_k[3];
+	d->ubo_data.aberr[0] = c->xdev->distortion.pano.aberration_k[0];
+	d->ubo_data.aberr[1] = c->xdev->distortion.pano.aberration_k[1];
+	d->ubo_data.aberr[2] = c->xdev->distortion.pano.aberration_k[2];
+	d->ubo_data.aberr[3] = c->xdev->distortion.pano.aberration_k[3];
+	d->ubo_data.lens_center[0][0] = c->xdev->views[0].lens_center.x_meters;
+	d->ubo_data.lens_center[0][1] = c->xdev->views[0].lens_center.y_meters;
+	d->ubo_data.lens_center[1][0] = c->xdev->views[1].lens_center.x_meters;
+	d->ubo_data.lens_center[1][1] = c->xdev->views[1].lens_center.y_meters;
+	d->ubo_data.viewport_scale[0] = c->xdev->views[0].display.w_meters;
+	d->ubo_data.viewport_scale[1] = c->xdev->views[0].display.h_meters;
+	d->ubo_data.warp_scale = c->xdev->distortion.pano.warp_scale;
+
+	memcpy(d->ubo_handle.mapped, &d->ubo_data, sizeof(d->ubo_data));
+	// clang-format on
+
+
+	/*
+	 * Common vertex shader stuff.
+	 */
+
+	// clang-format off
+	d->ubo_vp_data[0].viewport_id = 0;
+	d->ubo_vp_data[0].rot = c->xdev->views[0].rot;
+	d->ubo_vp_data[1].viewport_id = 1;
+	d->ubo_vp_data[1].rot = c->xdev->views[1].rot;
+
+	memcpy(d->ubo_viewport_handles[0].mapped, &d->ubo_vp_data[0], sizeof(d->ubo_vp_data[0]));
+	memcpy(d->ubo_viewport_handles[1].mapped, &d->ubo_vp_data[1], sizeof(d->ubo_vp_data[1]));
+	// clang-format on
+}
+
+static VkResult
+_create_buffer(struct vk_bundle *vk,
+               VkBufferUsageFlags usage_flags,
+               VkMemoryPropertyFlags memory_property_flags,
+               struct comp_uniform_buffer *buffer,
+               VkDeviceSize size,
+               void *data)
+{
+	buffer->device = vk->device;
+	VkResult ret;
+
+	// Create the buffer handle.
+	VkBufferCreateInfo buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+	    .size = size,
+	    .usage = usage_flags,
+	};
+	ret =
+	    vk->vkCreateBuffer(vk->device, &buffer_info, NULL, &buffer->buffer);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to create buffer!");
+		return ret;
+	}
+
+	// Create the memory backing up the buffer handle.
+	VkMemoryRequirements mem_reqs;
+	vk->vkGetBufferMemoryRequirements(vk->device, buffer->buffer,
+	                                  &mem_reqs);
+
+	// Find a memory type index that fits the properties of the buffer.
+	uint32_t memory_type_index;
+	vk_get_memory_type(vk, mem_reqs.memoryTypeBits, memory_property_flags,
+	                   &memory_type_index);
+
+	VkMemoryAllocateInfo mem_alloc = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+	    .allocationSize = mem_reqs.size,
+	    .memoryTypeIndex = memory_type_index,
+	};
+
+	ret =
+	    vk->vkAllocateMemory(vk->device, &mem_alloc, NULL, &buffer->memory);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to allocate memory!");
+		goto err_buffer;
+	}
+
+	buffer->alignment = mem_reqs.alignment;
+	buffer->size = mem_alloc.allocationSize;
+	buffer->usageFlags = usage_flags;
+	buffer->memoryPropertyFlags = memory_property_flags;
+
+	// If a pointer to the buffer data has been passed, map the
+	// buffer and copy over the data
+	if (data != NULL) {
+		ret = _buffer_map(vk, buffer, VK_WHOLE_SIZE, 0);
+		if (ret != VK_SUCCESS) {
+			VK_DEBUG(vk, "Failed to map buffer!");
+			goto err_memory;
+		}
+
+		memcpy(buffer->mapped, data, size);
+		_buffer_unmap(vk, buffer);
+	}
+
+	// Initialize a default descriptor that covers the whole buffer size
+	_buffer_setup_descriptor(vk, buffer, VK_WHOLE_SIZE, 0);
+
+	// Attach the memory to the buffer object
+	ret = vk->vkBindBufferMemory(vk->device, buffer->buffer, buffer->memory,
+	                             0);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to bind buffer to memory!");
+		goto err_memory;
+	}
+
+	return VK_SUCCESS;
+
+
+err_memory:
+	vk->vkFreeMemory(vk->device, buffer->memory, NULL);
+
+err_buffer:
+	vk->vkDestroyBuffer(vk->device, buffer->buffer, NULL);
+
+	return ret;
+}
+
+static void
+comp_distortion_init_uniform_buffer(struct comp_distortion *d,
+                                    struct comp_compositor *c)
+{
+	struct vk_bundle *vk = &c->vk;
+	VkMemoryPropertyFlags memory_property_flags = 0;
+	VkBufferUsageFlags usage_flags = 0;
+	VkResult ret;
+
+	// Using the same flags for all uniform buffers.
+	usage_flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
+	memory_property_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
+	memory_property_flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
+
+	// Warp UBO in deferred fragment shader
+	ret = _create_buffer(vk, usage_flags, memory_property_flags,
+	                     &d->ubo_handle, sizeof(d->ubo_data), NULL);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to create warp ubo buffer!");
+	}
+	ret = _buffer_map(vk, &d->ubo_handle, VK_WHOLE_SIZE, 0);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to map warp ubo buffer!");
+	}
+
+	// vp ubos
+	ret = _create_buffer(vk, usage_flags, memory_property_flags,
+	                     &d->ubo_viewport_handles[0],
+	                     sizeof(d->ubo_vp_data[0]), NULL);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to create vp ubo buffer[0]!");
+	}
+	ret = _buffer_map(vk, &d->ubo_viewport_handles[0], VK_WHOLE_SIZE, 0);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to map vp ubo buffer[0]!");
+	}
+
+	ret = _create_buffer(vk, usage_flags, memory_property_flags,
+	                     &d->ubo_viewport_handles[1],
+	                     sizeof(d->ubo_vp_data[1]), NULL);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to create vp ubo buffer[1]!");
+	}
+	ret = _buffer_map(vk, &d->ubo_viewport_handles[1], VK_WHOLE_SIZE, 0);
+	if (ret != VK_SUCCESS) {
+		VK_DEBUG(vk, "Failed to map vp ubo buffer[1]!");
+	}
+}
diff --git a/src/xrt/compositor/main/comp_distortion.h b/src/xrt/compositor/main/comp_distortion.h
new file mode 100644
index 000000000..b70ea626a
--- /dev/null
+++ b/src/xrt/compositor/main/comp_distortion.h
@@ -0,0 +1,135 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Distortion shader code header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "main/comp_settings.h"
+#include "main/comp_compositor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+
+/*!
+ * Helper buffer for a single uniform buffer.
+ *
+ * @ingroup comp
+ */
+struct comp_uniform_buffer
+{
+	VkDevice device;
+	VkBuffer buffer;
+	VkDeviceMemory memory;
+	VkDescriptorBufferInfo descriptor;
+	VkDeviceSize size;
+	VkDeviceSize alignment;
+	void *mapped;
+	VkBufferUsageFlags usageFlags;
+	VkMemoryPropertyFlags memoryPropertyFlags;
+};
+
+/*!
+ * Helper struct that encapsulate a distortion rendering code.
+ *
+ * @ingroup comp
+ */
+struct comp_distortion
+{
+	// Holds all of the needed common Vulkan things.
+	struct vk_bundle *vk;
+
+	struct comp_uniform_buffer ubo_handle;
+	struct comp_uniform_buffer ubo_viewport_handles[2];
+
+	struct
+	{
+		float hmd_warp_param[4];
+		float aberr[4];
+		float lens_center[2][4];
+		float viewport_scale[2];
+		float warp_scale;
+	} ubo_data;
+
+	struct
+	{
+		struct xrt_matrix_2x2 rot;
+		int viewport_id;
+		bool flip_y;
+	} ubo_vp_data[2];
+
+	VkPipelineLayout pipeline_layout;
+	VkPipeline pipeline;
+
+	VkDescriptorSetLayout descriptor_set_layout;
+	VkDescriptorSet descriptor_sets[2];
+};
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+/*!
+ * Init a distortion, pass in the distortion so it can be embedded in a struct.
+ *
+ * @ingroup comp
+ */
+void
+comp_distortion_init(struct comp_distortion *d,
+                     struct comp_compositor *c,
+                     VkRenderPass render_pass,
+                     VkPipelineCache pipeline_cache,
+                     enum xrt_distortion_model distortion_model,
+                     VkDescriptorPool descriptor_pool,
+                     bool flip_y);
+
+/*!
+ * Free and destroy all fields, does not free the destortion itself.
+ *
+ * @ingroup comp
+ */
+void
+comp_distortion_destroy(struct comp_distortion *d);
+
+/*!
+ * Update the descriptor set to a new image.
+ *
+ * @ingroup comp
+ */
+void
+comp_distortion_update_descriptor_set(struct comp_distortion *d,
+                                      VkSampler sampler,
+                                      VkImageView view,
+                                      uint32_t eye);
+
+/*!
+ * Submit draw commands to the given command_buffer.
+ *
+ * @ingroup comp
+ */
+void
+comp_distortion_draw_quad(struct comp_distortion *d,
+                          VkCommandBuffer command_buffer,
+                          int eye);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_glue_gl.c b/src/xrt/compositor/main/comp_glue_gl.c
new file mode 100644
index 000000000..67b5a5e14
--- /dev/null
+++ b/src/xrt/compositor/main/comp_glue_gl.c
@@ -0,0 +1,22 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Glue code to OpenGL client side glue code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include "xrt/xrt_gfx_gl.h"
+
+
+void
+xrt_gfx_gl_get_versions(struct xrt_api_requirements *ver)
+{
+	ver->min_major = 4;
+	ver->min_minor = 5;
+	ver->min_patch = 0;
+	ver->max_major = 4;
+	ver->max_minor = 6;
+	ver->max_patch = (1024 - 1);
+}
diff --git a/src/xrt/compositor/main/comp_glue_vk.c b/src/xrt/compositor/main/comp_glue_vk.c
new file mode 100644
index 000000000..b19c3c424
--- /dev/null
+++ b/src/xrt/compositor/main/comp_glue_vk.c
@@ -0,0 +1,65 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Glue code to vulkan client side glue code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include <stdlib.h>
+
+#include "main/comp_client_interface.h"
+#include "client/comp_vk_client.h"
+
+
+const char *xrt_gfx_vk_instance_extensions =
+    "VK_KHR_external_fence_capabilities "
+    "VK_KHR_external_memory_capabilities "
+    "VK_KHR_external_semaphore_capabilities "
+    "VK_KHR_get_physical_device_properties2 "
+    "VK_KHR_surface";
+
+const char *xrt_gfx_vk_device_extensions =
+    "VK_KHR_dedicated_allocation "
+    "VK_KHR_external_fence "
+    "VK_KHR_external_fence_fd "
+    "VK_KHR_external_memory "
+    "VK_KHR_external_memory_fd "
+    "VK_KHR_external_semaphore "
+    "VK_KHR_external_semaphore_fd "
+    "VK_KHR_get_memory_requirements2 "
+    "VK_KHR_swapchain";
+
+void
+xrt_gfx_vk_get_versions(struct xrt_api_requirements *ver)
+{
+	ver->min_major = 1;
+	ver->min_minor = 0;
+	ver->min_patch = 0;
+
+	ver->max_major = (1024 - 1);
+	ver->max_minor = (1024 - 1);
+	ver->max_patch = (1024 - 1);
+}
+
+struct xrt_compositor_vk *
+xrt_gfx_vk_provider_create(struct xrt_device *xdev,
+                           VkInstance instance,
+                           PFN_vkGetInstanceProcAddr get_instance_proc_addr,
+                           VkPhysicalDevice physical_device,
+                           VkDevice device,
+                           uint32_t queue_family_index,
+                           uint32_t queue_index)
+{
+	struct xrt_compositor_fd *xcfd = comp_compositor_create(xdev, false);
+	if (xcfd == NULL) {
+		return NULL;
+	}
+
+	struct client_vk_compositor *vcc = client_vk_compositor_create(
+	    xcfd, instance, get_instance_proc_addr, physical_device, device,
+	    queue_family_index, queue_index);
+
+	return &vcc->base;
+}
diff --git a/src/xrt/compositor/main/comp_glue_xlib.c b/src/xrt/compositor/main/comp_glue_xlib.c
new file mode 100644
index 000000000..5e4442242
--- /dev/null
+++ b/src/xrt/compositor/main/comp_glue_xlib.c
@@ -0,0 +1,36 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Glue code to Xlib client side glue code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+
+#include "main/comp_client_interface.h"
+#include "client/comp_xlib_client.h"
+
+
+struct xrt_compositor_gl *
+xrt_gfx_provider_create_gl_xlib(struct xrt_device *xdev,
+                                Display *xDisplay,
+                                uint32_t visualid,
+                                GLXFBConfig glxFBConfig,
+                                GLXDrawable glxDrawable,
+                                GLXContext glxContext)
+{
+	struct xrt_compositor_fd *xcfd = comp_compositor_create(xdev, true);
+	if (xcfd == NULL) {
+		return NULL;
+	}
+
+	struct client_xlib_compositor *xcc = client_xlib_compositor_create(
+	    xcfd, xDisplay, visualid, glxFBConfig, glxDrawable, glxContext);
+
+	return &xcc->base.base;
+}
diff --git a/src/xrt/compositor/main/comp_renderer.c b/src/xrt/compositor/main/comp_renderer.c
new file mode 100644
index 000000000..ec29e362b
--- /dev/null
+++ b/src/xrt/compositor/main/comp_renderer.c
@@ -0,0 +1,997 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Compositor rendering code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "xrt/xrt_compositor.h"
+#include "main/comp_distortion.h"
+
+
+/*
+ *
+ * Private struct.
+ *
+ */
+
+/*!
+ * Holds associated vulkan objects and state to render with a distortion.
+ *
+ * @ingroup comp
+ */
+struct comp_renderer
+{
+	bool one_buffer_imported[2];
+
+	uint32_t current_buffer;
+
+	VkQueue queue;
+	VkRenderPass render_pass;
+	VkDescriptorPool descriptor_pool;
+	VkPipelineCache pipeline_cache;
+
+	struct
+	{
+		VkSemaphore present_complete;
+		VkSemaphore render_complete;
+	} semaphores;
+
+	VkCommandBuffer *cmd_buffers;
+	uint32_t num_cmd_buffers;
+	VkFramebuffer *frame_buffers;
+	uint32_t num_frame_buffers;
+
+	struct comp_swapchain_image dummy_images[2];
+
+	struct comp_compositor *c;
+	struct comp_settings *settings;
+	struct comp_distortion *distortion;
+};
+
+
+/*
+ *
+ * Pre declare functions.
+ *
+ */
+
+static void
+renderer_create(struct comp_renderer *r, struct comp_compositor *c);
+
+static void
+renderer_init(struct comp_renderer *r);
+
+static void
+renderer_set_swapchain_image(struct comp_renderer *r,
+                             uint32_t eye,
+                             struct comp_swapchain_image *image);
+
+static void
+renderer_render(struct comp_renderer *r);
+
+static void
+renderer_submit_queue(struct comp_renderer *r);
+
+static void
+renderer_build_command_buffers(struct comp_renderer *r);
+
+static void
+renderer_rebuild_command_buffers(struct comp_renderer *r);
+
+static void
+renderer_build_command_buffer(struct comp_renderer *r,
+                              VkCommandBuffer command_buffer,
+                              VkFramebuffer framebuffer);
+
+static void
+renderer_init_descriptor_pool(struct comp_renderer *r);
+
+static void
+renderer_init_dummy_images(struct comp_renderer *r);
+
+static void
+renderer_create_frame_buffer(struct comp_renderer *r,
+                             VkFramebuffer *frame_buffer,
+                             uint32_t num_attachements,
+                             VkImageView *attachments);
+
+static void
+renderer_allocate_command_buffers(struct comp_renderer *r, uint32_t count);
+
+static void
+renderer_destroy_command_buffers(struct comp_renderer *r);
+
+static void
+renderer_create_pipeline_cache(struct comp_renderer *r);
+
+static void
+renderer_init_semaphores(struct comp_renderer *r);
+
+static void
+renderer_resize(struct comp_renderer *r);
+
+static void
+renderer_create_frame_buffers(struct comp_renderer *r, uint32_t count);
+
+static void
+renderer_create_render_pass(struct comp_renderer *r);
+
+static void
+renderer_aquire_swapchain_image(struct comp_renderer *r);
+
+static void
+renderer_present_swapchain_image(struct comp_renderer *r);
+
+static void
+renderer_destroy(struct comp_renderer *r);
+
+
+/*
+ *
+ * Interface functions.
+ *
+ */
+
+struct comp_renderer *
+comp_renderer_create(struct comp_compositor *c)
+{
+	struct comp_renderer *r = malloc(sizeof(struct comp_renderer));
+
+	renderer_create(r, c);
+	renderer_init(r);
+
+	return r;
+}
+
+void
+comp_renderer_frame(struct comp_renderer *r,
+                    struct comp_swapchain_image *left,
+                    struct comp_swapchain_image *right)
+{
+	renderer_set_swapchain_image(r, 0, left);
+	renderer_set_swapchain_image(r, 1, right);
+	renderer_render(r);
+	r->c->vk.vkDeviceWaitIdle(r->c->vk.device);
+}
+
+void
+comp_renderer_destroy(struct comp_renderer *r)
+{
+	renderer_destroy(r);
+	free(r);
+}
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+static void
+renderer_create(struct comp_renderer *r, struct comp_compositor *c)
+{
+	r->c = c;
+	r->settings = &c->settings;
+
+	r->one_buffer_imported[0] = false;
+	r->one_buffer_imported[1] = false;
+	r->current_buffer = 0;
+	r->queue = VK_NULL_HANDLE;
+	r->render_pass = VK_NULL_HANDLE;
+	r->descriptor_pool = VK_NULL_HANDLE;
+	r->pipeline_cache = VK_NULL_HANDLE;
+	r->semaphores.present_complete = VK_NULL_HANDLE;
+	r->semaphores.render_complete = VK_NULL_HANDLE;
+
+	memset(&r->dummy_images[0], 0, sizeof(struct comp_swapchain_image));
+	memset(&r->dummy_images[1], 0, sizeof(struct comp_swapchain_image));
+
+	r->distortion = NULL;
+	r->cmd_buffers = NULL;
+	r->frame_buffers = NULL;
+}
+
+static void
+renderer_submit_queue(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkPipelineStageFlags stage_flags[1] = {
+	    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+	};
+
+	VkSubmitInfo comp_submit_info = {
+	    .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+	    .pNext = NULL,
+	    .waitSemaphoreCount = 1,
+	    .pWaitSemaphores = &r->semaphores.present_complete,
+	    .pWaitDstStageMask = stage_flags,
+	    .commandBufferCount = 1,
+	    .pCommandBuffers = &r->cmd_buffers[r->current_buffer],
+	    .signalSemaphoreCount = 1,
+	    .pSignalSemaphores = &r->semaphores.render_complete,
+	};
+
+	ret = vk->vkQueueSubmit(r->queue, 1, &comp_submit_info, VK_NULL_HANDLE);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkQueueSubmit: %s", vk_result_string(ret));
+	}
+}
+
+static void
+renderer_build_command_buffers(struct comp_renderer *r)
+{
+	for (uint32_t i = 0; i < r->num_cmd_buffers; ++i)
+		renderer_build_command_buffer(r, r->cmd_buffers[i],
+		                              r->frame_buffers[i]);
+}
+
+static void
+renderer_rebuild_command_buffers(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+
+	vk->vkFreeCommandBuffers(vk->device, vk->cmd_pool, r->num_cmd_buffers,
+	                         r->cmd_buffers);
+	renderer_allocate_command_buffers(r,
+	                                  r->c->window->swapchain.image_count);
+	renderer_build_command_buffers(r);
+}
+
+static void
+renderer_set_viewport_scissor(float scale_x,
+                              float scale_y,
+                              VkViewport *v,
+                              VkRect2D *s,
+                              struct xrt_view *view)
+{
+	v->x = view->viewport.x_pixels * scale_x;
+	v->y = view->viewport.y_pixels * scale_y;
+	v->width = view->viewport.w_pixels * scale_x;
+	v->height = view->viewport.h_pixels * scale_y;
+
+	s->offset.x = (int32_t)(view->viewport.x_pixels * scale_x);
+	s->offset.y = (int32_t)(view->viewport.y_pixels * scale_y);
+	s->extent.width = (uint32_t)(view->viewport.w_pixels * scale_x);
+	s->extent.height = (uint32_t)(view->viewport.h_pixels * scale_y);
+}
+
+static void
+renderer_build_command_buffer(struct comp_renderer *r,
+                              VkCommandBuffer command_buffer,
+                              VkFramebuffer framebuffer)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkClearValue clear_color = {
+	    .color = {.float32 = {0.0f, 0.0f, 0.0f, 0.0f}}};
+
+	VkCommandBufferBeginInfo command_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .pInheritanceInfo = NULL,
+	};
+
+	ret = vk->vkBeginCommandBuffer(command_buffer, &command_buffer_info);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkBeginCommandBuffer: %s",
+		           vk_result_string(ret));
+		return;
+	}
+
+	VkRenderPassBeginInfo render_pass_begin_info = {
+	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
+	    .pNext = NULL,
+	    .renderPass = r->render_pass,
+	    .framebuffer = framebuffer,
+	    .renderArea =
+	        {
+	            .offset =
+	                {
+	                    .x = 0,
+	                    .y = 0,
+	                },
+	            .extent =
+	                {
+	                    .width = r->c->current.width,
+	                    .height = r->c->current.height,
+	                },
+	        },
+	    .clearValueCount = 1,
+	    .pClearValues = &clear_color,
+	};
+	vk->vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info,
+	                         VK_SUBPASS_CONTENTS_INLINE);
+
+
+	// clang-format off
+	float scale_x = (float)r->c->current.width /
+	                (float)r->c->xdev->screens[0].w_pixels;
+	float scale_y = (float)r->c->current.height /
+	                (float)r->c->xdev->screens[0].h_pixels;
+	// clang-format on
+
+	VkViewport viewport = {
+	    .x = 0,
+	    .y = 0,
+	    .width = 0,
+	    .height = 0,
+	    .minDepth = 0.0f,
+	    .maxDepth = 1.0f,
+	};
+
+	VkRect2D scissor = {
+	    .offset = {.x = 0, .y = 0},
+	    .extent = {.width = 0, .height = 0},
+	};
+
+	renderer_set_viewport_scissor(scale_x, scale_y, &viewport, &scissor,
+	                              &r->c->xdev->views[0]);
+	vk->vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+	vk->vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+
+	comp_distortion_draw_quad(r->distortion, command_buffer, 0);
+
+
+	renderer_set_viewport_scissor(scale_x, scale_y, &viewport, &scissor,
+	                              &r->c->xdev->views[1]);
+	vk->vkCmdSetViewport(command_buffer, 0, 1, &viewport);
+	vk->vkCmdSetScissor(command_buffer, 0, 1, &scissor);
+
+	comp_distortion_draw_quad(r->distortion, command_buffer, 1);
+
+	vk->vkCmdEndRenderPass(command_buffer);
+
+	ret = vk->vkEndCommandBuffer(command_buffer);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkEndCommandBuffer: %s",
+		           vk_result_string(ret));
+		return;
+	}
+}
+
+static void
+renderer_init_descriptor_pool(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkDescriptorPoolSize pool_sizes[2] = {
+	    {
+	        .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+	        .descriptorCount = 4,
+	    },
+	    {
+	        .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+	        .descriptorCount = 2,
+	    },
+	};
+
+	VkDescriptorPoolCreateInfo descriptor_pool_info = {
+	    .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .maxSets = 2,
+	    .poolSizeCount = ARRAY_SIZE(pool_sizes),
+	    .pPoolSizes = pool_sizes,
+	};
+
+	ret = vk->vkCreateDescriptorPool(vk->device, &descriptor_pool_info,
+	                                 NULL, &r->descriptor_pool);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateDescriptorPool: %s",
+		           vk_result_string(ret));
+	}
+}
+
+
+static void
+_set_image_layout(struct vk_bundle *vk,
+                  VkCommandBuffer cmd_buffer,
+                  VkImage image,
+                  VkAccessFlags src_access_mask,
+                  VkAccessFlags dst_access_mask,
+                  VkImageLayout old_layout,
+                  VkImageLayout new_layout,
+                  VkImageSubresourceRange subresource_range)
+{
+	VkImageMemoryBarrier barrier = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
+	    .pNext = NULL,
+	    .srcAccessMask = src_access_mask,
+	    .dstAccessMask = dst_access_mask,
+	    .oldLayout = old_layout,
+	    .newLayout = new_layout,
+	    .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+	    .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
+	    .image = image,
+	    .subresourceRange = subresource_range,
+	};
+
+	vk->vkCmdPipelineBarrier(cmd_buffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+	                         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, NULL,
+	                         0, NULL, 1, &barrier);
+}
+
+static bool
+_init_cmd_buffer(struct comp_compositor *c,
+                 VkCommandPool cmd_pool,
+                 VkCommandBuffer *out_cmd_buffer)
+{
+	struct vk_bundle *vk = &c->vk;
+
+	VkCommandBufferAllocateInfo cmd_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+	    .pNext = NULL,
+	    .commandPool = cmd_pool,
+	    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+	    .commandBufferCount = 1,
+	};
+
+	VkResult ret;
+	ret = vk->vkAllocateCommandBuffers(vk->device, &cmd_buffer_info,
+	                                   out_cmd_buffer);
+	if (ret != VK_SUCCESS) {
+		fprintf(stderr,
+		        "Error: Could not initialize command buffer.\n");
+		return false;
+	}
+
+	VkCommandBufferBeginInfo begin_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .pInheritanceInfo = NULL,
+	};
+	ret = vk->vkBeginCommandBuffer(*out_cmd_buffer, &begin_info);
+	if (ret != VK_SUCCESS) {
+		fprintf(stderr, "Error: Could not begin command buffer.\n");
+		return false;
+	}
+	return true;
+}
+
+static bool
+_submit_cmd_buffer(struct comp_compositor *c,
+                   VkCommandPool cmd_pool,
+                   VkCommandBuffer cmd_buffer)
+{
+	struct vk_bundle *vk = &c->vk;
+	VkResult ret;
+
+	ret = vk->vkEndCommandBuffer(cmd_buffer);
+	if (ret != VK_SUCCESS) {
+	}
+
+	VkSubmitInfo submitInfo = {
+	    .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
+	    .pNext = NULL,
+	    .waitSemaphoreCount = 0,
+	    .pWaitSemaphores = NULL,
+	    .pWaitDstStageMask = NULL,
+	    .commandBufferCount = 1,
+	    .pCommandBuffers = &cmd_buffer,
+	    .signalSemaphoreCount = 0,
+	    .pSignalSemaphores = NULL,
+	};
+
+	VkFenceCreateInfo fence_info = {
+	    .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	};
+	VkFence fence;
+	ret = vk->vkCreateFence(vk->device, &fence_info, NULL, &fence);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "vkCreateFence: %s", vk_result_string(ret));
+		vk->vkFreeCommandBuffers(vk->device, cmd_pool, 1, &cmd_buffer);
+		return false;
+	}
+
+	VkQueue queue;
+	vk->vkGetDeviceQueue(vk->device, c->vk.queue_family_index, 0, &queue);
+
+	ret = vk->vkQueueSubmit(queue, 1, &submitInfo, fence);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "vkCreateFence: %s", vk_result_string(ret));
+		vk->vkDestroyFence(vk->device, fence, NULL);
+		vk->vkFreeCommandBuffers(vk->device, cmd_pool, 1, &cmd_buffer);
+		return false;
+	}
+
+	ret = vk->vkWaitForFences(vk->device, 1, &fence, VK_TRUE, UINT64_MAX);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "vkCreateFence: %s", vk_result_string(ret));
+		vk->vkDestroyFence(vk->device, fence, NULL);
+		vk->vkFreeCommandBuffers(vk->device, cmd_pool, 1, &cmd_buffer);
+		return false;
+	}
+
+	vk->vkDestroyFence(vk->device, fence, NULL);
+	vk->vkFreeCommandBuffers(vk->device, cmd_pool, 1, &cmd_buffer);
+
+	return true;
+}
+
+static void
+renderer_init_dummy_images(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkCommandBuffer cmd_buffer;
+	_init_cmd_buffer(r->c, vk->cmd_pool, &cmd_buffer);
+
+	VkImageSubresourceRange subresource_range = {
+	    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	    .baseMipLevel = 0,
+	    .levelCount = 1,
+	    .baseArrayLayer = 0,
+	    .layerCount = 1};
+
+	VkClearColorValue color = {.float32 = {1, 1, 1, 1}};
+
+	for (uint32_t i = 0; i < 2; i++) {
+		vk_create_image_simple(
+		    &r->c->vk, 640, 800, VK_FORMAT_B8G8R8A8_SRGB,
+		    &r->dummy_images[i].memory, &r->dummy_images[i].image);
+
+		_set_image_layout(
+		    vk, cmd_buffer, r->dummy_images[i].image, 0,
+		    VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
+		    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, subresource_range);
+
+		vk->vkCmdClearColorImage(cmd_buffer, r->dummy_images[i].image,
+		                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		                         &color, 1, &subresource_range);
+
+		vk_set_image_layout(vk, cmd_buffer, r->dummy_images[i].image,
+		                    VK_ACCESS_TRANSFER_WRITE_BIT,
+		                    VK_ACCESS_SHADER_READ_BIT,
+		                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+		                    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		                    subresource_range);
+
+		vk_create_sampler(vk, &r->dummy_images[i].sampler);
+		vk_create_view(vk, r->dummy_images[i].image,
+		               VK_FORMAT_B8G8R8A8_SRGB,
+		               &r->dummy_images[i].view);
+	}
+
+	_submit_cmd_buffer(r->c, vk->cmd_pool, cmd_buffer);
+}
+
+static void
+renderer_init(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+	vk->vkGetDeviceQueue(vk->device, r->c->vk.queue_family_index, 0,
+	                     &r->queue);
+	renderer_init_semaphores(r);
+	renderer_create_pipeline_cache(r);
+	renderer_create_render_pass(r);
+
+	assert(r->c->window->swapchain.image_count > 0);
+
+	renderer_create_frame_buffers(r, r->c->window->swapchain.image_count);
+	renderer_allocate_command_buffers(r,
+	                                  r->c->window->swapchain.image_count);
+
+	renderer_init_dummy_images(r);
+
+	renderer_init_descriptor_pool(r);
+
+	r->distortion = calloc(1, sizeof(struct comp_distortion));
+
+	comp_distortion_init(r->distortion, r->c, r->render_pass,
+	                     r->pipeline_cache, r->settings->distortion_model,
+	                     r->descriptor_pool, r->settings->flip_y);
+
+	for (uint32_t i = 0; i < 2; i++)
+		comp_distortion_update_descriptor_set(
+		    r->distortion, r->dummy_images[i].sampler,
+		    r->dummy_images[i].view, i);
+
+	renderer_build_command_buffers(r);
+}
+
+static void
+renderer_set_swapchain_image(struct comp_renderer *r,
+                             uint32_t eye,
+                             struct comp_swapchain_image *image)
+{
+	if (eye > 1) {
+		COMP_ERROR(r->c, "Swapchain image %p %u not found",
+		           (void *)image, eye);
+		return;
+	}
+
+	if (!r->one_buffer_imported[eye]) {
+		COMP_DEBUG(r->c,
+		           "Updating descriptor set for"
+		           " swapchain image %p and eye %u",
+		           (void *)image, eye);
+		comp_distortion_update_descriptor_set(
+		    r->distortion, image->sampler, image->view, (uint32_t)eye);
+		renderer_rebuild_command_buffers(r);
+		r->one_buffer_imported[eye] = true;
+	}
+}
+
+static void
+renderer_render(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+	r->c->window->flush(r->c->window);
+	renderer_aquire_swapchain_image(r);
+	vk->vkDeviceWaitIdle(vk->device);
+	renderer_submit_queue(r);
+	renderer_present_swapchain_image(r);
+}
+
+static void
+renderer_create_frame_buffer(struct comp_renderer *r,
+                             VkFramebuffer *frame_buffer,
+                             uint32_t num_attachements,
+                             VkImageView *attachments)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkFramebufferCreateInfo frame_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .renderPass = r->render_pass,
+	    .attachmentCount = num_attachements,
+	    .pAttachments = attachments,
+	    .width = r->c->current.width,
+	    .height = r->c->current.height,
+	    .layers = 1,
+	};
+
+	ret = vk->vkCreateFramebuffer(vk->device, &frame_buffer_info, NULL,
+	                              frame_buffer);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateFramebuffer: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_allocate_command_buffers(struct comp_renderer *r, uint32_t count)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	if (count == 0) {
+		COMP_ERROR(r->c, "Requested 0 command buffers.");
+		return;
+	}
+
+	COMP_DEBUG(r->c, "Allocating %d Command Buffers.", count);
+
+	if (r->cmd_buffers != NULL)
+		free(r->cmd_buffers);
+
+	r->num_cmd_buffers = count;
+
+	r->cmd_buffers = malloc(sizeof(VkCommandBuffer) * count);
+
+	VkCommandBufferAllocateInfo cmd_buffer_info = {
+	    .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
+	    .pNext = NULL,
+	    .commandPool = vk->cmd_pool,
+	    .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
+	    .commandBufferCount = count,
+	};
+
+	ret = vk->vkAllocateCommandBuffers(vk->device, &cmd_buffer_info,
+	                                   r->cmd_buffers);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateFramebuffer: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_destroy_command_buffers(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+	vk->vkFreeCommandBuffers(vk->device, vk->cmd_pool, r->num_cmd_buffers,
+	                         r->cmd_buffers);
+}
+
+static void
+renderer_create_pipeline_cache(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkPipelineCacheCreateInfo pipeline_cache_info = {
+	    .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .initialDataSize = 0,
+	    .pInitialData = NULL,
+	};
+	ret = vk->vkCreatePipelineCache(vk->device, &pipeline_cache_info, NULL,
+	                                &r->pipeline_cache);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreatePipelineCache: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_init_semaphores(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkSemaphoreCreateInfo info = {
+	    .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	};
+
+	ret = vk->vkCreateSemaphore(vk->device, &info, NULL,
+	                            &r->semaphores.present_complete);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateSemaphore: %s",
+		           vk_result_string(ret));
+	}
+
+	ret = vk->vkCreateSemaphore(vk->device, &info, NULL,
+	                            &r->semaphores.render_complete);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateSemaphore: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_resize(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+	vk->vkDeviceWaitIdle(vk->device);
+
+	vk_swapchain_create(&r->c->window->swapchain, r->c->current.width,
+	                    r->c->current.height, r->settings->color_format,
+	                    r->settings->color_space,
+	                    r->settings->present_mode);
+
+	for (uint32_t i = 0; i < r->num_frame_buffers; i++)
+		vk->vkDestroyFramebuffer(vk->device, r->frame_buffers[i], NULL);
+	renderer_create_frame_buffers(r, r->c->window->swapchain.image_count);
+
+	renderer_destroy_command_buffers(r);
+	renderer_allocate_command_buffers(r,
+	                                  r->c->window->swapchain.image_count);
+
+	renderer_build_command_buffers(r);
+	vk->vkDeviceWaitIdle(vk->device);
+}
+
+static void
+renderer_create_frame_buffers(struct comp_renderer *r, uint32_t count)
+{
+	r->num_frame_buffers = count;
+
+	if (r->frame_buffers != NULL)
+		free(r->frame_buffers);
+
+	r->frame_buffers = malloc(sizeof(VkFramebuffer) * count);
+
+	for (uint32_t i = 0; i < count; i++) {
+		VkImageView attachments[1] = {
+		    r->c->window->swapchain.buffers[i].view,
+		};
+		renderer_create_frame_buffer(r, &r->frame_buffers[i],
+		                             ARRAY_SIZE(attachments),
+		                             attachments);
+	}
+}
+
+static void
+renderer_create_render_pass(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	VkAttachmentDescription attachments[1] = {
+	    (VkAttachmentDescription){
+	        .flags = 0,
+	        .format = r->c->window->swapchain.surface_format.format,
+	        .samples = VK_SAMPLE_COUNT_1_BIT,
+	        .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
+	        .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
+	        .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
+	        .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
+	        .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+	        .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
+	    },
+	};
+
+	VkAttachmentReference color_reference = {
+	    .attachment = 0,
+	    .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+	};
+
+	VkSubpassDescription subpass_description = {
+	    .flags = 0,
+	    .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
+	    .inputAttachmentCount = 0,
+	    .pInputAttachments = NULL,
+	    .colorAttachmentCount = 1,
+	    .pColorAttachments = &color_reference,
+	    .pResolveAttachments = NULL,
+	    .pDepthStencilAttachment = NULL,
+	    .preserveAttachmentCount = 0,
+	    .pPreserveAttachments = NULL,
+	};
+
+	VkSubpassDependency dependencies[1] = {
+	    (VkSubpassDependency){
+	        .srcSubpass = VK_SUBPASS_EXTERNAL,
+	        .dstSubpass = 0,
+	        .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+	        .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
+	        .srcAccessMask = 0,
+	        .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+	                         VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+	        .dependencyFlags = 0,
+	    },
+	};
+
+	VkRenderPassCreateInfo render_pass_info = {
+	    .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
+	    .pNext = NULL,
+	    .flags = 0,
+	    .attachmentCount = ARRAY_SIZE(attachments),
+	    .pAttachments = attachments,
+	    .subpassCount = 1,
+	    .pSubpasses = &subpass_description,
+	    .dependencyCount = ARRAY_SIZE(dependencies),
+	    .pDependencies = dependencies,
+	};
+
+	ret = vk->vkCreateRenderPass(vk->device, &render_pass_info, NULL,
+	                             &r->render_pass);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkCreateRenderPass: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_aquire_swapchain_image(struct comp_renderer *r)
+{
+	VkResult ret;
+
+	ret = vk_swapchain_acquire_next_image(&r->c->window->swapchain,
+	                                      r->semaphores.present_complete,
+	                                      &r->current_buffer);
+
+	if ((ret == VK_ERROR_OUT_OF_DATE_KHR) || (ret == VK_SUBOPTIMAL_KHR)) {
+		COMP_DEBUG(r->c, "Received %s.", vk_result_string(ret));
+		renderer_resize(r);
+		/* Acquire image again to silence validation error */
+		ret = vk_swapchain_acquire_next_image(
+		    &r->c->window->swapchain, r->semaphores.present_complete,
+		    &r->current_buffer);
+		if (ret != VK_SUCCESS) {
+			COMP_ERROR(r->c, "vk_swapchain_acquire_next_image: %s",
+			           vk_result_string(ret));
+		}
+	} else if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vk_swapchain_acquire_next_image: %s",
+		           vk_result_string(ret));
+	}
+}
+
+static void
+renderer_present_swapchain_image(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+	VkResult ret;
+
+	ret = vk_swapchain_present(&r->c->window->swapchain, r->queue,
+	                           r->current_buffer,
+	                           r->semaphores.render_complete);
+	if (ret == VK_ERROR_OUT_OF_DATE_KHR) {
+		renderer_resize(r);
+		return;
+	} else if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vk_swapchain_present: %s",
+		           vk_result_string(ret));
+	}
+
+	ret = vk->vkQueueWaitIdle(r->queue);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(r->c, "vkQueueWaitIdle: %s", vk_result_string(ret));
+	}
+}
+
+static void
+renderer_destroy(struct comp_renderer *r)
+{
+	struct vk_bundle *vk = &r->c->vk;
+
+	// Distortion
+	if (r->distortion != NULL) {
+		comp_distortion_destroy(r->distortion);
+		r->distortion = NULL;
+	}
+
+	// Dummy images
+	for (uint32_t i = 0; i < 2; i++) {
+		comp_swapchain_image_cleanup(vk, &r->dummy_images[i]);
+	}
+
+	// Discriptor pool
+	if (r->descriptor_pool != VK_NULL_HANDLE) {
+		vk->vkDestroyDescriptorPool(vk->device, r->descriptor_pool,
+		                            NULL);
+		r->descriptor_pool = VK_NULL_HANDLE;
+	}
+
+	// Command buffers
+	renderer_destroy_command_buffers(r);
+	if (r->cmd_buffers != NULL)
+		free(r->cmd_buffers);
+	r->num_cmd_buffers = 0;
+
+	// Render pass
+	if (r->render_pass != VK_NULL_HANDLE) {
+		vk->vkDestroyRenderPass(vk->device, r->render_pass, NULL);
+		r->render_pass = VK_NULL_HANDLE;
+	}
+
+	// Frame buffers
+	for (uint32_t i = 0; i < r->num_frame_buffers; i++) {
+		if (r->frame_buffers[i] != VK_NULL_HANDLE) {
+			vk->vkDestroyFramebuffer(vk->device,
+			                         r->frame_buffers[i], NULL);
+			r->frame_buffers[i] = VK_NULL_HANDLE;
+		}
+	}
+	if (r->frame_buffers != NULL)
+		free(r->frame_buffers);
+	r->frame_buffers = NULL;
+	r->num_frame_buffers = 0;
+
+	// Pipeline cache
+	if (r->pipeline_cache != VK_NULL_HANDLE) {
+		vk->vkDestroyPipelineCache(vk->device, r->pipeline_cache, NULL);
+		r->pipeline_cache = VK_NULL_HANDLE;
+	}
+
+	// Semaphores
+	if (r->semaphores.present_complete != VK_NULL_HANDLE) {
+		vk->vkDestroySemaphore(vk->device,
+		                       r->semaphores.present_complete, NULL);
+		r->semaphores.present_complete = VK_NULL_HANDLE;
+	}
+	if (r->semaphores.render_complete != VK_NULL_HANDLE) {
+		vk->vkDestroySemaphore(vk->device,
+		                       r->semaphores.render_complete, NULL);
+		r->semaphores.render_complete = VK_NULL_HANDLE;
+	}
+}
diff --git a/src/xrt/compositor/main/comp_renderer.h b/src/xrt/compositor/main/comp_renderer.h
new file mode 100644
index 000000000..9c4af294b
--- /dev/null
+++ b/src/xrt/compositor/main/comp_renderer.h
@@ -0,0 +1,53 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Compositor rendering code header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "xrt/xrt_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct comp_compositor;
+struct comp_renderer;
+struct comp_swapchain_image;
+
+/*!
+ * Called by the main compositor code to create the renderer.
+ *
+ * @ingroup comp
+ */
+struct comp_renderer *
+comp_renderer_create(struct comp_compositor *c);
+
+/*!
+ * Render a distorted stereo frame.
+ *
+ * @ingroup comp
+ */
+void
+comp_renderer_frame(struct comp_renderer *r,
+                    struct comp_swapchain_image *left,
+                    struct comp_swapchain_image *right);
+
+/*!
+ * Clean up and free the renderer.
+ *
+ * @ingroup comp
+ */
+void
+comp_renderer_destroy(struct comp_renderer *r);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_settings.c b/src/xrt/compositor/main/comp_settings.c
new file mode 100644
index 000000000..418855237
--- /dev/null
+++ b/src/xrt/compositor/main/comp_settings.c
@@ -0,0 +1,51 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Settings struct for compositor.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @ingroup comp
+ */
+
+#include "util/u_debug.h"
+#include "comp_settings.h"
+
+DEBUG_GET_ONCE_BOOL_OPTION(print_spew, "XRT_COMPOSITOR_PRINT_SPEW", false)
+DEBUG_GET_ONCE_BOOL_OPTION(print_debug, "XRT_COMPOSITOR_PRINT_DEBUG", false)
+DEBUG_GET_ONCE_BOOL_OPTION(force_direct, "XRT_COMPOSITOR_FORCE_DIRECT", false)
+DEBUG_GET_ONCE_BOOL_OPTION(force_xcb, "XRT_COMPOSITOR_FORCE_XCB", false)
+DEBUG_GET_ONCE_BOOL_OPTION(force_wayland, "XRT_COMPOSITOR_FORCE_WAYLAND", false)
+
+void
+comp_settings_init(struct comp_settings *s, struct xrt_device *xdev)
+{
+	s->display = -1;
+	s->mode = -1;
+	s->color_format = VK_FORMAT_B8G8R8A8_UNORM;
+	s->color_space = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+	s->present_mode = VK_PRESENT_MODE_FIFO_KHR;
+	s->window_type = WINDOW_AUTO;
+	s->fullscreen = false;
+	s->flip_y = false;
+	s->distortion_model = xdev->distortion.preferred;
+	s->width = xdev->screens[0].w_pixels;
+	s->height = xdev->screens[0].h_pixels;
+	s->print_spew = debug_get_bool_option_print_spew();
+	s->print_debug = debug_get_bool_option_print_debug();
+
+	if (debug_get_bool_option_force_direct()) {
+		s->window_type = WINDOW_DIRECT_MODE;
+	}
+	if (debug_get_bool_option_force_xcb()) {
+		s->window_type = WINDOW_XCB;
+		// HMD screen tends to be much larger then monitors.
+		s->width /= 2;
+		s->height /= 2;
+	}
+	if (debug_get_bool_option_force_wayland()) {
+		s->window_type = WINDOW_WAYLAND;
+		// HMD screen tends to be much larger then monitors.
+		s->width /= 2;
+		s->height /= 2;
+	}
+}
diff --git a/src/xrt/compositor/main/comp_settings.h b/src/xrt/compositor/main/comp_settings.h
new file mode 100644
index 000000000..97c491ecd
--- /dev/null
+++ b/src/xrt/compositor/main/comp_settings.h
@@ -0,0 +1,83 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Settings struct for compositor header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_compositor.h"
+#include "xrt/xrt_vulkan_includes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * Window type to use.
+ *
+ * @ingroup comp
+ */
+enum window_type
+{
+	WINDOW_NONE = 0,
+	WINDOW_AUTO,
+	WINDOW_XCB,
+	WINDOW_WAYLAND,
+	WINDOW_DIRECT_MODE,
+};
+
+/*!
+ * Settings for the compositor.
+ *
+ * @ingroup comp
+ */
+struct comp_settings
+{
+	int display;
+	int mode;
+
+	VkFormat color_format;
+	VkColorSpaceKHR color_space;
+	VkPresentModeKHR present_mode;
+
+	//! Window type to use.
+	enum window_type window_type;
+
+	//! Distortion type to use.
+	enum xrt_distortion_model distortion_model;
+
+	uint32_t width;
+	uint32_t height;
+
+	//! Not used with direct mode.
+	bool fullscreen;
+
+	//! Should we debug print a lot!
+	bool print_spew;
+
+	//! Should we debug print.
+	bool print_debug;
+
+	//! Should we flip y axis for compositor buffers (for GL)
+	bool flip_y;
+};
+
+/*!
+ * Initialize the settings struct with either defaults or loaded setting.
+ *
+ * @ingroup comp
+ */
+void
+comp_settings_init(struct comp_settings *s, struct xrt_device *xdev);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_swapchain.c b/src/xrt/compositor/main/comp_swapchain.c
new file mode 100644
index 000000000..523efcaf1
--- /dev/null
+++ b/src/xrt/compositor/main/comp_swapchain.c
@@ -0,0 +1,303 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Swapchain code for the main compositor.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "main/comp_compositor.h"
+
+
+static void
+swapchain_destroy(struct xrt_swapchain *xsc)
+{
+	struct comp_swapchain *sc = comp_swapchain(xsc);
+	struct vk_bundle *vk = &sc->c->vk;
+
+	COMP_SPEW(sc->c, "DESTROY");
+
+	for (uint32_t i = 0; i < sc->base.base.num_images; i++) {
+		comp_swapchain_image_cleanup(vk, &sc->images[i]);
+	}
+
+	free(sc);
+}
+
+static bool
+swapchain_acquire_image(struct xrt_swapchain *xsc, uint32_t *index)
+{
+	struct comp_swapchain *sc = comp_swapchain(xsc);
+
+	COMP_SPEW(sc->c, "ACQUIRE_IMAGE");
+	*index = 0;
+	return true;
+}
+
+static bool
+swapchain_wait_image(struct xrt_swapchain *xsc,
+                     uint64_t timeout,
+                     uint32_t index)
+{
+	struct comp_swapchain *sc = comp_swapchain(xsc);
+
+	COMP_SPEW(sc->c, "WAIT_IMAGE");
+	return true;
+}
+
+static bool
+swapchain_release_image(struct xrt_swapchain *xsc, uint32_t index)
+{
+	struct comp_swapchain *sc = comp_swapchain(xsc);
+
+	COMP_SPEW(sc->c, "RELEASE_IMAGE");
+	return true;
+}
+
+static VkResult
+create_image_fd(struct comp_compositor *c,
+                int64_t format,
+                uint32_t width,
+                uint32_t height,
+                uint32_t mip_count,
+                VkImage *out_image,
+                VkDeviceMemory *out_mem,
+                struct xrt_image_fd *out_image_fd)
+{
+	VkMemoryRequirements memory_requirements;
+	VkImageUsageFlagBits image_usage = 0;
+	VkDeviceMemory device_memory = NULL;
+	uint32_t memory_type_index = UINT32_MAX;
+	VkImage image = NULL;
+	VkResult ret;
+	size_t size;
+	int fd;
+
+	COMP_SPEW(c, "->image - vkCreateImage %dx%d", width, height);
+
+
+	/*
+	 * Create the image.
+	 */
+
+	VkExternalMemoryImageCreateInfoKHR external_memory_image_create_info = {
+	    .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR,
+	    .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
+	};
+
+	image_usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
+	image_usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+	image_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+	VkImageCreateInfo info = {
+	    .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
+	    .pNext = &external_memory_image_create_info,
+	    .imageType = VK_IMAGE_TYPE_2D,
+	    .format = format,
+	    .extent = {.width = width, .height = height, .depth = 1},
+	    .mipLevels = mip_count,
+	    .arrayLayers = 1,
+	    .samples = VK_SAMPLE_COUNT_1_BIT,
+	    .tiling = VK_IMAGE_TILING_OPTIMAL,
+	    .usage = image_usage,
+	    .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
+	    .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
+	};
+
+	ret = c->vk.vkCreateImage(c->vk.device, &info, NULL, &image);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "->image - vkCreateImage: %s",
+		           vk_result_string(ret));
+		goto err;
+	}
+
+
+	/*
+	 * Get the size of the buffer.
+	 */
+
+	c->vk.vkGetImageMemoryRequirements(c->vk.device, image,
+	                                   &memory_requirements);
+	size = memory_requirements.size;
+
+	if (!vk_get_memory_type(&c->vk, memory_requirements.memoryTypeBits,
+	                        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
+	                        &memory_type_index)) {
+		COMP_ERROR(c, "->image - _get_memory_type!");
+		ret = VK_ERROR_OUT_OF_DEVICE_MEMORY;
+		goto err_image;
+	}
+
+	/*
+	 * Create the memory.
+	 */
+
+	VkMemoryDedicatedAllocateInfoKHR dedicated_memory_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR,
+	    .pNext = NULL,
+	    .image = image,
+	    .buffer = VK_NULL_HANDLE,
+	};
+
+	VkExportMemoryAllocateInfo export_alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR,
+	    .pNext = &dedicated_memory_info,
+	    .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
+	};
+
+	VkMemoryAllocateInfo alloc_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
+	    .pNext = &export_alloc_info,
+	    .allocationSize = size,
+	    .memoryTypeIndex = memory_type_index,
+	};
+
+	ret = c->vk.vkAllocateMemory(c->vk.device, &alloc_info, NULL,
+	                             &device_memory);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "->image - vkAllocateMemory: %s",
+		           vk_result_string(ret));
+		goto err_image;
+	}
+
+	ret = c->vk.vkBindImageMemory(c->vk.device, image, device_memory, 0);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "->image - vkBindImageMemory: %s",
+		           vk_result_string(ret));
+		goto err_mem;
+	}
+
+
+	/*
+	 * Get the fd.
+	 */
+
+	VkMemoryGetFdInfoKHR fd_info = {
+	    .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
+	    .memory = device_memory,
+	    .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR,
+	};
+
+	ret = c->vk.vkGetMemoryFdKHR(c->vk.device, &fd_info, &fd);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(c, "->image - vkGetMemoryFdKHR: %s",
+		           vk_result_string(ret));
+		ret = VK_ERROR_FEATURE_NOT_PRESENT;
+		goto err_mem;
+	}
+
+	*out_image = image;
+	*out_mem = device_memory;
+	out_image_fd->fd = fd;
+	out_image_fd->size = size;
+
+	return ret;
+
+err_mem:
+	c->vk.vkFreeMemory(c->vk.device, device_memory, NULL);
+err_image:
+	c->vk.vkDestroyImage(c->vk.device, image, NULL);
+err:
+	return ret;
+}
+
+struct xrt_swapchain *
+comp_swapchain_create(struct xrt_compositor *xc,
+                      enum xrt_swapchain_create_flags create,
+                      enum xrt_swapchain_usage_bits bits,
+                      int64_t format,
+                      uint32_t sample_count,
+                      uint32_t width,
+                      uint32_t height,
+                      uint32_t face_count,
+                      uint32_t array_size,
+                      uint32_t mip_count)
+{
+	struct comp_compositor *c = comp_compositor(xc);
+	VkCommandBuffer cmd_buffer;
+	uint32_t num_images = 3;
+	VkResult ret;
+
+
+	struct comp_swapchain *sc = calloc(1, sizeof(struct comp_swapchain));
+	sc->base.base.destroy = swapchain_destroy;
+	sc->base.base.acquire_image = swapchain_acquire_image;
+	sc->base.base.wait_image = swapchain_wait_image;
+	sc->base.base.release_image = swapchain_release_image;
+	sc->base.base.num_images = num_images;
+	sc->c = c;
+
+	COMP_DEBUG(c, "CREATE %p %dx%d", (void *)sc, width, height);
+
+	for (uint32_t i = 0; i < num_images; i++) {
+		ret = create_image_fd(
+		    c, format, width, height, mip_count, &sc->images[i].image,
+		    &sc->images[i].memory, &sc->base.images[i]);
+		if (ret != VK_SUCCESS) {
+			return NULL;
+		}
+
+		vk_create_sampler(&c->vk, &sc->images[i].sampler);
+
+		vk_create_view(&c->vk, sc->images[i].image, format,
+		               &sc->images[i].view);
+	}
+
+
+	/*
+	 *
+	 * Transition image.
+	 *
+	 */
+
+	vk_init_cmd_buffer(&c->vk, &cmd_buffer);
+
+	VkImageSubresourceRange subresource_range = {
+	    .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
+	    .baseMipLevel = 0,
+	    .levelCount = 1,
+	    .baseArrayLayer = 0,
+	    .layerCount = 1,
+	};
+
+	for (uint32_t i = 0; i < num_images; i++) {
+		vk_set_image_layout(&c->vk, cmd_buffer, sc->images[i].image, 0,
+		                    VK_ACCESS_SHADER_READ_BIT,
+		                    VK_IMAGE_LAYOUT_UNDEFINED,
+		                    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+		                    subresource_range);
+	}
+
+	vk_submit_cmd_buffer(&c->vk, cmd_buffer);
+
+	return &sc->base.base;
+}
+
+void
+comp_swapchain_image_cleanup(struct vk_bundle *vk,
+                             struct comp_swapchain_image *image)
+{
+	if (image->view != NULL) {
+		vk->vkDestroyImageView(vk->device, image->view, NULL);
+		image->view = NULL;
+	}
+
+	if (image->sampler != NULL) {
+		vk->vkDestroySampler(vk->device, image->sampler, NULL);
+		image->sampler = NULL;
+	}
+
+	if (image->image != NULL) {
+		vk->vkDestroyImage(vk->device, image->image, NULL);
+		image->image = NULL;
+	}
+
+	if (image->memory != NULL) {
+		vk->vkFreeMemory(vk->device, image->memory, NULL);
+		image->memory = NULL;
+	}
+}
diff --git a/src/xrt/compositor/main/comp_window.h b/src/xrt/compositor/main/comp_window.h
new file mode 100644
index 000000000..0afdb2197
--- /dev/null
+++ b/src/xrt/compositor/main/comp_window.h
@@ -0,0 +1,92 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Compositor window header.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#pragma once
+
+#include "common/comp_vk_swapchain.h"
+#include "main/comp_compositor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+/*!
+ * A output device or a window, often directly connected to the device.
+ *
+ * @ingroup comp
+ */
+struct comp_window
+{
+	//! Owning compositor.
+	struct comp_compositor *c;
+
+	//! Name of the window system.
+	const char *name;
+
+	//! Helper struct.
+	struct vk_swapchain swapchain;
+
+	void (*destroy)(struct comp_window *w);
+	void (*flush)(struct comp_window *w);
+	bool (*init)(struct comp_window *w);
+	bool (*init_swapchain)(struct comp_window *w,
+	                       uint32_t width,
+	                       uint32_t height);
+	void (*update_window_title)(struct comp_window *w, const char *title);
+};
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+/*!
+ * Create a xcb window.
+ *
+ * @ingroup comp
+ */
+struct comp_window *
+comp_window_xcb_create(struct comp_compositor *c);
+#endif
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+/*!
+ * Create a wayland window.
+ *
+ * @ingroup comp
+ */
+struct comp_window *
+comp_window_wayland_create(struct comp_compositor *c);
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+/*!
+ * Create a direct surface to a HMD.
+ *
+ * @ingroup comp
+ */
+struct comp_window *
+comp_window_direct_create(struct comp_compositor *c);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/compositor/main/comp_window_direct_mode.cpp b/src/xrt/compositor/main/comp_window_direct_mode.cpp
new file mode 100644
index 000000000..833c27334
--- /dev/null
+++ b/src/xrt/compositor/main/comp_window_direct_mode.cpp
@@ -0,0 +1,648 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Direct mode window code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
+#include <X11/extensions/Xrandr.h>
+
+#include <map>
+#include <string>
+#include <vector>
+#include <utility>
+#include <cstring>
+
+#include "xrt/xrt_compiler.h"
+#include "main/comp_window.h"
+
+
+/*
+ *
+ * Private structs
+ *
+ */
+
+/*!
+ * Probed display.
+ */
+struct comp_window_direct_display
+{
+	std::string name;
+	xcb_randr_output_t output;
+	xcb_randr_mode_info_t primary_mode;
+	VkDisplayKHR display;
+};
+
+/*!
+ * Direct mode "window" into a device, using Vulkan direct mode extension
+ * and xcb.
+ */
+struct comp_window_direct
+{
+	struct comp_window base = comp_window();
+
+	Display* dpy = nullptr;
+	xcb_connection_t* connection = nullptr;
+	xcb_screen_t* screen = nullptr;
+
+	std::map<uint32_t, xcb_randr_mode_info_t> modes = {};
+
+	std::vector<comp_window_direct_display> displays = {};
+};
+
+
+/*
+ *
+ * Pre decalre functions
+ *
+ */
+
+static void
+comp_window_direct_destroy(struct comp_window* w);
+
+XRT_MAYBE_UNUSED static void
+comp_window_direct_list_screens(struct comp_window_direct* w);
+
+static bool
+comp_window_direct_init(struct comp_window* w);
+
+static comp_window_direct_display*
+comp_window_direct_current_display(struct comp_window_direct* w);
+
+static void
+comp_window_direct_flush(struct comp_window* w);
+
+static VkDisplayModeKHR
+comp_window_direct_get_primary_display_mode(struct comp_window_direct* w,
+                                            VkDisplayKHR display);
+
+static VkDisplayPlaneAlphaFlagBitsKHR
+choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags);
+
+static VkResult
+comp_window_direct_create_surface(struct comp_window_direct* w,
+                                  VkInstance instance,
+                                  VkSurfaceKHR* surface,
+                                  uint32_t width,
+                                  uint32_t height);
+
+static bool
+comp_window_direct_init_swapchain(struct comp_window* w,
+                                  uint32_t width,
+                                  uint32_t height);
+
+static int
+comp_window_direct_connect(struct comp_window_direct* w);
+
+static void
+comp_window_direct_aquire_xlib_display(struct comp_window_direct* w,
+                                       VkDisplayKHR display);
+
+static VkDisplayKHR
+comp_window_direct_get_xlib_randr_output(struct comp_window_direct* w,
+                                         RROutput output);
+
+static void
+comp_window_direct_enumerate_modes(
+    struct comp_window_direct* w,
+    xcb_randr_get_screen_resources_reply_t* resources_reply);
+
+static void
+comp_window_direct_get_randr_outputs(struct comp_window_direct* w);
+
+static void
+comp_window_direct_update_window_title(struct comp_window* w,
+                                       const char* title);
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+extern "C" struct comp_window*
+comp_window_direct_create(struct comp_compositor* c)
+{
+	auto w = new comp_window_direct();
+
+	w->base.name = "direct";
+	w->base.destroy = comp_window_direct_destroy;
+	w->base.flush = comp_window_direct_flush;
+	w->base.init = comp_window_direct_init;
+	w->base.init_swapchain = comp_window_direct_init_swapchain;
+	w->base.update_window_title = comp_window_direct_update_window_title;
+	w->base.c = c;
+	w->modes.clear();
+
+	return &w->base;
+}
+
+static void
+comp_window_direct_destroy(struct comp_window* w)
+{
+	comp_window_direct* w_direct = (comp_window_direct*)w;
+	vk_bundle* vk = &w->c->vk;
+
+	for (uint32_t i = 0; i < w_direct->displays.size(); i++) {
+		comp_window_direct_display* d = &w_direct->displays[i];
+
+		if (d->display == VK_NULL_HANDLE) {
+			continue;
+		}
+
+		vk->vkReleaseDisplayEXT(vk->physical_device, d->display);
+		d->display = VK_NULL_HANDLE;
+	}
+
+	if (w_direct->connection) {
+		xcb_disconnect(w_direct->connection);
+		w_direct->connection = nullptr;
+	}
+
+	delete w;
+}
+
+static void
+comp_window_direct_list_screens(struct comp_window_direct* w)
+{
+	int display_i = 0;
+	for (comp_window_direct_display d : w->displays) {
+		COMP_DEBUG(w->base.c, "%d: %s %dx%d@%.2f", display_i,
+		           d.name.c_str(), d.primary_mode.width,
+		           d.primary_mode.height,
+		           (double)d.primary_mode.dot_clock /
+		               (d.primary_mode.htotal * d.primary_mode.vtotal));
+		display_i++;
+	}
+}
+
+static bool
+comp_window_direct_init(struct comp_window* w)
+{
+	comp_window_direct* w_direct = (comp_window_direct*)w;
+
+	if (!comp_window_direct_connect(w_direct)) {
+		return false;
+	}
+
+	xcb_screen_iterator_t iter =
+	    xcb_setup_roots_iterator(xcb_get_setup(w_direct->connection));
+
+	w_direct->screen = iter.data;
+
+	comp_window_direct_get_randr_outputs(w_direct);
+
+	if (w_direct->displays.size() < 1) {
+		COMP_ERROR(w->c, "No non-desktop output available.");
+		return false;
+	}
+
+	if (w->c->settings.display > (int)w_direct->displays.size() - 1) {
+		COMP_DEBUG(w->c,
+		           "Requested display %d, but only %d displays are "
+		           "available.",
+		           w->c->settings.display,
+		           (int)w_direct->displays.size());
+
+		w->c->settings.display = 0;
+		comp_window_direct_display* d =
+		    comp_window_direct_current_display(w_direct);
+		COMP_DEBUG(w->c, "Selecting '%s' instead.", d->name.c_str());
+	}
+
+	if (w->c->settings.display < 0) {
+		w->c->settings.display = 0;
+		comp_window_direct_display* d =
+		    comp_window_direct_current_display(w_direct);
+		COMP_DEBUG(w->c, "Selecting '%s' first display.",
+		           d->name.c_str());
+	}
+
+	comp_window_direct_display* d =
+	    comp_window_direct_current_display(w_direct);
+	w->c->settings.width = d->primary_mode.width;
+	w->c->settings.height = d->primary_mode.height;
+	// TODO: size callback
+	// set_size_cb(settings->width, settings->height);
+
+	return true;
+}
+
+static comp_window_direct_display*
+comp_window_direct_current_display(struct comp_window_direct* w)
+{
+	uint32_t index = w->base.c->settings.display;
+	if (index == (uint32_t)-1) {
+		index = 0;
+	}
+
+	if (w->displays.size() <= index) {
+		return nullptr;
+	}
+
+	return &w->displays[index];
+}
+
+static void
+comp_window_direct_flush(struct comp_window* w)
+{}
+
+static VkDisplayModeKHR
+comp_window_direct_get_primary_display_mode(struct comp_window_direct* w,
+                                            VkDisplayKHR display)
+{
+	struct vk_bundle* vk = w->base.swapchain.vk;
+	uint32_t mode_count;
+	VkResult ret;
+
+	ret = vk->vkGetDisplayModePropertiesKHR(
+	    w->base.swapchain.vk->physical_device, display, &mode_count,
+	    nullptr);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
+		           vk_result_string(ret));
+		return nullptr;
+	}
+
+	COMP_DEBUG(w->base.c, "Found %d modes", mode_count);
+
+	VkDisplayModePropertiesKHR* mode_properties;
+	mode_properties = new VkDisplayModePropertiesKHR[mode_count];
+	ret = vk->vkGetDisplayModePropertiesKHR(
+	    w->base.swapchain.vk->physical_device, display, &mode_count,
+	    mode_properties);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkGetDisplayModePropertiesKHR: %s",
+		           vk_result_string(ret));
+		delete[] mode_properties;
+		return nullptr;
+	}
+
+	VkDisplayModePropertiesKHR props = mode_properties[0];
+
+	COMP_DEBUG(w->base.c, "found display mode %d %d",
+	           props.parameters.visibleRegion.width,
+	           props.parameters.visibleRegion.height);
+
+	delete[] mode_properties;
+
+	return props.displayMode;
+}
+
+static VkDisplayPlaneAlphaFlagBitsKHR
+choose_alpha_mode(VkDisplayPlaneAlphaFlagsKHR flags)
+{
+	if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR) {
+		return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR;
+	} else if (flags & VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR) {
+		return VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR;
+	} else {
+		return VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR;
+	}
+}
+
+static VkResult
+comp_window_direct_create_surface(struct comp_window_direct* w,
+                                  VkInstance instance,
+                                  VkSurfaceKHR* surface,
+                                  uint32_t width,
+                                  uint32_t height)
+{
+	comp_window_direct_display* d = comp_window_direct_current_display(w);
+	struct vk_bundle* vk = w->base.swapchain.vk;
+	VkResult ret;
+
+	COMP_DEBUG(w->base.c, "Will use display: %s %dx%d@%.2f",
+	           d->name.c_str(), d->primary_mode.width,
+	           d->primary_mode.height,
+	           (double)d->primary_mode.dot_clock /
+	               (d->primary_mode.htotal * d->primary_mode.vtotal));
+
+	d->display = comp_window_direct_get_xlib_randr_output(w, d->output);
+	if (d->display == VK_NULL_HANDLE) {
+		return VK_ERROR_INITIALIZATION_FAILED;
+	}
+
+	comp_window_direct_aquire_xlib_display(w, d->display);
+
+
+	// Get plane properties
+	uint32_t plane_property_count;
+	ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
+	    w->base.swapchain.vk->physical_device, &plane_property_count,
+	    nullptr);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c,
+		           "vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+	COMP_DEBUG(w->base.c, "Found %d plane properites.",
+	           plane_property_count);
+
+	VkDisplayPlanePropertiesKHR* plane_properties =
+	    new VkDisplayPlanePropertiesKHR[plane_property_count];
+
+	ret = vk->vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
+	    w->base.swapchain.vk->physical_device, &plane_property_count,
+	    plane_properties);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c,
+		           "vkGetPhysicalDeviceDisplayPlanePropertiesKHR: %s",
+		           vk_result_string(ret));
+		delete[] plane_properties;
+		return ret;
+	}
+
+	uint32_t plane_index = 0;
+
+	VkDisplayModeKHR display_mode =
+	    comp_window_direct_get_primary_display_mode(w, d->display);
+
+	VkDisplayPlaneCapabilitiesKHR plane_caps;
+	vk->vkGetDisplayPlaneCapabilitiesKHR(
+	    w->base.swapchain.vk->physical_device, display_mode, plane_index,
+	    &plane_caps);
+
+	VkDisplaySurfaceCreateInfoKHR surface_info = {
+	    .sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR,
+	    .pNext = nullptr,
+	    .flags = 0,
+	    .displayMode = display_mode,
+	    .planeIndex = plane_index,
+	    .planeStackIndex = plane_properties[plane_index].currentStackIndex,
+	    .transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
+	    .globalAlpha = 1.0,
+	    .alphaMode = choose_alpha_mode(plane_caps.supportedAlpha),
+	    .imageExtent =
+	        {
+	            .width = width,
+	            .height = height,
+	        },
+	};
+
+	VkResult result = vk->vkCreateDisplayPlaneSurfaceKHR(
+	    instance, &surface_info, nullptr, surface);
+
+	delete[] plane_properties;
+
+	return result;
+}
+
+static bool
+comp_window_direct_init_swapchain(struct comp_window* w,
+                                  uint32_t width,
+                                  uint32_t height)
+{
+	comp_window_direct* w_direct = (comp_window_direct*)w;
+	VkResult ret;
+
+
+	ret = comp_window_direct_create_surface(
+	    w_direct, w->swapchain.vk->instance, &w->swapchain.surface, width,
+	    height);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->c, "Failed to create surface!");
+		return false;
+	}
+
+	vk_swapchain_create(
+	    &w->swapchain, width, height, w->c->settings.color_format,
+	    w->c->settings.color_space, w->c->settings.present_mode);
+
+	return true;
+}
+
+static int
+comp_window_direct_connect(struct comp_window_direct* w)
+{
+	w->dpy = XOpenDisplay(nullptr);
+	if (w->dpy == nullptr) {
+		COMP_ERROR(w->base.c, "Could not open X display.");
+		return false;
+	}
+
+	//! @todo only open one connection and use XGetXCBConnection.
+	w->connection = xcb_connect(nullptr, nullptr);
+	return !xcb_connection_has_error(w->connection);
+}
+
+static void
+comp_window_direct_aquire_xlib_display(struct comp_window_direct* w,
+                                       VkDisplayKHR display)
+{
+	struct vk_bundle* vk = w->base.swapchain.vk;
+	VkResult ret;
+
+	ret = vk->vkAcquireXlibDisplayEXT(w->base.swapchain.vk->physical_device,
+	                                  w->dpy, display);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkAcquireXlibDisplayEXT: %s (%p)",
+		           vk_result_string(ret), (void*)display);
+	}
+}
+
+static VkDisplayKHR
+comp_window_direct_get_xlib_randr_output(struct comp_window_direct* w,
+                                         RROutput output)
+{
+	struct vk_bundle* vk = w->base.swapchain.vk;
+	VkResult ret;
+
+	VkDisplayKHR display;
+	ret = vk->vkGetRandROutputDisplayEXT(
+	    w->base.swapchain.vk->physical_device, w->dpy, output, &display);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkGetRandROutputDisplayEXT: %s",
+		           vk_result_string(ret));
+		return nullptr;
+	}
+
+	if (display == VK_NULL_HANDLE) {
+		COMP_DEBUG(w->base.c,
+		           "vkGetRandROutputDisplayEXT"
+		           " returned a null display! %p",
+		           display);
+		return VK_NULL_HANDLE;
+	}
+
+	return display;
+}
+
+static void
+comp_window_direct_enumerate_modes(
+    struct comp_window_direct* w,
+    xcb_randr_get_screen_resources_reply_t* resources_reply)
+{
+	xcb_randr_mode_info_t* mode_infos =
+	    xcb_randr_get_screen_resources_modes(resources_reply);
+
+	int n = xcb_randr_get_screen_resources_modes_length(resources_reply);
+	for (int i = 0; i < n; i++)
+		w->modes.insert(std::pair<uint32_t, xcb_randr_mode_info_t>(
+		    mode_infos[i].id, mode_infos[i]));
+}
+
+static void
+comp_window_direct_get_randr_outputs(struct comp_window_direct* w)
+{
+	xcb_randr_query_version_cookie_t version_cookie =
+	    xcb_randr_query_version(w->connection, XCB_RANDR_MAJOR_VERSION,
+	                            XCB_RANDR_MINOR_VERSION);
+	xcb_randr_query_version_reply_t* version_reply =
+	    xcb_randr_query_version_reply(w->connection, version_cookie, NULL);
+
+	if (!version_reply) {
+		COMP_ERROR(w->base.c, "Could not get RandR version.");
+		return;
+	}
+
+	COMP_DEBUG(w->base.c, "RandR version %d.%d",
+	           version_reply->major_version, version_reply->minor_version);
+
+	if (version_reply->major_version < 1 ||
+	    version_reply->minor_version < 6) {
+		COMP_DEBUG(w->base.c, "RandR version below 1.6.");
+	}
+
+	xcb_generic_error_t* error = nullptr;
+	xcb_intern_atom_cookie_t non_desktop_cookie = xcb_intern_atom(
+	    w->connection, 1, strlen("non-desktop"), "non-desktop");
+	xcb_intern_atom_reply_t* non_desktop_reply =
+	    xcb_intern_atom_reply(w->connection, non_desktop_cookie, &error);
+
+	if (error != nullptr) {
+		COMP_ERROR(w->base.c, "xcb_intern_atom_reply returned error %d",
+		           error->error_code);
+		return;
+	}
+
+	if (non_desktop_reply == nullptr) {
+		COMP_ERROR(w->base.c, "non-desktop reply nullptr");
+		return;
+	}
+
+	if (non_desktop_reply->atom == XCB_NONE) {
+		COMP_ERROR(w->base.c, "No output has non-desktop property");
+		return;
+	}
+
+	xcb_randr_get_screen_resources_cookie_t resources_cookie =
+	    xcb_randr_get_screen_resources(w->connection, w->screen->root);
+	xcb_randr_get_screen_resources_reply_t* resources_reply =
+	    xcb_randr_get_screen_resources_reply(w->connection,
+	                                         resources_cookie, nullptr);
+	xcb_randr_output_t* xcb_outputs =
+	    xcb_randr_get_screen_resources_outputs(resources_reply);
+
+	comp_window_direct_enumerate_modes(w, resources_reply);
+
+	int count =
+	    xcb_randr_get_screen_resources_outputs_length(resources_reply);
+	if (count < 1) {
+		COMP_ERROR(w->base.c, "failed to retrieve randr outputs");
+	}
+
+	for (int i = 0; i < count; i++) {
+		xcb_randr_get_output_info_cookie_t output_cookie =
+		    xcb_randr_get_output_info(w->connection, xcb_outputs[i],
+		                              XCB_CURRENT_TIME);
+		xcb_randr_get_output_info_reply_t* output_reply =
+		    xcb_randr_get_output_info_reply(w->connection,
+		                                    output_cookie, nullptr);
+
+		// Only outputs with an available mode should be used
+		// (it is possible to see 'ghost' outputs with non-desktop=1).
+		if (output_reply->num_modes == 0) {
+			continue;
+		}
+
+		uint8_t* name = xcb_randr_get_output_info_name(output_reply);
+		int name_len =
+		    xcb_randr_get_output_info_name_length(output_reply);
+
+		char* name_str = (char*)malloc(name_len + 1);
+		memcpy(name_str, name, name_len);
+		name_str[name_len] = '\0';
+
+		// Find the first output that has the non-desktop property set.
+		xcb_randr_get_output_property_cookie_t prop_cookie;
+		prop_cookie = xcb_randr_get_output_property(
+		    w->connection, xcb_outputs[i], non_desktop_reply->atom,
+		    XCB_ATOM_NONE, 0, 4, 0, 0);
+		xcb_randr_get_output_property_reply_t* prop_reply = nullptr;
+		prop_reply = xcb_randr_get_output_property_reply(
+		    w->connection, prop_cookie, &error);
+		if (error != nullptr) {
+			COMP_ERROR(w->base.c,
+			           "xcb_randr_get_output_property_reply "
+			           "returned error %d",
+			           error->error_code);
+			free(name_str);
+			continue;
+		}
+
+		if (prop_reply == nullptr) {
+			COMP_ERROR(w->base.c, "property reply == nullptr");
+			free(name_str);
+			continue;
+		}
+
+		if (prop_reply->type != XCB_ATOM_INTEGER ||
+		    prop_reply->num_items != 1 || prop_reply->format != 32) {
+			COMP_ERROR(w->base.c, "Invalid non-desktop reply");
+			free(name_str);
+			continue;
+		}
+
+		uint8_t non_desktop =
+		    *xcb_randr_get_output_property_data(prop_reply);
+		if (non_desktop == 1) {
+			xcb_randr_mode_t* output_modes =
+			    xcb_randr_get_output_info_modes(output_reply);
+
+			int num_modes = xcb_randr_get_output_info_modes_length(
+			    output_reply);
+			if (num_modes == 0) {
+				COMP_ERROR(w->base.c,
+				           "%s does not have any modes "
+				           "available. "
+				           "Check `xrandr --prop`.",
+				           name_str);
+			}
+
+			if (!w->modes.count(output_modes[0])) {
+				COMP_ERROR(w->base.c,
+				           "No mode with id %d found??",
+				           output_modes[0]);
+			}
+
+			comp_window_direct_display d = {
+			    .name = std::string(name_str),
+			    .output = xcb_outputs[i],
+			    .primary_mode = w->modes.at(output_modes[0]),
+			    .display = VK_NULL_HANDLE,
+			};
+
+			w->displays.push_back(d);
+		}
+
+		free(name_str);
+	}
+}
+
+static void
+comp_window_direct_update_window_title(struct comp_window* w, const char* title)
+{}
+
+#endif
diff --git a/src/xrt/compositor/main/comp_window_wayland.cpp b/src/xrt/compositor/main/comp_window_wayland.cpp
new file mode 100644
index 000000000..6c4e3b4d1
--- /dev/null
+++ b/src/xrt/compositor/main/comp_window_wayland.cpp
@@ -0,0 +1,629 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Wayland window code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#ifdef VK_USE_PLATFORM_WAYLAND_KHR
+
+#include <poll.h>
+#include <linux/input.h>
+#include <wayland-client.h>
+#include "xdg-shell-unstable-v6.h"
+
+#include <map>
+#include <vector>
+#include <string>
+#include <utility>
+#include <cstring>
+
+#include "xrt/xrt_compiler.h"
+#include "main/comp_window.h"
+
+
+/*
+ *
+ * Private structs.
+ *
+ */
+
+/*!
+ * Wayland display mode.
+ */
+struct comp_window_wayland_mode
+{
+	std::pair<int, int> size;
+	int refresh;
+};
+
+/*!
+ * A single Wayland display.
+ */
+struct comp_window_wayland_display
+{
+	wl_output *output;
+	std::string make;
+	std::string model;
+	std::vector<comp_window_wayland_mode> modes;
+	std::pair<int, int> physical_size_mm;
+	std::pair<int, int> position;
+};
+
+/*!
+ * A Wayland connection and window.
+ */
+struct comp_window_wayland
+{
+	struct comp_window base = comp_window();
+
+	wl_display *display = nullptr;
+	wl_compositor *compositor = nullptr;
+	wl_surface *surface = nullptr;
+
+	zxdg_shell_v6 *shell = nullptr;
+	zxdg_surface_v6 *xdg_surface = nullptr;
+	zxdg_toplevel_v6 *xdg_toplevel = nullptr;
+
+	std::vector<comp_window_wayland_display> displays = {};
+
+	bool is_configured = false;
+	bool first_configure = true;
+	bool fullscreen_requested = false;
+};
+
+
+/*
+ *
+ * Pre declare functions.
+ *
+ */
+
+static void
+comp_window_wayland_destroy(struct comp_window *w);
+
+static bool
+comp_window_wayland_init(struct comp_window *w);
+
+static void
+comp_window_wayland_update_window_title(struct comp_window *w,
+                                        const char *title);
+
+static void
+comp_window_wayland_registry_global(struct comp_window_wayland *w,
+                                    wl_registry *registry,
+                                    uint32_t name,
+                                    const char *interface);
+
+static void
+comp_window_wayland_fullscreen(struct comp_window_wayland *w);
+
+static void
+comp_window_wayland_fullscreen(struct comp_window_wayland *w,
+                               wl_output *output);
+
+static bool
+comp_window_wayland_init_swapchain(struct comp_window *w,
+                                   uint32_t width,
+                                   uint32_t height);
+
+static VkResult
+comp_window_wayland_create_surface(struct comp_window_wayland *w,
+                                   VkSurfaceKHR *vk_surface);
+
+static void
+comp_window_wayland_flush(struct comp_window *w);
+
+static void
+comp_window_wayland_output_mode(struct comp_window_wayland *w,
+                                wl_output *output,
+                                unsigned int flags,
+                                int width,
+                                int height,
+                                int refresh);
+
+static comp_window_wayland_display *
+comp_window_wayland_get_display_from_output(struct comp_window_wayland *w,
+                                            wl_output *output);
+
+XRT_MAYBE_UNUSED static void
+comp_window_wayland_print_displays(struct comp_window_wayland *w);
+
+static comp_window_wayland_display *
+comp_window_wayland_current_display(struct comp_window_wayland *w);
+
+static comp_window_wayland_mode *
+comp_window_wayland_current_mode(struct comp_window_wayland *w);
+
+static std::string
+mode_to_string(comp_window_wayland_mode *m);
+
+static void
+comp_window_wayland_validate_display(struct comp_window_wayland *w);
+
+static void
+validate_mode(struct comp_window_wayland *w);
+
+static void
+comp_window_wayland_configure(struct comp_window_wayland *w,
+                              int32_t width,
+                              int32_t height);
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+extern "C" struct comp_window *
+comp_window_wayland_create(struct comp_compositor *c)
+{
+	auto w = new comp_window_wayland();
+
+	w->base.name = "wayland";
+	w->base.destroy = comp_window_wayland_destroy;
+	w->base.flush = comp_window_wayland_flush;
+	w->base.init = comp_window_wayland_init;
+	w->base.init_swapchain = comp_window_wayland_init_swapchain;
+	w->base.update_window_title = comp_window_wayland_update_window_title;
+	w->base.c = c;
+
+	return &w->base;
+}
+
+static void
+comp_window_wayland_destroy(struct comp_window *w)
+{
+	struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
+
+	if (w_wayland->surface) {
+		wl_surface_destroy(w_wayland->surface);
+		w_wayland->surface = nullptr;
+	}
+	if (w_wayland->compositor) {
+		wl_compositor_destroy(w_wayland->compositor);
+		w_wayland->compositor = nullptr;
+	}
+	if (w_wayland->display) {
+		wl_display_disconnect(w_wayland->display);
+		w_wayland->display = nullptr;
+	}
+
+	delete w;
+}
+
+static void
+comp_window_wayland_update_window_title(struct comp_window *w,
+                                        const char *title)
+{
+	struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
+	zxdg_toplevel_v6_set_title(w_wayland->xdg_toplevel, title);
+}
+
+static void
+comp_window_wayland_fullscreen(struct comp_window_wayland *w)
+{
+	comp_window_wayland_fullscreen(
+	    w, comp_window_wayland_current_display(w)->output);
+}
+
+static void
+comp_window_wayland_fullscreen(struct comp_window_wayland *w, wl_output *output)
+{
+	zxdg_toplevel_v6_set_fullscreen(w->xdg_toplevel, output);
+	wl_surface_commit(w->surface);
+}
+
+static void
+_xdg_surface_configure_cb(void *data, zxdg_surface_v6 *surface, uint32_t serial)
+{
+	zxdg_surface_v6_ack_configure(surface, serial);
+}
+
+static void
+_xdg_toplevel_configure_cb(void *data,
+                           zxdg_toplevel_v6 *toplevel,
+                           int32_t width,
+                           int32_t height,
+                           struct wl_array *states)
+{
+	comp_window_wayland *w = (comp_window_wayland *)data;
+	comp_window_wayland_configure(w, width, height);
+}
+
+static const zxdg_surface_v6_listener xdg_surface_listener = {
+    _xdg_surface_configure_cb,
+};
+
+static void
+_xdg_toplevel_close_cb(void *data, zxdg_toplevel_v6 *toplevel)
+{}
+
+static const zxdg_toplevel_v6_listener xdg_toplevel_listener = {
+    _xdg_toplevel_configure_cb,
+    _xdg_toplevel_close_cb,
+};
+
+static void
+_xdg_shell_ping_cb(void *data, zxdg_shell_v6 *shell, uint32_t serial)
+{
+	zxdg_shell_v6_pong(shell, serial);
+}
+
+const zxdg_shell_v6_listener xdg_shell_listener = {
+    _xdg_shell_ping_cb,
+};
+
+static bool
+comp_window_wayland_init_swapchain(struct comp_window *w,
+                                   uint32_t width,
+                                   uint32_t height)
+{
+	struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
+	VkResult ret;
+
+	ret = comp_window_wayland_create_surface(w_wayland,
+	                                         &w->swapchain.surface);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->c, "Failed to create surface!");
+		return false;
+	}
+
+	vk_swapchain_create(
+	    &w->swapchain, width, height, w->c->settings.color_format,
+	    w->c->settings.color_space, w->c->settings.present_mode);
+
+	return true;
+}
+
+static VkResult
+comp_window_wayland_create_surface(struct comp_window_wayland *w,
+                                   VkSurfaceKHR *vk_surface)
+{
+	struct vk_bundle *vk = w->base.swapchain.vk;
+	VkResult ret;
+
+	VkWaylandSurfaceCreateInfoKHR surface_info = {
+	    .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
+	    .pNext = nullptr,
+	    .flags = 0,
+	    .display = w->display,
+	    .surface = w->surface,
+	};
+
+	ret = vk->vkCreateWaylandSurfaceKHR(vk->instance, &surface_info, NULL,
+	                                    vk_surface);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkCreateWaylandSurfaceKHR: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+	return VK_SUCCESS;
+}
+
+static void
+comp_window_wayland_flush(struct comp_window *w)
+{
+	struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
+
+	while (wl_display_prepare_read(w_wayland->display) != 0)
+		wl_display_dispatch_pending(w_wayland->display);
+	if (wl_display_flush(w_wayland->display) < 0 && errno != EAGAIN) {
+		wl_display_cancel_read(w_wayland->display);
+		return;
+	}
+
+	struct pollfd fds[] = {
+	    {
+	        .fd = wl_display_get_fd(w_wayland->display),
+	        .events = POLLIN,
+	        .revents = 0,
+	    },
+	};
+
+	if (poll(fds, 1, 0) > 0) {
+		wl_display_read_events(w_wayland->display);
+		wl_display_dispatch_pending(w_wayland->display);
+	} else {
+		wl_display_cancel_read(w_wayland->display);
+	}
+}
+
+static void
+comp_window_wayland_output_mode(struct comp_window_wayland *w,
+                                wl_output *output,
+                                unsigned int flags,
+                                int width,
+                                int height,
+                                int refresh)
+{
+	comp_window_wayland_mode m = {};
+	m.size = {width, height};
+	m.refresh = refresh;
+
+	comp_window_wayland_display *d =
+	    comp_window_wayland_get_display_from_output(w, output);
+	if (d == nullptr) {
+		COMP_ERROR(w->base.c, "Output mode callback before geomentry!");
+		return;
+	}
+
+	d->modes.push_back(m);
+}
+
+static void
+_output_done_cb(void *data, wl_output *output)
+{}
+
+static void
+_output_scale_cb(void *data, wl_output *output, int scale)
+{}
+
+static void
+_registry_global_remove_cb(void *data, wl_registry *registry, uint32_t name)
+{}
+
+static void
+_registry_global_cb(void *data,
+                    wl_registry *registry,
+                    uint32_t name,
+                    const char *interface,
+                    uint32_t version)
+{
+	comp_window_wayland *w = (comp_window_wayland *)data;
+	// vik_log_d("Interface: %s Version %d", interface, version);
+	comp_window_wayland_registry_global(w, registry, name, interface);
+}
+
+static void
+_output_mode_cb(void *data,
+                wl_output *output,
+                unsigned int flags,
+                int width,
+                int height,
+                int refresh)
+{
+	comp_window_wayland *w = (comp_window_wayland *)data;
+	comp_window_wayland_output_mode(w, output, flags, width, height,
+	                                refresh);
+}
+
+static void
+_output_geometry_cb(void *data,
+                    wl_output *output,
+                    int x,
+                    int y,
+                    int w,
+                    int h,
+                    int subpixel,
+                    const char *make,
+                    const char *model,
+                    int transform)
+{
+	comp_window_wayland_display d = {};
+	d.output = output;
+	d.make = std::string(make);
+	d.model = std::string(model);
+	d.physical_size_mm = {w, h};
+	d.position = {x, y};
+
+	comp_window_wayland *self = (comp_window_wayland *)data;
+	self->displays.push_back(d);
+}
+
+// listeners
+static const wl_registry_listener registry_listener = {
+    _registry_global_cb,
+    _registry_global_remove_cb,
+};
+
+static const wl_output_listener output_listener = {
+    _output_geometry_cb,
+    _output_mode_cb,
+    _output_done_cb,
+    _output_scale_cb,
+};
+
+static void
+comp_window_wayland_registry_global(struct comp_window_wayland *w,
+                                    wl_registry *registry,
+                                    uint32_t name,
+                                    const char *interface)
+{
+	if (strcmp(interface, "wl_compositor") == 0) {
+		w->compositor = (wl_compositor *)wl_registry_bind(
+		    registry, name, &wl_compositor_interface, 4);
+	} else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+		w->shell = (zxdg_shell_v6 *)wl_registry_bind(
+		    registry, name, &zxdg_shell_v6_interface, 1);
+		zxdg_shell_v6_add_listener(w->shell, &xdg_shell_listener, w);
+	} else if (strcmp(interface, "wl_output") == 0) {
+		wl_output *_output = (wl_output *)wl_registry_bind(
+		    registry, name, &wl_output_interface, 2);
+		wl_output_add_listener(_output, &output_listener, w);
+	}
+}
+
+static bool
+comp_window_wayland_init(struct comp_window *w)
+{
+	struct comp_window_wayland *w_wayland = (struct comp_window_wayland *)w;
+
+	w_wayland->display = wl_display_connect(NULL);
+	if (!w_wayland->display) {
+		return false;
+	}
+
+	wl_registry *registry = wl_display_get_registry(w_wayland->display);
+	wl_registry_add_listener(registry, &registry_listener, w_wayland);
+
+	wl_display_roundtrip(w_wayland->display);
+
+	wl_registry_destroy(registry);
+
+	w_wayland->surface =
+	    wl_compositor_create_surface(w_wayland->compositor);
+
+	if (!w_wayland->shell) {
+		COMP_ERROR(
+		    w->c,
+		    "Compositor is missing unstable zxdg_shell_v6 support");
+	}
+
+	w_wayland->xdg_surface =
+	    zxdg_shell_v6_get_xdg_surface(w_wayland->shell, w_wayland->surface);
+
+	zxdg_surface_v6_add_listener(w_wayland->xdg_surface,
+	                             &xdg_surface_listener, w_wayland);
+
+	w_wayland->xdg_toplevel =
+	    zxdg_surface_v6_get_toplevel(w_wayland->xdg_surface);
+
+	zxdg_toplevel_v6_add_listener(w_wayland->xdg_toplevel,
+	                              &xdg_toplevel_listener, w_wayland);
+
+	wl_surface_commit(w_wayland->surface);
+
+	return true;
+}
+
+static comp_window_wayland_display *
+comp_window_wayland_get_display_from_output(struct comp_window_wayland *w,
+                                            wl_output *output)
+{
+	for (int i = 0; i < (int)w->displays.size(); i++) {
+		if (w->displays[i].output == output)
+			return &w->displays[i];
+	}
+	return nullptr;
+}
+
+XRT_MAYBE_UNUSED static void
+comp_window_wayland_print_displays(struct comp_window_wayland *w)
+{
+	int i_d = 0;
+	COMP_DEBUG(w->base.c, "Available displays:");
+	for (auto d : w->displays) {
+		COMP_DEBUG(w->base.c, "%d: %s %s [%d, %d] %dx%dmm (%d Modes)",
+		           i_d, d.make.c_str(), d.model.c_str(),
+		           d.position.first, d.position.second,
+		           d.physical_size_mm.first, d.physical_size_mm.second,
+		           (int)d.modes.size());
+
+		int i_m = 0;
+		for (auto m : d.modes) {
+			COMP_DEBUG(w->base.c, "\t%d: %s", i_m,
+			           mode_to_string(&m).c_str());
+			i_m++;
+		}
+		i_d++;
+	}
+}
+
+static comp_window_wayland_display *
+comp_window_wayland_current_display(struct comp_window_wayland *w)
+{
+	return &w->displays[w->base.c->settings.display];
+}
+
+static comp_window_wayland_mode *
+comp_window_wayland_current_mode(struct comp_window_wayland *w)
+{
+	return &comp_window_wayland_current_display(w)
+	            ->modes[w->base.c->settings.mode];
+}
+
+static std::string
+mode_to_string(comp_window_wayland_mode *m)
+{
+	auto size = std::snprintf(nullptr, 0, "%d x %d @ %.2fHz", m->size.first,
+	                          m->size.second, (float)m->refresh / 1000.0);
+	std::string output(size + 1, '\0');
+	std::snprintf(&output[0], size, "%d x %d @ %.2fHz", m->size.first,
+	              m->size.second, (float)m->refresh / 1000.0);
+	return std::string(output);
+}
+
+static void
+comp_window_wayland_validate_display(struct comp_window_wayland *w)
+{
+	comp_window_wayland_display *d;
+
+	if (w->base.c->settings.display < 0)
+		w->base.c->settings.display = 0;
+
+	if (w->base.c->settings.display > (int)w->displays.size()) {
+		COMP_DEBUG(w->base.c,
+		           "Requested display %d, but only %d displays are "
+		           "available.",
+		           w->base.c->settings.display,
+		           (int)w->displays.size());
+
+		w->base.c->settings.display = 0;
+		d = comp_window_wayland_current_display(w);
+		COMP_DEBUG(w->base.c, "Selecting '%s %s' instead.",
+		           d->make.c_str(), d->model.c_str());
+	}
+}
+
+static void
+validate_mode(struct comp_window_wayland *w)
+{
+	comp_window_wayland_display *d = comp_window_wayland_current_display(w);
+
+	if (w->base.c->settings.mode < 0)
+		w->base.c->settings.mode = 0;
+
+	if (w->base.c->settings.mode > (int)d->modes.size()) {
+		COMP_DEBUG(w->base.c,
+		           "Requested mode %d, but only %d modes"
+		           " are available on display %d.",
+		           w->base.c->settings.mode, (int)d->modes.size(),
+		           w->base.c->settings.display);
+		w->base.c->settings.mode = 0;
+		COMP_DEBUG(w->base.c, "Selecting '%s' instead",
+		           mode_to_string(comp_window_wayland_current_mode(w))
+		               .c_str());
+	}
+}
+
+static void
+comp_window_wayland_configure(struct comp_window_wayland *w,
+                              int32_t width,
+                              int32_t height)
+{
+	if (w->first_configure) {
+		comp_window_wayland_validate_display(w);
+		validate_mode(w);
+		w->first_configure = false;
+	}
+
+	comp_window_wayland_mode *m = comp_window_wayland_current_mode(w);
+	if (w->fullscreen_requested &&
+	    (m->size.first != width || m->size.second != height)) {
+		COMP_DEBUG(w->base.c,
+		           "Received mode %dx%d does not match requested Mode "
+		           "%dx%d. "
+		           "Compositor bug? Requesting again.",
+		           width, height, m->size.first, m->size.second);
+		w->fullscreen_requested = false;
+	}
+
+	m = comp_window_wayland_current_mode(w);
+	if (w->base.c->settings.fullscreen && !w->fullscreen_requested) {
+		COMP_DEBUG(
+		    w->base.c, "Setting full screen on Display %d Mode %s",
+		    w->base.c->settings.display, mode_to_string(m).c_str());
+		comp_window_wayland_fullscreen(w);
+		w->fullscreen_requested = true;
+		// TODO: resize cb
+		// resize_cb(m->size.first, m->size.second);
+	}
+}
+
+#endif
diff --git a/src/xrt/compositor/main/comp_window_xcb.cpp b/src/xrt/compositor/main/comp_window_xcb.cpp
new file mode 100644
index 000000000..c80bed3c6
--- /dev/null
+++ b/src/xrt/compositor/main/comp_window_xcb.cpp
@@ -0,0 +1,408 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  XCB window code.
+ * @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup comp
+ */
+
+#ifdef VK_USE_PLATFORM_XCB_KHR
+
+#include <xcb/xcb.h>
+#include <xcb/randr.h>
+
+#include <string>
+#include <vector>
+#include <utility>
+#include <cstring>
+
+#include "xrt/xrt_compiler.h"
+#include "main/comp_window.h"
+
+
+/*
+ *
+ * Private structs.
+ *
+ */
+
+/*!
+ * Xcb display, xrandr output.
+ */
+struct comp_window_xcb_display
+{
+	std::string name;
+	std::pair<int16_t, int16_t> position;
+	std::pair<uint16_t, uint16_t> size;
+};
+
+/*!
+ * A xcb connection and window.
+ */
+struct comp_window_xcb
+{
+	struct comp_window base = comp_window();
+
+	xcb_connection_t* connection = nullptr;
+	xcb_window_t window = XCB_NONE;
+	xcb_screen_t* screen = nullptr;
+
+	xcb_atom_t atom_wm_protocols = XCB_NONE;
+	xcb_atom_t atom_wm_delete_window = XCB_NONE;
+
+	std::vector<comp_window_xcb_display> displays = {};
+};
+
+
+/*
+ *
+ * Pre declare functions.
+ *
+ */
+
+static void
+comp_window_xcb_destroy(struct comp_window* w);
+
+static void
+comp_window_xcb_flush(struct comp_window* w);
+
+XRT_MAYBE_UNUSED static void
+comp_window_xcb_list_screens(comp_window_xcb* w, xcb_screen_t* screen);
+
+static bool
+comp_window_xcb_init(struct comp_window* w);
+
+static comp_window_xcb_display*
+comp_window_xcb_current_display(comp_window_xcb* w);
+
+static bool
+comp_window_xcb_init_swapchain(struct comp_window* w,
+                               uint32_t width,
+                               uint32_t height);
+
+static int
+comp_window_xcb_connect(comp_window_xcb* w);
+
+static void
+comp_window_xcb_create_window(comp_window_xcb* w,
+                              uint32_t width,
+                              uint32_t height);
+
+static void
+comp_window_xcb_get_randr_outputs(comp_window_xcb* w);
+
+static void
+comp_window_xcb_connect_delete_event(comp_window_xcb* w);
+
+static void
+comp_window_xcb_set_full_screen(comp_window_xcb* w);
+
+static xcb_atom_t
+comp_window_xcb_get_atom(comp_window_xcb* w, const char* name);
+
+static VkResult
+comp_window_xcb_create_surface(comp_window_xcb* w, VkSurfaceKHR* surface);
+
+static void
+comp_window_xcb_update_window_title(struct comp_window* w, const char* title);
+
+
+/*
+ *
+ * Functions.
+ *
+ */
+
+extern "C" struct comp_window*
+comp_window_xcb_create(struct comp_compositor* c)
+{
+	auto w = new comp_window_xcb();
+
+	w->base.name = "xcb";
+	w->base.destroy = comp_window_xcb_destroy;
+	w->base.flush = comp_window_xcb_flush;
+	w->base.init = comp_window_xcb_init;
+	w->base.init_swapchain = comp_window_xcb_init_swapchain;
+	w->base.update_window_title = comp_window_xcb_update_window_title;
+	w->base.c = c;
+
+	return &w->base;
+}
+
+static void
+comp_window_xcb_destroy(struct comp_window* w)
+{
+	comp_window_xcb* w_xcb = (comp_window_xcb*)w;
+	xcb_destroy_window(w_xcb->connection, w_xcb->window);
+	xcb_disconnect(w_xcb->connection);
+
+	delete w;
+}
+
+static void
+comp_window_xcb_list_screens(comp_window_xcb* w, xcb_screen_t* screen)
+{
+	COMP_DEBUG(w->base.c, "Screen 0 %dx%d", screen->width_in_pixels,
+	           screen->height_in_pixels);
+	comp_window_xcb_get_randr_outputs(w);
+
+	int display_i = 0;
+	for (comp_window_xcb_display d : w->displays) {
+		COMP_DEBUG(w->base.c, "%d: %s %dx%d [%d, %d]", display_i,
+		           d.name.c_str(), d.size.first, d.size.second,
+		           d.position.first, d.position.second);
+		display_i++;
+	}
+}
+
+static bool
+comp_window_xcb_init(struct comp_window* w)
+{
+	struct comp_window_xcb* w_xcb = (struct comp_window_xcb*)w;
+
+	if (!comp_window_xcb_connect(w_xcb)) {
+		return false;
+	}
+
+	xcb_screen_iterator_t iter =
+	    xcb_setup_roots_iterator(xcb_get_setup(w_xcb->connection));
+
+	w_xcb->screen = iter.data;
+
+	if (w->c->settings.fullscreen) {
+		comp_window_xcb_get_randr_outputs(w_xcb);
+
+		if (w->c->settings.display > (int)w_xcb->displays.size() - 1) {
+			COMP_DEBUG(w->c,
+			           "Requested display %d, but only %d "
+			           "displays are available.",
+			           w->c->settings.display,
+			           (int)w_xcb->displays.size());
+
+			w->c->settings.display = 0;
+			comp_window_xcb_display* d =
+			    comp_window_xcb_current_display(w_xcb);
+			COMP_DEBUG(w->c, "Selecting '%s' instead.",
+			           d->name.c_str());
+		}
+
+		if (w->c->settings.display == -1)
+			w->c->settings.display = 0;
+
+		comp_window_xcb_display* d =
+		    comp_window_xcb_current_display(w_xcb);
+		w->c->settings.width = d->size.first;
+		w->c->settings.height = d->size.second;
+		// TODO: size cb
+		// set_size_cb(settings->width, settings->height);
+	}
+
+	comp_window_xcb_create_window(w_xcb, w->c->settings.width,
+	                              w->c->settings.height);
+
+	comp_window_xcb_connect_delete_event(w_xcb);
+
+	if (w->c->settings.fullscreen)
+		comp_window_xcb_set_full_screen(w_xcb);
+
+	xcb_map_window(w_xcb->connection, w_xcb->window);
+
+	return true;
+}
+
+static comp_window_xcb_display*
+comp_window_xcb_current_display(comp_window_xcb* w)
+{
+	return &w->displays[w->base.c->settings.display];
+}
+
+static void
+comp_window_xcb_flush(struct comp_window* w)
+{}
+
+static bool
+comp_window_xcb_init_swapchain(struct comp_window* w,
+                               uint32_t width,
+                               uint32_t height)
+{
+	comp_window_xcb* w_xcb = (comp_window_xcb*)w;
+	VkResult ret;
+
+	ret = comp_window_xcb_create_surface(w_xcb, &w->swapchain.surface);
+	if (ret != VK_SUCCESS) {
+		return false;
+	}
+
+	// vk_swapchain_set_dimension_cb(&swapchain, set_size_cb);
+	// vk_swapchain_set_settings(&w->swapchain, w->settings);
+	vk_swapchain_create(
+	    &w->swapchain, width, height, w->c->settings.color_format,
+	    w->c->settings.color_space, w->c->settings.present_mode);
+
+	return true;
+}
+
+static int
+comp_window_xcb_connect(comp_window_xcb* w)
+{
+	w->connection = xcb_connect(nullptr, nullptr);
+	return !xcb_connection_has_error(w->connection);
+}
+
+static void
+comp_window_xcb_create_window(comp_window_xcb* w,
+                              uint32_t width,
+                              uint32_t height)
+{
+	w->window = xcb_generate_id(w->connection);
+
+	int x = 0;
+	int y = 0;
+
+	if (w->base.c->settings.fullscreen) {
+		x = comp_window_xcb_current_display(w)->position.first;
+		y = comp_window_xcb_current_display(w)->position.second;
+	}
+
+	uint32_t value_list = XCB_EVENT_MASK_STRUCTURE_NOTIFY;
+
+	xcb_create_window(w->connection, XCB_COPY_FROM_PARENT, w->window,
+	                  w->screen->root, x, y, width, height, 0,
+	                  XCB_WINDOW_CLASS_INPUT_OUTPUT, w->screen->root_visual,
+	                  XCB_CW_EVENT_MASK, &value_list);
+}
+
+static void
+comp_window_xcb_get_randr_outputs(comp_window_xcb* w)
+{
+	xcb_randr_get_screen_resources_cookie_t resources_cookie =
+	    xcb_randr_get_screen_resources(w->connection, w->screen->root);
+	xcb_randr_get_screen_resources_reply_t* resources_reply =
+	    xcb_randr_get_screen_resources_reply(w->connection,
+	                                         resources_cookie, nullptr);
+	xcb_randr_output_t* xcb_outputs =
+	    xcb_randr_get_screen_resources_outputs(resources_reply);
+
+	int count =
+	    xcb_randr_get_screen_resources_outputs_length(resources_reply);
+	if (count < 1) {
+		COMP_ERROR(w->base.c, "Failed to retrieve randr outputs");
+	}
+
+	for (int i = 0; i < count; i++) {
+		xcb_randr_get_output_info_cookie_t output_cookie =
+		    xcb_randr_get_output_info(w->connection, xcb_outputs[i],
+		                              XCB_CURRENT_TIME);
+		xcb_randr_get_output_info_reply_t* output_reply =
+		    xcb_randr_get_output_info_reply(w->connection,
+		                                    output_cookie, nullptr);
+
+		if (output_reply->connection !=
+		        XCB_RANDR_CONNECTION_CONNECTED ||
+		    output_reply->crtc == XCB_NONE) {
+			continue;
+		}
+
+		xcb_randr_get_crtc_info_cookie_t crtc_cookie =
+		    xcb_randr_get_crtc_info(w->connection, output_reply->crtc,
+		                            XCB_CURRENT_TIME);
+		xcb_randr_get_crtc_info_reply_t* crtc_reply =
+		    xcb_randr_get_crtc_info_reply(w->connection, crtc_cookie,
+		                                  nullptr);
+
+		uint8_t* name = xcb_randr_get_output_info_name(output_reply);
+		int name_len =
+		    xcb_randr_get_output_info_name_length(output_reply);
+
+		char* name_str = (char*)malloc(name_len + 1);
+		memcpy(name_str, name, name_len);
+		name_str[name_len] = '\0';
+
+		struct comp_window_xcb_display d = {};
+		d.name = std::string(name_str);
+		d.position = {crtc_reply->x, crtc_reply->y};
+		d.size = {crtc_reply->width, crtc_reply->height};
+		w->displays.push_back(d);
+
+		free(name_str);
+	}
+}
+
+static void
+comp_window_xcb_connect_delete_event(comp_window_xcb* w)
+{
+	w->atom_wm_protocols = comp_window_xcb_get_atom(w, "WM_PROTOCOLS");
+	w->atom_wm_delete_window =
+	    comp_window_xcb_get_atom(w, "WM_DELETE_WINDOW");
+	xcb_change_property(w->connection, XCB_PROP_MODE_REPLACE, w->window,
+	                    w->atom_wm_protocols, XCB_ATOM_ATOM, 32, 1,
+	                    &w->atom_wm_delete_window);
+}
+
+static void
+comp_window_xcb_set_full_screen(comp_window_xcb* w)
+{
+	xcb_atom_t atom_wm_state = comp_window_xcb_get_atom(w, "_NET_WM_STATE");
+	xcb_atom_t atom_wm_fullscreen =
+	    comp_window_xcb_get_atom(w, "_NET_WM_STATE_FULLSCREEN");
+	xcb_change_property(w->connection, XCB_PROP_MODE_REPLACE, w->window,
+	                    atom_wm_state, XCB_ATOM_ATOM, 32, 1,
+	                    &atom_wm_fullscreen);
+}
+
+static xcb_atom_t
+comp_window_xcb_get_atom(comp_window_xcb* w, const char* name)
+{
+	xcb_intern_atom_cookie_t cookie;
+	xcb_intern_atom_reply_t* reply;
+	xcb_atom_t atom;
+
+	cookie = xcb_intern_atom(w->connection, 0, strlen(name), name);
+	reply = xcb_intern_atom_reply(w->connection, cookie, NULL);
+	if (reply) {
+		atom = reply->atom;
+	} else {
+		atom = XCB_NONE;
+	}
+
+	free(reply);
+	return atom;
+}
+
+static VkResult
+comp_window_xcb_create_surface(comp_window_xcb* w, VkSurfaceKHR* surface)
+{
+	struct vk_bundle* vk = w->base.swapchain.vk;
+	VkResult ret;
+
+	VkXcbSurfaceCreateInfoKHR surface_info = {
+	    .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
+	    .pNext = nullptr,
+	    .flags = 0,
+	    .connection = w->connection,
+	    .window = w->window,
+	};
+
+	ret = vk->vkCreateXcbSurfaceKHR(vk->instance, &surface_info, NULL,
+	                                surface);
+	if (ret != VK_SUCCESS) {
+		COMP_ERROR(w->base.c, "vkCreateXcbSurfaceKHR: %s",
+		           vk_result_string(ret));
+		return ret;
+	}
+
+	return VK_SUCCESS;
+}
+
+static void
+comp_window_xcb_update_window_title(struct comp_window* w, const char* title)
+{
+	comp_window_xcb* w_xcb = (comp_window_xcb*)w;
+	xcb_change_property(w_xcb->connection, XCB_PROP_MODE_REPLACE,
+	                    w_xcb->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
+	                    strlen(title), title);
+}
+
+#endif
diff --git a/src/xrt/compositor/shaders/CMakeLists.txt b/src/xrt/compositor/shaders/CMakeLists.txt
new file mode 100644
index 000000000..814a73aef
--- /dev/null
+++ b/src/xrt/compositor/shaders/CMakeLists.txt
@@ -0,0 +1,5 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+# CMakeLists.txt required for CMake to create the shaders/ directory in the build tree.
+# Generated shaders will be placed there.
diff --git a/src/xrt/compositor/shaders/distortion.vert b/src/xrt/compositor/shaders/distortion.vert
new file mode 100644
index 000000000..81b07fa82
--- /dev/null
+++ b/src/xrt/compositor/shaders/distortion.vert
@@ -0,0 +1,34 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+// Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+#version 450
+
+layout (location = 0) out vec2 outUV;
+layout (location = 1) out int  outViewIndex;
+
+layout (binding = 2, std140) uniform UBO
+{
+	vec4 rot;
+	int viewport_id;
+	bool flip_y;
+} ubo_vp;
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+
+void main()
+{
+	mat2x2 rot = {
+		ubo_vp.rot.xy,
+		ubo_vp.rot.zw,
+	};
+
+	outViewIndex = ubo_vp.viewport_id;
+	outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
+	gl_Position = vec4(rot * (outUV * 2.0f - 1.0f), 0.0f, 1.0f);
+	if (ubo_vp.flip_y)
+		outUV.y = 1.0 - outUV.y;
+}
diff --git a/src/xrt/compositor/shaders/none.frag b/src/xrt/compositor/shaders/none.frag
new file mode 100644
index 000000000..df2ab5b8a
--- /dev/null
+++ b/src/xrt/compositor/shaders/none.frag
@@ -0,0 +1,17 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+// Author: Jakob Bornecrantz <jakob@collabora.com>
+#version 450
+
+layout (binding = 0) uniform sampler2D texSampler;
+
+layout (location = 0)      in vec2 inUV;
+layout (location = 1) flat in int  inViewIndex;
+
+layout (location = 0) out vec4 outColor;
+
+
+void main()
+{
+	outColor = vec4(texture(texSampler, inUV).rgb, 1.0);
+}
diff --git a/src/xrt/compositor/shaders/panotools.frag b/src/xrt/compositor/shaders/panotools.frag
new file mode 100644
index 000000000..9e7c9503f
--- /dev/null
+++ b/src/xrt/compositor/shaders/panotools.frag
@@ -0,0 +1,77 @@
+// Copyright 2017, James Sarrett.
+// Copyright 2017, Bastiaan Olij.
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+// Author: James Sarrett <jsarrett@gmail.com>
+// Author: Bastiaan Olij <mux213@gmail.com>
+// Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+#version 450
+
+layout (binding = 0) uniform sampler2D texSampler;
+
+layout (binding = 1, std140) uniform UBO
+{
+	// Distoriton coefficients (PanoTools model) [a,b,c,d]
+	vec4 HmdWarpParam;
+
+	// chromatic distortion post scaling
+	vec4 aberr;
+
+	// Position of lens center in m (usually eye_w/2, eye_h/2)
+	vec2 LensCenter[2];
+
+	// Scale from texture co-ords to m (usually eye_w, eye_h)
+	vec2 ViewportScale;
+
+	// Distortion overall scale in m (usually ~eye_w/2)
+	float WarpScale;
+} ubo;
+
+layout (location = 0)      in vec2 inUV;
+layout (location = 1) flat in int  inViewIndex;
+
+layout (location = 0) out vec4 outColor;
+
+
+void main()
+{
+	const int i = inViewIndex;
+
+	vec2 r = inUV * ubo.ViewportScale - ubo.LensCenter[i];
+
+	// scale for distortion model
+	// distortion model has r=1 being the largest circle inscribed (e.g. eye_w/2)
+	r /= ubo.WarpScale;
+
+	// |r|**2
+	float r_mag = length(r);
+
+	// offset for which fragment is sourced
+	vec2 r_displaced = r * (
+		ubo.HmdWarpParam.w +
+		ubo.HmdWarpParam.z * r_mag +
+		ubo.HmdWarpParam.y * r_mag * r_mag +
+		ubo.HmdWarpParam.x * r_mag * r_mag * r_mag
+	);
+
+	// back to world scale
+	r_displaced *= ubo.WarpScale;
+
+	// back to viewport co-ord
+	vec2 tcR = (ubo.LensCenter[i] + ubo.aberr.r * r_displaced) / ubo.ViewportScale;
+	vec2 tcG = (ubo.LensCenter[i] + ubo.aberr.g * r_displaced) / ubo.ViewportScale;
+	vec2 tcB = (ubo.LensCenter[i] + ubo.aberr.b * r_displaced) / ubo.ViewportScale;
+
+	vec3 color = vec3(
+		texture(texSampler, tcR).r,
+		texture(texSampler, tcG).g,
+		texture(texSampler, tcB).b
+	);
+
+	// distortion cuttoff
+	if (tcG.x < 0.0 || tcG.x > 1.0 || tcG.y < 0.0 || tcG.y > 1.0) {
+		color *= 0.125;
+	}
+
+	outColor = vec4(color, 1.0);
+}
diff --git a/src/xrt/compositor/shaders/vive.frag b/src/xrt/compositor/shaders/vive.frag
new file mode 100644
index 000000000..012e2b947
--- /dev/null
+++ b/src/xrt/compositor/shaders/vive.frag
@@ -0,0 +1,84 @@
+// Copyright      2017, Philipp Zabel.
+// Copyright 2017-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+// Author: Philipp Zabel <philipp.zabel@gmail.com>
+// Author: Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
+#version 450
+
+// TODO: Don't use hard coded config
+float aspect_x_over_y = 0.8999999761581421;
+float grow_for_undistort = 0.6000000238418579;
+
+vec2 undistort_r2_cutoff = vec2(1.11622154712677, 1.101870775222778);
+
+vec2 center[2] = vec2[](
+	vec2(0.08946027017045266, -0.009002181016260827),
+	vec2(-0.08933516629552526, -0.006014565287238661)
+);
+
+vec3 coeffs[2][3] = {
+	// left
+	{
+		// green
+		vec3(-0.188236068524731, -0.221086205321053, -0.2537849057915209),
+		// blue
+		vec3(-0.07316590815739493, -0.02332400789561968, 0.02469959434698275),
+		// red
+		vec3(-0.02223805567703767, -0.04931309279533211, -0.07862881939243466),
+	},
+	// right
+	{
+		// green
+		vec3(-0.1906209981894497, -0.2248896677207884, -0.2721364516782803),
+		// blue
+		vec3(-0.07346071902951497, -0.02189527566250131, 0.0581378652359256),
+		// red
+		vec3(-0.01755850332081247, -0.04517245633373419, -0.0928909347763)
+	}
+};
+
+layout (binding = 0) uniform sampler2D texSampler;
+
+layout (location = 0) in vec2 inUV;
+layout (location = 1) flat in int inViewIndex;
+
+layout (location = 0) out vec4 outColor;
+
+
+void main()
+{
+	const int i = inViewIndex;
+
+	const vec2 factor = 0.5 / (1.0 + grow_for_undistort)
+	                    * vec2(1.0, aspect_x_over_y);
+
+	vec2 texCoord = 2.0 * inUV - vec2(1.0);
+
+	texCoord.y /= aspect_x_over_y;
+	texCoord -= center[i];
+
+	float r2 = dot(texCoord, texCoord);
+
+	vec3 d_inv = ((r2 * coeffs[i][2] + coeffs[i][1])
+	             * r2 + coeffs[i][0])
+	             * r2 + vec3(1.0);
+
+	const vec3 d = 1.0 / d_inv;
+
+	const vec2 offset = vec2(0.5);
+
+	vec2 tcR = offset + (texCoord * d.r + center[i]) * factor;
+	vec2 tcG = offset + (texCoord * d.g + center[i]) * factor;
+	vec2 tcB = offset + (texCoord * d.b + center[i]) * factor;
+
+	vec3 color = vec3(
+	      texture(texSampler, tcR).r,
+	      texture(texSampler, tcG).g,
+	      texture(texSampler, tcB).b);
+
+	if (r2 > undistort_r2_cutoff[i]) {
+		color *= 0.125;
+	}
+
+	outColor = vec4(color, 1.0);
+}
diff --git a/src/xrt/drivers/CMakeLists.txt b/src/xrt/drivers/CMakeLists.txt
new file mode 100644
index 000000000..f7beac62a
--- /dev/null
+++ b/src/xrt/drivers/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+include_directories(
+	${CMAKE_CURRENT_SOURCE_DIR}/../include
+	${CMAKE_CURRENT_SOURCE_DIR}/../auxiliary
+	)
+
+set(OHMD_SOURCE_FILES
+	ohmd/oh_device.c
+	ohmd/oh_device.h
+	ohmd/oh_interface.h
+	ohmd/oh_prober.c
+	)
+
+# Use OBJECT to not create a archive, since it just gets in the way.
+add_library(drv_ohmd OBJECT ${OHMD_SOURCE_FILES})
+set_property(TARGET drv_ohmd PROPERTY POSITION_INDEPENDENT_CODE ON)
+target_include_directories(drv_ohmd SYSTEM
+	PRIVATE ${OPENHMD_INCLUDE_DIRS}
+	)
+
+if(HIDAPI_FOUND)
+	set(HDK_SOURCE_FILES
+		hdk/hdk_device.cpp
+		hdk/hdk_device.h
+		hdk/hdk_interface.h
+		hdk/hdk_prober.c
+		)
+
+	# Use OBJECT to not create a archive, since it just gets in the way.
+	add_library(drv_hdk OBJECT ${HDK_SOURCE_FILES})
+	set_property(TARGET drv_hdk PROPERTY POSITION_INDEPENDENT_CODE ON)
+	target_include_directories(drv_hdk SYSTEM
+		PRIVATE ${HIDAPI_INCLUDE_DIRS}
+		)
+endif()
diff --git a/src/xrt/drivers/hdk/hdk_device.cpp b/src/xrt/drivers/hdk/hdk_device.cpp
new file mode 100644
index 000000000..8a0226d99
--- /dev/null
+++ b/src/xrt/drivers/hdk/hdk_device.cpp
@@ -0,0 +1,276 @@
+// Copyright 2019, Collabora, Ltd.
+// Copyright 2014, Kevin M. Godby
+// Copyright 2014-2018, Sensics, Inc.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Driver for an OSVR Hacker Dev Kit device.
+ *
+ * Based in part on the corresponding VRPN driver,
+ * available under BSL-1.0.
+ *
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Kevin M. Godby <kevin@godby.org>
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <type_traits>
+
+#include <hidapi.h>
+
+#include "math/m_api.h"
+#include "xrt/xrt_device.h"
+#include "util/u_debug.h"
+#include "util/u_misc.h"
+#include "util/u_device.h"
+
+#include "hdk_device.h"
+
+
+/**
+ * A fixed-point to float conversion function.
+ *
+ * Values are signed, two's-complement, if the supplied integer is.
+ *
+ * The conversion is effectively from the fixed-point arithmetic type known
+ * "unambiguously" as Q INTEGER_BITS.FRACTIONAL_BITS - the number of integer
+ * bits is not inferred, though it is checked to ensure it adds up.
+ *
+ * @tparam INTEGER_BITS The number of bits devoted to the integer part.
+ * @tparam FRACTIONAL_BITS The number of bits devoted to the fractional
+ * part.
+ * @tparam IntegerType The input integer type, typically deduced (do not need to
+ * specify explicitly)
+ * @param v An input "integer" that is actually a fixed-point value.
+ *
+ * INTEGER_BITS and FRACTIONAL_BITS must sum to 8 * sizeof(v), the bit width of
+ * the input integer, for unsigned values, or to one less than that (for the
+ * sign bit) for signed values.
+ *
+ * Based in part on the VRPN header vrpn_FixedPoint.h,
+ * available under BSL-1.0.
+ */
+template <size_t INTEGER_BITS, size_t FRACTIONAL_BITS, typename IntegerType>
+static inline float
+fromFixedPoint(IntegerType v)
+{
+	constexpr size_t SIGN_BIT = std::is_signed<IntegerType>::value ? 1 : 0;
+	static_assert(INTEGER_BITS + FRACTIONAL_BITS + SIGN_BIT ==
+	                  8 * sizeof(IntegerType),
+	              "INTEGER_BITS and FRACTIONAL_BITS, plus 1 for a sign bit "
+	              "if applicable, must sum to the input "
+	              "integer width, but do not.");
+	return static_cast<float>(v) / (1 << FRACTIONAL_BITS);
+}
+
+static inline uint16_t
+hdk_get_le_uint16(uint8_t *&bufPtr)
+{
+	assert(bufPtr != nullptr);
+	uint16_t ret = static_cast<uint16_t>(*bufPtr) |
+	               (static_cast<uint16_t>(*(bufPtr + 1)) << 8);
+	bufPtr += 2;
+	return ret;
+}
+
+static inline int16_t
+hdk_get_le_int16(uint8_t *&bufPtr)
+{
+	return static_cast<int16_t>(hdk_get_le_uint16(bufPtr));
+}
+
+static void
+hdk_device_destroy(struct xrt_device *xdev)
+{
+	struct hdk_device *hd = hdk_device(xdev);
+
+	if (hd->dev != NULL) {
+		hid_close(hd->dev);
+		hd->dev = NULL;
+	}
+
+	free(hd);
+}
+
+static void
+hdk_device_get_tracked_pose(struct xrt_device *xdev,
+                            struct xrt_space_relation *out_relation)
+{
+	struct hdk_device *hd = hdk_device(xdev);
+
+	uint8_t buffer[32];
+	auto bytesRead = hid_read(hd->dev, &(buffer[0]), sizeof(buffer));
+	if (bytesRead != 32 && bytesRead != 16) {
+		HDK_DEBUG(hd, "Only got %d bytes", bytesRead);
+		out_relation->relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
+		return;
+	}
+	uint8_t *buf = &(buffer[0]);
+
+#if 0
+	uint8_t version = uint8_t(0x0f) & *buf;
+	uint8_t hdmi_status = (uint8_t(0xf0) & *buf) >> 4;
+#endif
+	buf++;
+
+	// HDMI status only valid in reports version 3.
+	// Expecting either version 1 (100Hz) or 3 (400Hz):
+	// https://github.com/OSVR/OSVR-HDK-MCU-Firmware/blob/master/Source%20code/Embedded/src/DeviceDrivers/BNO070_using_hostif.c#L511
+
+	// Next byte is sequence number, ignore
+	buf++;
+
+	struct xrt_quat quat;
+	quat.x = fromFixedPoint<1, 14>(hdk_get_le_int16(buf)) * -1;
+	quat.y = fromFixedPoint<1, 14>(hdk_get_le_int16(buf)) * -1;
+	quat.z = fromFixedPoint<1, 14>(hdk_get_le_int16(buf));
+	quat.w = fromFixedPoint<1, 14>(hdk_get_le_int16(buf));
+
+	out_relation->pose.orientation = quat;
+
+	/// @todo might not be accurate on some version 1 reports??
+
+	// This is in the "world" coordinate system.
+	struct xrt_vec3 ang_vel;
+	ang_vel.x = fromFixedPoint<6, 9>(hdk_get_le_int16(buf));
+	ang_vel.y = fromFixedPoint<6, 9>(hdk_get_le_int16(buf));
+	ang_vel.z = fromFixedPoint<6, 9>(hdk_get_le_int16(buf));
+
+	out_relation->angular_velocity = ang_vel;
+
+	out_relation->relation_flags = xrt_space_relation_flags(
+	    XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
+	    XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT |
+	    XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
+
+	HDK_SPEW(hd, "GET_TRACKED_POSE (%f, %f, %f, %f) ANG_VEL (%f, %f, %f)",
+	         quat.x, quat.y, quat.z, quat.w, ang_vel.x, ang_vel.y,
+	         ang_vel.z);
+}
+
+static void
+hdk_device_get_view_pose(struct xrt_device *xdev,
+                         struct xrt_vec3 *eye_relation,
+                         uint32_t view_index,
+                         struct xrt_pose *out_pose)
+{
+	struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}};
+	bool adjust = view_index == 0;
+
+	pose.position.x = eye_relation->x / 2.0f;
+	pose.position.y = eye_relation->y / 2.0f;
+	pose.position.z = eye_relation->z / 2.0f;
+
+	// Adjust for left/right while also making sure there aren't any -0.f.
+	if (pose.position.x > 0.0f && adjust) {
+		pose.position.x = -pose.position.x;
+	}
+	if (pose.position.y > 0.0f && adjust) {
+		pose.position.y = -pose.position.y;
+	}
+	if (pose.position.z > 0.0f && adjust) {
+		pose.position.z = -pose.position.z;
+	}
+
+	*out_pose = pose;
+}
+
+#define HDK_DEBUG_INT(hd, name, val) HDK_DEBUG(hd, "\t%s = %u", name, val)
+
+#define HDK_DEBUG_MM(hd, name, val)                                            \
+	HDK_DEBUG(hd, "\t%s = %i.%02imm", name, (int32_t)(val * 1000.f),       \
+	          abs((int32_t)(val * 100000.f)) % 100)
+
+#define HDK_DEBUG_ANGLE(hd, name, val)                                         \
+	HDK_DEBUG(hd, "\t%s = %f (%i)", name, val,                             \
+	          (int32_t)(val * (180 / M_PI)))
+
+#define HDK_DEBUG_MAT2X2(hd, name, rot)                                        \
+	HDK_DEBUG(hd, "\t%s = {%f, %f} {%f, %f}", name, rot.v[0], rot.v[1],    \
+	          rot.v[2], rot.v[3])
+
+struct hdk_device *
+hdk_device_create(hid_device *dev,
+                  enum HDK_VARIANT variant,
+                  bool print_spew,
+                  bool print_debug)
+{
+	struct hdk_device *hd =
+	    (struct hdk_device *)calloc(1, sizeof(struct hdk_device));
+	hd->base.blend_mode = XRT_BLEND_MODE_OPAQUE;
+	hd->base.destroy = hdk_device_destroy;
+	hd->base.get_tracked_pose = hdk_device_get_tracked_pose;
+	hd->base.get_view_pose = hdk_device_get_view_pose;
+	hd->dev = dev;
+	hd->print_spew = print_spew;
+	hd->print_debug = print_debug;
+
+	if (variant != HDK_VARIANT_2) {
+		HDK_ERROR(hd,
+		          "Only recognize HDK2 for now, and this isn't it!");
+		hdk_device_destroy(&hd->base);
+		return NULL;
+	}
+
+	// Treat as symmetric right now.
+	const double FOV = 92.0 / 180 * M_PI;
+	{
+		/* right eye */
+		math_compute_fovs(1.0, 0.5, FOV, 1, 0.5, FOV,
+		                  &hd->base.views[1].fov);
+	}
+	{
+		/* left eye - just mirroring right eye now */
+		hd->base.views[0].fov.angle_up = hd->base.views[1].fov.angle_up;
+		hd->base.views[0].fov.angle_down =
+		    hd->base.views[1].fov.angle_down;
+
+		hd->base.views[0].fov.angle_left =
+		    -hd->base.views[1].fov.angle_right;
+		hd->base.views[0].fov.angle_right =
+		    -hd->base.views[1].fov.angle_left;
+	}
+
+	// HDK2 is upside down :facepalm:
+
+	// clang-format off
+	// Main display.
+	hd->base.screens[0].w_pixels = 2160;
+	hd->base.screens[0].h_pixels = 1200;
+
+	// Left
+	hd->base.views[0].display.w_pixels = 1080;
+	hd->base.views[0].display.h_pixels = 1200;
+	hd->base.views[0].viewport.x_pixels = 1080; // right half of display
+	hd->base.views[0].viewport.y_pixels = 60;
+	hd->base.views[0].viewport.w_pixels = 1080;
+	hd->base.views[0].viewport.h_pixels = 1080;
+	hd->base.views[0].rot = u_device_rotation_180;
+
+	// Right
+	hd->base.views[1].display.w_pixels = 1080;
+	hd->base.views[1].display.h_pixels = 1200;
+	hd->base.views[1].viewport.x_pixels = 0;
+	hd->base.views[1].viewport.y_pixels = 60;
+	hd->base.views[1].viewport.w_pixels = 1080;
+	hd->base.views[1].viewport.h_pixels = 1080;
+	hd->base.views[1].rot = u_device_rotation_180;
+
+	// Distortion
+	hd->base.distortion.models = XRT_DISTORTION_MODEL_NONE;
+	hd->base.distortion.preferred = XRT_DISTORTION_MODEL_NONE;
+	// clang-format on
+
+
+	if (hd->print_debug) {
+		u_device_dump_config(&hd->base, __func__,
+		                     "OSVR HDK-family Device");
+	}
+
+	return hd;
+}
diff --git a/src/xrt/drivers/hdk/hdk_device.h b/src/xrt/drivers/hdk/hdk_device.h
new file mode 100644
index 000000000..ea4d083f0
--- /dev/null
+++ b/src/xrt/drivers/hdk/hdk_device.h
@@ -0,0 +1,76 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interface to direct OSVR HDK driver code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#pragma once
+
+#include <hidapi.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum HDK_VARIANT
+{
+	HDK_UNKNOWN = 0,
+	HDK_VARIANT_1_2,
+	HDK_VARIANT_1_3_1_4,
+	HDK_VARIANT_2
+};
+
+struct hdk_device
+{
+	struct xrt_device base;
+	hid_device *dev;
+	enum HDK_VARIANT variant;
+
+	bool print_spew;
+	bool print_debug;
+};
+
+static inline struct hdk_device *
+hdk_device(struct xrt_device *xdev)
+{
+	return (struct hdk_device *)xdev;
+}
+
+struct hdk_device *
+hdk_device_create(hid_device *dev,
+                  enum HDK_VARIANT variant,
+                  bool print_spew,
+                  bool print_debug);
+
+#define HDK_SPEW(c, ...)                                                       \
+	do {                                                                   \
+		if (c->print_spew) {                                           \
+			fprintf(stderr, "%s - ", __func__);                    \
+			fprintf(stderr, __VA_ARGS__);                          \
+			fprintf(stderr, "\n");                                 \
+		}                                                              \
+	} while (false)
+#define HDK_DEBUG(c, ...)                                                      \
+	do {                                                                   \
+		if (c->print_debug) {                                          \
+			fprintf(stderr, "%s - ", __func__);                    \
+			fprintf(stderr, __VA_ARGS__);                          \
+			fprintf(stderr, "\n");                                 \
+		}                                                              \
+	} while (false)
+
+#define HDK_ERROR(c, ...)                                                      \
+	do {                                                                   \
+		fprintf(stderr, "%s - ", __func__);                            \
+		fprintf(stderr, __VA_ARGS__);                                  \
+		fprintf(stderr, "\n");                                         \
+	} while (false)
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/drivers/hdk/hdk_interface.h b/src/xrt/drivers/hdk/hdk_interface.h
new file mode 100644
index 000000000..0fb5a4aba
--- /dev/null
+++ b/src/xrt/drivers/hdk/hdk_interface.h
@@ -0,0 +1,23 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interface to direct OSVR HDK driver code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct xrt_prober*
+hdk_create_prober();
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/drivers/hdk/hdk_prober.c b/src/xrt/drivers/hdk/hdk_prober.c
new file mode 100644
index 000000000..5145992db
--- /dev/null
+++ b/src/xrt/drivers/hdk/hdk_prober.c
@@ -0,0 +1,107 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OSVR HDK prober code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#include <hidapi.h>
+#include "xrt/xrt_prober.h"
+
+#include "util/u_misc.h"
+#include "util/u_debug.h"
+
+#include "hdk_device.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(hdk_spew, "HDK_PRINT_SPEW", false)
+DEBUG_GET_ONCE_BOOL_OPTION(hdk_debug, "HDK_PRINT_DEBUG", false)
+
+struct hdk_prober
+{
+	struct xrt_prober base;
+};
+
+static inline struct hdk_prober *
+hdk_prober(struct xrt_prober *p)
+{
+	return (struct hdk_prober *)p;
+}
+
+static void
+hdk_prober_destroy(struct xrt_prober *p)
+{
+	struct hdk_prober *hhp = hdk_prober(p);
+
+
+	free(hhp);
+}
+#define HDK_MAKE_STRING(NAME, STR)                                             \
+	static const char NAME[] = STR;                                        \
+	static const wchar_t NAME##_W[] = L##STR
+
+HDK_MAKE_STRING(HDK2_PRODUCT_STRING, "OSVR HDK 2");
+HDK_MAKE_STRING(HDK13_PRODUCT_STRING, "OSVR HDK 1.3/1.4");
+
+
+static const uint16_t HDK_VID = 0x1532;
+static const uint16_t HDK_PID = 0x0b00;
+
+static struct xrt_device *
+hdk_prober_autoprobe(struct xrt_prober *p)
+{
+	struct hdk_prober *hhp = hdk_prober(p);
+
+	(void)hhp;
+
+	bool print_spew = debug_get_bool_option_hdk_spew();
+	bool print_debug = debug_get_bool_option_hdk_debug();
+	struct hid_device_info *devs = hid_enumerate(HDK_VID, HDK_PID);
+
+	// Just take the first one, not going to loop right now.
+	if (devs == NULL) {
+		if (print_debug) {
+			fprintf(stderr, "%s - no device found\n", __func__);
+		}
+		return NULL;
+	}
+	enum HDK_VARIANT variant = HDK_UNKNOWN;
+	const char *name = NULL;
+	if (0 == wcscmp(HDK2_PRODUCT_STRING_W, devs->product_string)) {
+		variant = HDK_VARIANT_2;
+		name = HDK2_PRODUCT_STRING;
+	} else {
+		//! @todo just assuming anything else is 1.3 for now
+		(void)HDK13_PRODUCT_STRING_W;
+		variant = HDK_VARIANT_1_3_1_4;
+		name = HDK13_PRODUCT_STRING;
+	}
+
+	hid_device *dev = hid_open(HDK_VID, HDK_PID, devs->serial_number);
+	struct hdk_device *hd =
+	    hdk_device_create(dev, variant, print_spew, print_debug);
+	hid_free_enumeration(devs);
+	devs = NULL;
+
+	printf("%s - Found at least the tracker of some HDK: %s\n", __func__,
+	       name);
+
+	return &hd->base;
+}
+
+struct xrt_prober *
+hdk_create_prober()
+{
+	struct hdk_prober *hhp =
+	    (struct hdk_prober *)calloc(1, sizeof(struct hdk_prober));
+	hhp->base.destroy = hdk_prober_destroy;
+	hhp->base.lelo_dallas_autoprobe = hdk_prober_autoprobe;
+
+	return &hhp->base;
+}
diff --git a/src/xrt/drivers/ohmd/oh_device.c b/src/xrt/drivers/ohmd/oh_device.c
new file mode 100644
index 000000000..f70ce59c6
--- /dev/null
+++ b/src/xrt/drivers/ohmd/oh_device.c
@@ -0,0 +1,379 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Adaptor to a OpenHMD device.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "openhmd.h"
+
+#include "math/m_api.h"
+#include "xrt/xrt_device.h"
+#include "util/u_misc.h"
+#include "util/u_debug.h"
+#include "util/u_device.h"
+
+#include "oh_device.h"
+
+// Define this if you have the appropriately hacked-up OpenHMD version.
+#undef OHMD_HAVE_ANG_VEL
+
+static void
+oh_device_destroy(struct xrt_device *xdev)
+{
+	struct oh_device *ohd = oh_device(xdev);
+
+	if (ohd->dev != NULL) {
+		ohmd_close_device(ohd->dev);
+		ohd->dev = NULL;
+	}
+
+	free(ohd);
+}
+
+static void
+oh_device_get_tracked_pose(struct xrt_device *xdev,
+                           struct xrt_space_relation *out_relation)
+{
+	struct oh_device *ohd = oh_device(xdev);
+	struct xrt_quat quat = {0.f, 0.f, 0.f, 1.f};
+	ohmd_ctx_update(ohd->ctx);
+	ohmd_device_getf(ohd->dev, OHMD_ROTATION_QUAT, &quat.x);
+	out_relation->pose.orientation = quat;
+	//! @todo assuming that orientation is actually currently tracked.
+	out_relation->relation_flags = (enum xrt_space_relation_flags)(
+	    XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
+	    XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
+
+#ifdef OHMD_HAVE_ANG_VEL
+	if (!ohd->skip_ang_vel) {
+		struct xrt_vec3 ang_vel;
+		if (0 == ohmd_device_getf(ohd->dev, OHMD_ANGULAR_VELOCITY,
+		                          &ang_vel.x)) {
+			out_relation->angular_velocity = ang_vel;
+			out_relation->relation_flags =
+			    (enum xrt_space_relation_flags)(
+			        out_relation->relation_flags |
+			        XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT);
+			OH_SPEW(
+			    ohd,
+			    "GET_TRACKED_POSE (%f, %f, %f, %f) (%f, %f, %f)",
+			    quat.x, quat.y, quat.z, quat.w, ang_vel.x,
+			    ang_vel.y, ang_vel.z);
+			return;
+		} else {
+			// we now know this device doesn't return angular
+			// velocity.
+			ohd->skip_ang_vel = true;
+		}
+	}
+#endif
+	OH_SPEW(ohd, "GET_TRACKED_POSE (%f, %f, %f, %f)", quat.x, quat.y,
+	        quat.z, quat.w);
+}
+
+static void
+oh_device_get_view_pose(struct xrt_device *xdev,
+                        struct xrt_vec3 *eye_relation,
+                        uint32_t view_index,
+                        struct xrt_pose *out_pose)
+{
+	struct xrt_pose pose = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}};
+	bool adjust = view_index == 0;
+
+	pose.position.x = eye_relation->x / 2.0f;
+	pose.position.y = eye_relation->y / 2.0f;
+	pose.position.z = eye_relation->z / 2.0f;
+
+	// Adjust for left/right while also making sure there aren't any -0.f.
+	if (pose.position.x > 0.0f && adjust) {
+		pose.position.x = -pose.position.x;
+	}
+	if (pose.position.y > 0.0f && adjust) {
+		pose.position.y = -pose.position.y;
+	}
+	if (pose.position.z > 0.0f && adjust) {
+		pose.position.z = -pose.position.z;
+	}
+
+	*out_pose = pose;
+}
+
+struct display_info
+{
+	float w_meters;
+	float h_meters;
+	int w_pixels;
+	int h_pixels;
+};
+
+struct device_info
+{
+	struct display_info display;
+
+	float lens_horizontal_separation;
+	float lens_vertical_position;
+
+	float pano_distortion_k[4];
+	float pano_aberration_k[4];
+	float pano_warp_scale;
+
+	struct
+	{
+		float fov;
+
+		struct display_info display;
+
+		float lens_center_x_meters;
+		float lens_center_y_meters;
+	} views[2];
+};
+
+static struct device_info
+get_info(struct oh_device *ohd)
+{
+	struct device_info info = {0};
+
+	// clang-format off
+	ohmd_device_getf(ohd->dev, OHMD_SCREEN_HORIZONTAL_SIZE, &info.display.w_meters);
+	ohmd_device_getf(ohd->dev, OHMD_SCREEN_VERTICAL_SIZE, &info.display.h_meters);
+	ohmd_device_getf(ohd->dev, OHMD_LENS_HORIZONTAL_SEPARATION, &info.lens_horizontal_separation);
+	ohmd_device_getf(ohd->dev, OHMD_LENS_VERTICAL_POSITION, &info.lens_vertical_position);
+	ohmd_device_getf(ohd->dev, OHMD_LEFT_EYE_FOV, &info.views[0].fov);
+	ohmd_device_getf(ohd->dev, OHMD_RIGHT_EYE_FOV, &info.views[1].fov);
+	ohmd_device_geti(ohd->dev, OHMD_SCREEN_HORIZONTAL_RESOLUTION, &info.display.w_pixels);
+	ohmd_device_geti(ohd->dev, OHMD_SCREEN_VERTICAL_RESOLUTION, &info.display.h_pixels);
+	ohmd_device_getf(ohd->dev, OHMD_UNIVERSAL_DISTORTION_K, &info.pano_distortion_k[0]);
+	ohmd_device_getf(ohd->dev, OHMD_UNIVERSAL_ABERRATION_K, &info.pano_aberration_k[0]);
+
+	/*
+	 * Assumptions made here:
+	 *
+	 * - There is a single, continuous, flat display serving both eyes, with
+	 *   no dead space/gap between eyes.
+	 * - This single panel is (effectively) perpendicular to the forward
+	 *   (-Z) direction, with edges aligned with the X and Y axes.
+	 * - Lens position is symmetrical about the center ("bridge of  nose").
+	 * - Pixels are square and uniform across the entirety of the panel.
+	 *
+	 * If any of these are not true, then either the rendering will
+	 * be inaccurate, or the properties will have to be "fudged" to
+	 * make the math work.
+	 */
+
+	info.views[0].display.w_meters = info.display.w_meters / 2.0;
+	info.views[0].display.h_meters = info.display.h_meters;
+	info.views[1].display.w_meters = info.display.w_meters / 2.0;
+	info.views[1].display.h_meters = info.display.h_meters;
+
+	info.views[0].display.w_pixels = info.display.w_pixels / 2;
+	info.views[0].display.h_pixels = info.display.h_pixels;
+	info.views[1].display.w_pixels = info.display.w_pixels / 2;
+	info.views[1].display.h_pixels = info.display.h_pixels;
+
+	/*
+	 * Assuming the lenses are centered vertically on the
+	 * display. It's not universal, but 0.5 COP on Y is more
+	 * common than on X, and it looked like many of the
+	 * driver lens_vpos values were copy/pasted or marked
+	 * with FIXME. Safer to fix it to 0.5 than risk an
+	 * extreme geometry mismatch.
+	 */
+
+	const double cop_y = 0.5;
+	const double h_1 = cop_y * info.display.h_meters;
+
+	//! @todo This are probably all wrong!
+	info.views[0].lens_center_x_meters = info.views[0].display.w_meters - info.lens_horizontal_separation / 2.0;
+	info.views[0].lens_center_y_meters = h_1;
+
+	info.views[1].lens_center_x_meters = info.lens_horizontal_separation / 2.0;
+	info.views[1].lens_center_y_meters = h_1;
+
+	//! @todo This is most definitely wrong!
+	//!       3Glasses likes the opposite better.
+	info.pano_warp_scale =
+		(info.views[0].lens_center_x_meters > info.views[0].lens_center_x_meters) ?
+			info.views[0].lens_center_x_meters :
+			info.views[0].lens_center_x_meters;
+	// clang-format on
+
+	return info;
+}
+
+struct oh_device *
+oh_device_create(ohmd_context *ctx,
+                 ohmd_device *dev,
+                 const char *prod,
+                 bool print_spew,
+                 bool print_debug)
+{
+	struct oh_device *ohd =
+	    (struct oh_device *)calloc(1, sizeof(struct oh_device));
+	ohd->base.destroy = oh_device_destroy;
+	ohd->base.get_tracked_pose = oh_device_get_tracked_pose;
+	ohd->base.get_view_pose = oh_device_get_view_pose;
+	ohd->ctx = ctx;
+	ohd->dev = dev;
+	ohd->print_spew = print_spew;
+	ohd->print_debug = print_debug;
+
+	const struct device_info info = get_info(ohd);
+
+	{
+		/* right eye */
+		if (!math_compute_fovs(info.views[1].display.w_meters,
+		                       info.views[1].lens_center_x_meters,
+		                       info.views[1].fov,
+		                       info.views[1].display.h_meters,
+		                       info.views[1].lens_center_y_meters, 0,
+		                       &ohd->base.views[1].fov)) {
+			OH_ERROR(
+			    ohd,
+			    "Failed to compute the partial fields of view.");
+			free(ohd);
+			return NULL;
+		}
+	}
+	{
+		/* left eye - just mirroring right eye now */
+		ohd->base.views[0].fov.angle_up =
+		    ohd->base.views[1].fov.angle_up;
+		ohd->base.views[0].fov.angle_down =
+		    ohd->base.views[1].fov.angle_down;
+
+		ohd->base.views[0].fov.angle_left =
+		    -ohd->base.views[1].fov.angle_right;
+		ohd->base.views[0].fov.angle_right =
+		    -ohd->base.views[1].fov.angle_left;
+	}
+
+	// clang-format off
+	// Main display.
+	ohd->base.distortion.models = XRT_DISTORTION_MODEL_PANOTOOLS;
+	ohd->base.distortion.preferred = XRT_DISTORTION_MODEL_PANOTOOLS;
+	ohd->base.screens[0].w_pixels = info.display.w_pixels;
+	ohd->base.screens[0].h_pixels = info.display.h_pixels;
+	ohd->base.distortion.pano.distortion_k[0] = info.pano_distortion_k[0];
+	ohd->base.distortion.pano.distortion_k[1] = info.pano_distortion_k[1];
+	ohd->base.distortion.pano.distortion_k[2] = info.pano_distortion_k[2];
+	ohd->base.distortion.pano.distortion_k[3] = info.pano_distortion_k[3];
+	ohd->base.distortion.pano.aberration_k[0] = info.pano_aberration_k[0];
+	ohd->base.distortion.pano.aberration_k[1] = info.pano_aberration_k[1];
+	ohd->base.distortion.pano.aberration_k[2] = info.pano_aberration_k[2];
+	ohd->base.distortion.pano.warp_scale = info.pano_warp_scale;
+
+	// Left
+	ohd->base.views[0].display.w_meters = info.views[0].display.w_meters;
+	ohd->base.views[0].display.h_meters = info.views[0].display.h_meters;
+	ohd->base.views[0].lens_center.x_meters = info.views[0].lens_center_x_meters;
+	ohd->base.views[0].lens_center.y_meters = info.views[0].lens_center_y_meters;
+	ohd->base.views[0].display.w_pixels = info.views[0].display.w_pixels;
+	ohd->base.views[0].display.h_pixels = info.views[0].display.h_pixels;
+	ohd->base.views[0].viewport.x_pixels = 0;
+	ohd->base.views[0].viewport.y_pixels = 0;
+	ohd->base.views[0].viewport.w_pixels = info.views[0].display.w_pixels;
+	ohd->base.views[0].viewport.h_pixels = info.views[0].display.h_pixels;
+	ohd->base.views[0].rot = u_device_rotation_ident;
+
+	// Right
+	ohd->base.views[1].display.w_meters = info.views[1].display.w_meters;
+	ohd->base.views[1].display.h_meters = info.views[1].display.h_meters;
+	ohd->base.views[1].lens_center.x_meters = info.views[1].lens_center_x_meters;
+	ohd->base.views[1].lens_center.y_meters = info.views[1].lens_center_y_meters;
+	ohd->base.views[1].display.w_pixels = info.views[1].display.w_pixels;
+	ohd->base.views[1].display.h_pixels = info.views[1].display.h_pixels;
+	ohd->base.views[1].viewport.x_pixels = info.views[0].display.w_pixels;
+	ohd->base.views[1].viewport.y_pixels = 0;
+	ohd->base.views[1].viewport.w_pixels = info.views[1].display.w_pixels;
+	ohd->base.views[1].viewport.h_pixels = info.views[1].display.h_pixels;
+	ohd->base.views[1].rot = u_device_rotation_ident;
+	// clang-format on
+
+	// Find any needed quirks.
+	bool quirk_rotate_right = false;
+	bool quirk_rotate_inwards = false;
+	bool quirk_video_see_through = false;
+	bool quirk_video_distortion_none = false;
+	bool quirk_video_distortion_vive = false;
+	bool quirk_left_center_pano_scale = false;
+
+	// Needs to be rotated.
+	if (strcmp(prod, "3Glasses-D3V2") == 0) {
+		quirk_rotate_right = true;
+		quirk_left_center_pano_scale = true;
+	}
+
+	if (strcmp(prod, "HTC Vive") == 0) {
+		quirk_video_distortion_vive = true;
+		quirk_video_see_through = true;
+	}
+
+	if (strcmp(prod, "LGR100") == 0) {
+		quirk_rotate_inwards = true;
+	}
+
+	if (strcmp(prod, "External Device") == 0) {
+		quirk_video_distortion_none = true;
+	}
+
+	// Which blend modes does the device support.
+	ohd->base.blend_mode |= XRT_BLEND_MODE_OPAQUE;
+	if (quirk_video_see_through) {
+		ohd->base.blend_mode |= XRT_BLEND_MODE_ALPHA_BLEND;
+	}
+
+	if (quirk_video_distortion_vive) {
+		ohd->base.distortion.models |= XRT_DISTORTION_MODEL_VIVE;
+		ohd->base.distortion.preferred = XRT_DISTORTION_MODEL_VIVE;
+	}
+
+	if (quirk_video_distortion_none) {
+		ohd->base.distortion.models = XRT_DISTORTION_MODEL_NONE;
+		ohd->base.distortion.preferred = XRT_DISTORTION_MODEL_NONE;
+	}
+
+	if (quirk_left_center_pano_scale) {
+		ohd->base.distortion.pano.warp_scale =
+		    info.views[0].lens_center_x_meters;
+	}
+
+	if (quirk_rotate_right) {
+		int w = info.display.w_pixels;
+		int h = info.display.h_pixels;
+
+		ohd->base.screens[0].w_pixels = h;
+		ohd->base.screens[0].h_pixels = w;
+
+		ohd->base.views[0].viewport.x_pixels = 0;
+		ohd->base.views[0].viewport.y_pixels = 0;
+		ohd->base.views[0].viewport.w_pixels = h;
+		ohd->base.views[0].viewport.h_pixels = w / 2;
+		ohd->base.views[0].rot = u_device_rotation_right;
+
+		ohd->base.views[1].viewport.x_pixels = 0;
+		ohd->base.views[1].viewport.y_pixels = w / 2;
+		ohd->base.views[1].viewport.w_pixels = h;
+		ohd->base.views[1].viewport.h_pixels = w / 2;
+		ohd->base.views[1].rot = u_device_rotation_right;
+	}
+
+	if (quirk_rotate_inwards) {
+		ohd->base.views[0].rot = u_device_rotation_right;
+		ohd->base.views[1].rot = u_device_rotation_left;
+	}
+
+	if (ohd->print_debug) {
+		u_device_dump_config(&ohd->base, __func__, prod);
+	}
+
+	return ohd;
+}
diff --git a/src/xrt/drivers/ohmd/oh_device.h b/src/xrt/drivers/ohmd/oh_device.h
new file mode 100644
index 000000000..02974ffb3
--- /dev/null
+++ b/src/xrt/drivers/ohmd/oh_device.h
@@ -0,0 +1,69 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interface to OpenHMD driver code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct oh_device
+{
+	struct xrt_device base;
+	ohmd_context *ctx;
+	ohmd_device *dev;
+
+	bool skip_ang_vel;
+
+	bool print_spew;
+	bool print_debug;
+};
+
+static inline struct oh_device *
+oh_device(struct xrt_device *xdev)
+{
+	return (struct oh_device *)xdev;
+}
+
+struct oh_device *
+oh_device_create(ohmd_context *ctx,
+                 ohmd_device *dev,
+                 const char *prod,
+                 bool print_spew,
+                 bool print_debug);
+
+#define OH_SPEW(c, ...)                                                        \
+	do {                                                                   \
+		if (c->print_spew) {                                           \
+			fprintf(stderr, "%s - ", __func__);                    \
+			fprintf(stderr, __VA_ARGS__);                          \
+			fprintf(stderr, "\n");                                 \
+		}                                                              \
+	} while (false)
+
+#define OH_DEBUG(c, ...)                                                       \
+	do {                                                                   \
+		if (c->print_debug) {                                          \
+			fprintf(stderr, "%s - ", __func__);                    \
+			fprintf(stderr, __VA_ARGS__);                          \
+			fprintf(stderr, "\n");                                 \
+		}                                                              \
+	} while (false)
+
+#define OH_ERROR(c, ...)                                                       \
+	do {                                                                   \
+		fprintf(stderr, "%s - ", __func__);                            \
+		fprintf(stderr, __VA_ARGS__);                                  \
+		fprintf(stderr, "\n");                                         \
+	} while (false)
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/drivers/ohmd/oh_interface.h b/src/xrt/drivers/ohmd/oh_interface.h
new file mode 100644
index 000000000..3b7f941e5
--- /dev/null
+++ b/src/xrt/drivers/ohmd/oh_interface.h
@@ -0,0 +1,22 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Interface to OpenHMD driver code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct xrt_prober*
+oh_create_prober();
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/drivers/ohmd/oh_prober.c b/src/xrt/drivers/ohmd/oh_prober.c
new file mode 100644
index 000000000..96df01557
--- /dev/null
+++ b/src/xrt/drivers/ohmd/oh_prober.c
@@ -0,0 +1,112 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  OpenHMD prober code.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "openhmd.h"
+#include "xrt/xrt_prober.h"
+
+#include "util/u_misc.h"
+#include "util/u_debug.h"
+
+#include "oh_device.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(oh_spew, "OH_PRINT_SPEW", false)
+DEBUG_GET_ONCE_BOOL_OPTION(oh_debug, "OH_PRINT_DEBUG", false)
+
+struct oh_prober
+{
+	struct xrt_prober base;
+	ohmd_context *ctx;
+	bool print_spew;
+	bool print_debug;
+};
+
+static inline struct oh_prober *
+oh_prober(struct xrt_prober *p)
+{
+	return (struct oh_prober *)p;
+}
+
+static void
+oh_prober_destroy(struct xrt_prober *p)
+{
+	struct oh_prober *ohp = oh_prober(p);
+
+	if (ohp->ctx != NULL) {
+		ohmd_ctx_destroy(ohp->ctx);
+		ohp->ctx = NULL;
+	}
+
+	free(ohp);
+}
+
+static struct xrt_device *
+oh_prober_autoprobe(struct xrt_prober *p)
+{
+	struct oh_prober *ohp = oh_prober(p);
+
+	int device_idx = -1;
+
+	/* Probe for devices */
+	int num_devices = ohmd_ctx_probe(ohp->ctx);
+
+	/* Then loop */
+	for (int i = 0; i < num_devices; i++) {
+		int device_class = 0, device_flags = 0;
+
+		ohmd_list_geti(ohp->ctx, i, OHMD_DEVICE_CLASS, &device_class);
+		ohmd_list_geti(ohp->ctx, i, OHMD_DEVICE_FLAGS, &device_flags);
+
+		if (device_class != OHMD_DEVICE_CLASS_HMD) {
+			OH_DEBUG(ohp, "Rejecting device idx %i, is not a HMD.",
+			         i);
+			continue;
+		}
+
+		if (device_flags & OHMD_DEVICE_FLAGS_NULL_DEVICE) {
+			OH_DEBUG(ohp,
+			         "Rejecting device idx %i, is a NULL device.",
+			         i);
+			continue;
+		}
+
+		OH_DEBUG(ohp, "Selecting device idx %i", i);
+		device_idx = i;
+		break;
+	}
+
+	if (device_idx < 0) {
+		return NULL;
+	}
+
+	const char *prod = ohmd_list_gets(ohp->ctx, device_idx, OHMD_PRODUCT);
+	ohmd_device *dev = ohmd_list_open_device(ohp->ctx, device_idx);
+	if (dev == NULL) {
+		return NULL;
+	}
+
+	struct oh_device *ohd = oh_device_create(
+	    ohp->ctx, dev, prod, ohp->print_spew, ohp->print_debug);
+	return &ohd->base;
+}
+
+struct xrt_prober *
+oh_create_prober()
+{
+	struct oh_prober *ohp = calloc(1, sizeof(struct oh_prober));
+	ohp->base.destroy = oh_prober_destroy;
+	ohp->base.lelo_dallas_autoprobe = oh_prober_autoprobe;
+	ohp->ctx = ohmd_ctx_create();
+	ohp->print_spew = debug_get_bool_option_oh_spew();
+	ohp->print_debug = debug_get_bool_option_oh_debug();
+
+	return &ohp->base;
+}
diff --git a/src/xrt/include/xrt/xrt_compiler.h b/src/xrt/include/xrt/xrt_compiler.h
new file mode 100644
index 000000000..344cb8927
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_compiler.h
@@ -0,0 +1,44 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header holding common defines.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+
+/*
+ * C99 is not a high bar to reach.
+ */
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/*!
+ * Array size helper.
+ */
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
+/*
+ * Printf helper attribute.
+ */
+#if defined(__GNUC__)
+#define XRT_PRINTF_FORMAT(fmt, list) __attribute__((format(printf, fmt, list)))
+#else
+#define XRT_PRINTF_FORMAT(fmt, list)
+#endif
+
+
+/*
+ * To silence unused warnings.
+ */
+#if defined(__GNUC__)
+#define XRT_MAYBE_UNUSED __attribute__((unused))
+#else
+#define XRT_MAYBE_UNUSED
+#endif
diff --git a/src/xrt/include/xrt/xrt_compositor.h b/src/xrt/include/xrt/xrt_compositor.h
new file mode 100644
index 000000000..23707fc6f
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_compositor.h
@@ -0,0 +1,341 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header defining a XRT graphics provider.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * Max swapchain images, artificial limit.
+ *
+ * @ingroup xrt_iface
+ */
+#define XRT_MAX_SWAPCHAIN_IMAGES 8
+
+/*!
+ * Max formats supported by a compositor, artificial limit.
+ *
+ * @ingroup xrt_iface
+ */
+#define XRT_MAX_SWAPCHAIN_FORMATS 8
+
+/*!
+ * Special flags for creating swapchain images.
+ *
+ * @ingroup xrt_iface
+ */
+enum xrt_swapchain_create_flags
+{
+	XRT_SWAPCHAIN_CREATE_STATIC_IMAGE = (1 << 0),
+};
+
+/*!
+ * Usage of the swapchain images.
+ *
+ * @ingroup xrt_iface
+ */
+enum xrt_swapchain_usage_bits
+{
+	XRT_SWAPCHAIN_USAGE_COLOR = (1 << 0),
+};
+
+/*!
+ * View type to be rendered to by the compositor.
+ *
+ * @ingroup xrt_iface
+ */
+enum xrt_view_type
+{
+	XRT_VIEW_TYPE_MONO = 1,
+	XRT_VIEW_TYPE_STEREO = 2,
+};
+
+/*!
+ * Common swapchain base.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_swapchain
+{
+	/*!
+	 * Number of images, the images themselves are on the subclasses.
+	 */
+	uint32_t num_images;
+
+	/*!
+	 * Must have called release_image before calling this function.
+	 */
+	void (*destroy)(struct xrt_swapchain *sc);
+
+	/*!
+	 * See xrWaitSwapchainImage, must make sure that no image is acquired
+	 * before calling acquire_image.
+	 */
+	bool (*acquire_image)(struct xrt_swapchain *xc, uint32_t *index);
+
+	/*!
+	 * See xrWaitSwapchainImage, state tracker needs to track index.
+	 */
+	bool (*wait_image)(struct xrt_swapchain *xc,
+	                   uint64_t timeout,
+	                   uint32_t index);
+
+	/*!
+	 * See xrReleaseSwapchainImage, state tracker needs to track index.
+	 */
+	bool (*release_image)(struct xrt_swapchain *xc, uint32_t index);
+};
+
+/*!
+ * Common compositor base.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_compositor
+{
+	/*!
+	 * Number of formats.
+	 */
+	uint32_t num_formats;
+
+	/*!
+	 * Supported formats.
+	 */
+	int64_t formats[XRT_MAX_SWAPCHAIN_FORMATS];
+
+	/*!
+	 * Create a swapchain with a set of images.
+	 */
+	struct xrt_swapchain *(*create_swapchain)(
+	    struct xrt_compositor *xc,
+	    enum xrt_swapchain_create_flags create,
+	    enum xrt_swapchain_usage_bits bits,
+	    int64_t format,
+	    uint32_t sample_count,
+	    uint32_t width,
+	    uint32_t height,
+	    uint32_t face_count,
+	    uint32_t array_size,
+	    uint32_t mip_count);
+
+	/*!
+	 * Poll events from this compositor.
+	 *
+	 * This function is very much WIP.
+	 */
+	void (*poll_events)(struct xrt_compositor *xc, uint64_t *WIP);
+
+	/*!
+	 * This function is implicit in the OpenXR spec but made explicit here.
+	 */
+	void (*prepare_session)(struct xrt_compositor *xc);
+
+	/*!
+	 * See xrBeginSession.
+	 */
+	void (*begin_session)(struct xrt_compositor *xc,
+	                      enum xrt_view_type view_type);
+
+	/*!
+	 * See xrEndSession, unlike the OpenXR one the state tracker is
+	 * responsible to call discard frame before calling this function. See
+	 * discard_frame.
+	 */
+	void (*end_session)(struct xrt_compositor *xc);
+
+	/*!
+	 * See xrWaitFrame.
+	 */
+	void (*wait_frame)(struct xrt_compositor *xc,
+	                   int64_t *predicted_display_time,
+	                   int64_t *predicted_display_period);
+
+	/*!
+	 * See xrBeginFrame.
+	 */
+	void (*begin_frame)(struct xrt_compositor *xc);
+
+	/*!
+	 * This isn't in the OpenXR API but is explicit in the XRT interfaces.
+	 *
+	 * Two calls to xrBeginFrame will cause the state tracker to call.
+	 *
+	 * ```c
+	 * xc->begin_frame(xc)
+	 * xc->discard_frame(xc)
+	 * xc->begin_frame(xc)
+	 * ```
+	 */
+	void (*discard_frame)(struct xrt_compositor *xc);
+
+	/*!
+	 * See xrEndFrame.
+	 */
+	void (*end_frame)(struct xrt_compositor *xc,
+	                  enum xrt_blend_mode blend_mode,
+	                  struct xrt_swapchain **xscs,
+	                  uint32_t *acquired_index,
+	                  uint32_t num_swapchains);
+
+	/*!
+	 * Teardown the compositor.
+	 *
+	 * The state tracker must have made sure that no frames or sessions are
+	 * currently pending. See discard_frame, end_frame, end_session.
+	 */
+	void (*destroy)(struct xrt_compositor *xc);
+};
+
+
+/*
+ *
+ * OpenGL interface.
+ *
+ */
+
+/*!
+ * @ingroup xrt_iface comp_client
+ */
+struct xrt_swapchain_gl
+{
+	struct xrt_swapchain base;
+
+	// GLuint
+	unsigned int images[XRT_MAX_SWAPCHAIN_IMAGES];
+	// GLuint
+	unsigned int memory[XRT_MAX_SWAPCHAIN_IMAGES];
+};
+
+/*!
+ * @ingroup xrt_iface comp_client
+ */
+struct xrt_compositor_gl
+{
+	struct xrt_compositor base;
+};
+
+static inline struct xrt_swapchain_gl *
+xrt_swapchain_gl(struct xrt_swapchain *xsc)
+{
+	return (struct xrt_swapchain_gl *)xsc;
+}
+
+static inline struct xrt_compositor_gl *
+xrt_compositor_gl(struct xrt_compositor *xc)
+{
+	return (struct xrt_compositor_gl *)xc;
+}
+
+
+/*
+ *
+ * Vulkan interface.
+ *
+ */
+
+typedef struct VkImage_T *VkImage;
+typedef struct VkDeviceMemory_T *VkDeviceMemory;
+
+/*!
+ * Base clase for a Vulkan client swapchain.
+ *
+ * @ingroup xrt_iface comp_client
+ */
+struct xrt_swapchain_vk
+{
+	struct xrt_swapchain base;
+
+	VkImage images[XRT_MAX_SWAPCHAIN_IMAGES];
+	VkDeviceMemory mems[XRT_MAX_SWAPCHAIN_IMAGES];
+};
+
+/*!
+ * Base clase for a Vulkan client compositor.
+ *
+ * @ingroup xrt_iface comp_client
+ */
+struct xrt_compositor_vk
+{
+	struct xrt_compositor base;
+};
+
+static inline struct xrt_swapchain_vk *
+xrt_swapchain_vk(struct xrt_swapchain *xsc)
+{
+	return (struct xrt_swapchain_vk *)xsc;
+}
+
+static inline struct xrt_compositor_vk *
+xrt_compositor_vk(struct xrt_compositor *xc)
+{
+	return (struct xrt_compositor_vk *)xc;
+}
+
+
+/*
+ *
+ * FD interface, aka DMABUF.
+ *
+ */
+
+/*!
+ * A single image of a fd based swapchain.
+ *
+ * @ingroup xrt_iface comp
+ */
+struct xrt_image_fd
+{
+	size_t size;
+	int fd;
+	int _pad;
+};
+
+/*!
+ * A swapchain that exposes fd to be imported into a client API.
+ *
+ * @ingroup xrt_iface comp
+ */
+struct xrt_swapchain_fd
+{
+	struct xrt_swapchain base;
+
+	struct xrt_image_fd images[XRT_MAX_SWAPCHAIN_IMAGES];
+};
+
+/*!
+ * Main compositor.
+ *
+ * @ingroup xrt_iface comp
+ */
+struct xrt_compositor_fd
+{
+	struct xrt_compositor base;
+};
+
+static inline struct xrt_swapchain_fd *
+xrt_swapchain_fd(struct xrt_swapchain *xsc)
+{
+	return (struct xrt_swapchain_fd *)xsc;
+}
+
+static inline struct xrt_compositor_fd *
+xrt_compositor_fd(struct xrt_compositor *xc)
+{
+	return (struct xrt_compositor_fd *)xc;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_config.h b/src/xrt/include/xrt/xrt_config.h
new file mode 100644
index 000000000..c67c3d5f4
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_config.h
@@ -0,0 +1,30 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Auto detect OS and certain features.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+
+/*
+ *
+ * Auto detect OS.
+ *
+ */
+
+#if defined(__linux__)
+#define XRT_OS_LINUX
+#define XRT_OS_UNIX
+#define XRT_OS_WAS_AUTODETECTED
+#endif
+
+
+
+#ifndef XRT_OS_WAS_AUTODETECTED
+#error "OS type not found during compile"
+#endif
+#undef XRT_OS_WAS_AUTODETECTED
diff --git a/src/xrt/include/xrt/xrt_defines.h b/src/xrt/include/xrt/xrt_defines.h
new file mode 100644
index 000000000..b12452969
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_defines.h
@@ -0,0 +1,196 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Common defines and enums for XRT.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_compiler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * Which blend mode does the device support, used as both a bitfield and value.
+ *
+ * @ingroup xrt_iface
+ */
+enum xrt_blend_mode
+{
+	// clang-format off
+	XRT_BLEND_MODE_OPAQUE      = 1 << 0,
+	XRT_BLEND_MODE_ADDITIVE    = 1 << 1,
+	XRT_BLEND_MODE_ALPHA_BLEND = 1 << 2,
+	// clang-format on
+};
+
+/*!
+ * Which distortion model does the device expose,
+ * used both as a bitfield and value.
+ */
+enum xrt_distortion_model
+{
+	// clang-format off
+	XRT_DISTORTION_MODEL_NONE      = 1 << 0,
+	XRT_DISTORTION_MODEL_PANOTOOLS = 1 << 1,
+	XRT_DISTORTION_MODEL_VIVE      = 1 << 2,
+	// clang-format on
+};
+
+/*!
+ * A quaternion with single floats.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_quat
+{
+	float x;
+	float y;
+	float z;
+	float w;
+};
+
+/*!
+ * A 3 element vector with single floats.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_vec3
+{
+	float x;
+	float y;
+	float z;
+};
+
+/*!
+ * A 2 element vector with single floats.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_vec2
+{
+	float x;
+	float y;
+};
+
+/*!
+ * A pose composed of a position and orientation.
+ *
+ * @see xrt_qaut
+ * @see xrt_vec3
+ * @ingroup xrt_iface math
+ */
+struct xrt_pose
+{
+	struct xrt_quat orientation;
+	struct xrt_vec3 position;
+};
+
+/*!
+ * Describes a projection matrix fov.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_fov
+{
+	float angle_left;
+	float angle_right;
+	float angle_up;
+	float angle_down;
+};
+
+/*!
+ * A tightly packed 2x2 matrix of floats.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_matrix_2x2
+{
+	union {
+		float v[4];
+		struct xrt_vec2 vecs[2];
+	};
+};
+
+/*!
+ * A tightly packed 4x4 matrix of floats.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_matrix_4x4
+{
+	float v[16];
+};
+
+/*!
+ * A range of API versions supported.
+ *
+ * @ingroup xrt_iface math
+ */
+struct xrt_api_requirements
+{
+	uint32_t min_major;
+	uint32_t min_minor;
+	uint32_t min_patch;
+
+	uint32_t max_major;
+	uint32_t max_minor;
+	uint32_t max_patch;
+};
+
+/*!
+ * Flags of which components of a @ref xrt_space_relation is valid.
+ *
+ * @see xrt_space_relation
+ * @ingroup xrt_iface math
+ */
+enum xrt_space_relation_flags
+{
+	XRT_SPACE_RELATION_ORIENTATION_VALID_BIT = 0x00000001,
+	XRT_SPACE_RELATION_POSITION_VALID_BIT = 0x00000002,
+	XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT = 0x00000004,
+	XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT = 0x00000008,
+	XRT_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT = 0x00000010,
+	XRT_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT = 0x00000020,
+	XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT = 0x00000040,
+	XRT_SPACE_RELATION_POSITION_TRACKED_BIT = 0x00000080,
+	XRT_SPACE_RELATION_BITMASK_ALL =
+	    XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
+	    XRT_SPACE_RELATION_POSITION_VALID_BIT |
+	    XRT_SPACE_RELATION_LINEAR_VELOCITY_VALID_BIT |
+	    XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT |
+	    XRT_SPACE_RELATION_LINEAR_ACCELERATION_VALID_BIT |
+	    XRT_SPACE_RELATION_ANGULAR_ACCELERATION_VALID_BIT |
+	    XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT |
+	    XRT_SPACE_RELATION_POSITION_TRACKED_BIT,
+	XRT_SPACE_RELATION_BITMASK_NONE = 0
+};
+
+/*!
+ * A relation with two spaces, includes velocity and acceleration.
+ *
+ * @see xrt_quat
+ * @see xrt_vec3
+ * @see xrt_pose
+ * @see xrt_space_relation_flags
+ * @ingroup xrt_iface math
+ */
+struct xrt_space_relation
+{
+	enum xrt_space_relation_flags relation_flags;
+	struct xrt_pose pose;
+	struct xrt_vec3 linear_velocity;
+	struct xrt_vec3 angular_velocity;
+	struct xrt_vec3 linear_acceleration;
+	struct xrt_vec3 angular_acceleration;
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_device.h b/src/xrt/include/xrt/xrt_device.h
new file mode 100644
index 000000000..f1c5c9aaf
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_device.h
@@ -0,0 +1,174 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header defining a xrt HMD device.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * A per-lens view information.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_view
+{
+	/*!
+	 * Viewpport position on the screen, in absolute screen coordinates,
+	 * this field is only used by @ref comp to setup the device rendering.
+	 *
+	 * If the view is being rotated by xrt_view.rot 90° right in the
+	 * distortion shader then `display.w_pixels == viewport.h_pixels` &
+	 * `display.h_pixels == viewport.w_pixels`.
+	 */
+	struct
+	{
+		uint32_t x_pixels;
+		uint32_t y_pixels;
+		uint32_t w_pixels;
+		uint32_t h_pixels;
+	} viewport;
+
+	/*!
+	 * Pixel and phyisical properties of this display, not in absolute
+	 * screen coordinates that the compositor sees. So before any rotation
+	 * is applied by xrt_view::rot.
+	 *
+	 * The xrt_view::display::w_pixels & xrt_view::display::h_pixels
+	 * become the recommdnded image size for this view.
+	 */
+	struct
+	{
+		uint32_t w_pixels;
+		uint32_t h_pixels;
+		float w_meters;
+		float h_meters;
+	} display;
+
+	/*!
+	 * Position in meters relative to display origin, before any rotation
+	 * is applied by xrt_view::rot.
+	 */
+	struct
+	{
+		float x_meters;
+		float y_meters;
+	} lens_center;
+
+	/*!
+	 * Rotation 2d matrix used to rotate the position of the output of the
+	 * distortion shaders onto the screen. Should the distortion shader be
+	 * based on mesh then this matrix rotates the vertex positions.
+	 */
+	struct xrt_matrix_2x2 rot;
+
+	/*!
+	 * Fov expressed in OpenXR.
+	 */
+	struct xrt_fov fov;
+};
+
+/*!
+ * A single HMD device.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_device
+{
+	/*!
+	 * The hmd screen, right now hardcoded to one.
+	 */
+	struct
+	{
+		int w_pixels;
+		int h_pixels;
+	} screens[1];
+
+	/*!
+	 * Display information.
+	 *
+	 * For now hardcoded display to two.
+	 */
+	struct xrt_view views[2];
+
+	/*!
+	 * Supported blend modes, a bitfield.
+	 */
+	enum xrt_blend_mode blend_mode;
+
+	/*!
+	 * Distortion information.
+	 */
+	struct
+	{
+		//! Supported distortion models, a bitfield.
+		enum xrt_distortion_model models;
+		//! Preferred disortion model, single value.
+		enum xrt_distortion_model preferred;
+
+		struct
+		{
+			//! Panotools universal distortion k.
+			float distortion_k[4];
+			//! Panotools post distortion scale, <r, g, b, _>.
+			float aberration_k[4];
+			//! Panotools warp scale.
+			float warp_scale;
+		} pano;
+
+		struct
+		{
+			// To be filled in.
+			float temp;
+		} vive;
+
+	} distortion;
+
+	/*!
+	 * Get relationship of a tracked device to the device "base space".
+	 *
+	 * Right now the base space is assumed to be local space.
+	 *
+	 * This is very very WIP and will need to be made a lot more advanced.
+	 */
+	void (*get_tracked_pose)(struct xrt_device *xdev,
+	                         struct xrt_space_relation *out_relation);
+
+	/*!
+	 * Get the per view pose in relation to the view space. Does not do any
+	 * device level tracking, use get_tracked_pose for that.
+	 *
+	 * @param eye_relation The interpupillary relation as a 3D position,
+	 *                     most simple stereo devices would just want to set
+	 *                     out_puse->position.[x|y|z] = ipd.[x|y|z] / 2.0f.
+	 *                     Not to be confused with IPD that is absolute
+	 *                     distance, this is a full 3D relation.
+	 * @param index        Index of view.
+	 * @param out_pose     Output pose, see ipd argument, and in addition
+	 *                     orientation most likely identity rotation.
+	 */
+	void (*get_view_pose)(struct xrt_device *xdev,
+	                      struct xrt_vec3 *eye_relation,
+	                      uint32_t view_index,
+	                      struct xrt_pose *out_pose);
+
+	/*!
+	 * Destroy device.
+	 */
+	void (*destroy)(struct xrt_device *xdev);
+};
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_documentation.h b/src/xrt/include/xrt/xrt_documentation.h
new file mode 100644
index 000000000..7115bea58
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_documentation.h
@@ -0,0 +1,22 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header with just documentation.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt
+ */
+
+#pragma once
+
+/*!
+ * @defgroup xrt Monado(XRT)
+ */
+
+/*!
+ * @defgroup xrt_iface XRT interfaces
+ *
+ * The main interface shared between the different components of Monado.
+ *
+ * @ingroup xrt
+ */
diff --git a/src/xrt/include/xrt/xrt_gfx_gl.h b/src/xrt/include/xrt/xrt_gfx_gl.h
new file mode 100644
index 000000000..853627d53
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_gfx_gl.h
@@ -0,0 +1,28 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header for misc OpenGL code, not a complete graphics provider.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @ingroup xrt_iface
+ */
+void
+xrt_gfx_gl_get_versions(struct xrt_api_requirements *ver);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_gfx_vk.h b/src/xrt/include/xrt/xrt_gfx_vk.h
new file mode 100644
index 000000000..0df24a33a
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_gfx_vk.h
@@ -0,0 +1,53 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header defining a XRT graphics provider.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_compositor.h"
+#include "xrt/xrt_vulkan_includes.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @ingroup xrt_iface
+ */
+extern const char *xrt_gfx_vk_instance_extensions;
+
+/*!
+ * @ingroup xrt_iface
+ */
+extern const char *xrt_gfx_vk_device_extensions;
+
+/*!
+ * @ingroup xrt_iface
+ */
+void
+xrt_gfx_vk_get_versions(struct xrt_api_requirements *ver);
+
+/*!
+ * @ingroup xrt_iface
+ */
+struct xrt_compositor_vk *
+xrt_gfx_vk_provider_create(struct xrt_device *xdev,
+                           VkInstance instance,
+                           PFN_vkGetInstanceProcAddr getProc,
+                           VkPhysicalDevice physicalDevice,
+                           VkDevice device,
+                           uint32_t queueFamilyIndex,
+                           uint32_t queueIndex);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_gfx_xlib.h b/src/xrt/include/xrt/xrt_gfx_xlib.h
new file mode 100644
index 000000000..66fa1c3eb
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_gfx_xlib.h
@@ -0,0 +1,39 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header defining a XRT graphics provider.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_compositor.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef void* Display;
+typedef void* GLXFBConfig;
+typedef void* GLXDrawable;
+typedef void* GLXContext;
+
+/*!
+ * @ingroup xrt_iface
+ */
+struct xrt_compositor_gl*
+xrt_gfx_provider_create_gl_xlib(struct xrt_device* xdev,
+                                Display* xDisplay,
+                                uint32_t visualid,
+                                GLXFBConfig glxFBConfig,
+                                GLXDrawable glxDrawable,
+                                GLXContext glxContext);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_openxr_includes.h b/src/xrt/include/xrt/xrt_openxr_includes.h
new file mode 100644
index 000000000..96e5113d5
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_openxr_includes.h
@@ -0,0 +1,31 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Include all of the openxr headers in one place.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+// Move these to the build system instead.
+#define XR_USE_GRAPHICS_API_OPENGL
+#define XR_USE_GRAPHICS_API_VULKAN
+#define XR_USE_PLATFORM_XLIB
+#define XR_USE_TIMESPEC 1
+
+#ifdef XR_USE_PLATFORM_XLIB
+typedef void* Display;
+typedef void* GLXFBConfig;
+typedef void* GLXDrawable;
+typedef void* GLXContext;
+#endif
+
+#ifdef XR_USE_TIMESPEC
+#include <time.h>
+#endif
+
+#include "openxr_includes/openxr.h"
+#include "openxr_includes/openxr_platform.h"
+#include "openxr_includes/loader_interfaces.h"
diff --git a/src/xrt/include/xrt/xrt_prober.h b/src/xrt/include/xrt/xrt_prober.h
new file mode 100644
index 000000000..7e0a9211e
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_prober.h
@@ -0,0 +1,42 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Common interface to probe for devices.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * A prober for HMD devices connected to the system.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_prober
+{
+	struct xrt_device *(*lelo_dallas_autoprobe)(struct xrt_prober *xdev);
+	void (*destroy)(struct xrt_prober *xdev);
+};
+
+/*!
+ * Call this function to create the prober. This function is setup in the the
+ * very small target wrapper.c for each binary.
+ *
+ * @ingroup xrt_iface
+ */
+struct xrt_prober *
+xrt_create_prober();
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/include/xrt/xrt_vulkan_includes.h b/src/xrt/include/xrt/xrt_vulkan_includes.h
new file mode 100644
index 000000000..deb086bda
--- /dev/null
+++ b/src/xrt/include/xrt/xrt_vulkan_includes.h
@@ -0,0 +1,13 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Include all of the Vulkan headers in one place.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup xrt_iface
+ */
+
+#pragma once
+
+#define VK_NO_PROTOTYPES
+#include <vulkan/vulkan.h>
diff --git a/src/xrt/state_trackers/CMakeLists.txt b/src/xrt/state_trackers/CMakeLists.txt
new file mode 100644
index 000000000..c65bfe9a7
--- /dev/null
+++ b/src/xrt/state_trackers/CMakeLists.txt
@@ -0,0 +1,47 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+include_directories(
+	${CMAKE_CURRENT_SOURCE_DIR}/../include
+	${CMAKE_CURRENT_SOURCE_DIR}/../auxiliary
+	${CMAKE_CURRENT_SOURCE_DIR}/../../external
+	)
+
+set(OXR_SOURCE_FILES
+	oxr/oxr_api_action.c
+	oxr/oxr_api_debug.c
+	oxr/oxr_api_funcs.h
+	oxr/oxr_api_instance.c
+	oxr/oxr_api_negotiate.c
+	oxr/oxr_api_session.c
+	oxr/oxr_api_space.c
+	oxr/oxr_api_swapchain.c
+	oxr/oxr_api_system.c
+	oxr/oxr_api_verify.h
+	oxr/oxr_event.cpp
+	oxr/oxr_instance.c
+	oxr/oxr_logger.cpp
+	oxr/oxr_logger.h
+	oxr/oxr_objects.h
+	oxr/oxr_session.c
+	oxr/oxr_session_gl.c
+	oxr/oxr_session_vk.c
+	oxr/oxr_space.c
+	oxr/oxr_swapchain.c
+	oxr/oxr_swapchain_gl.c
+	oxr/oxr_swapchain_vk.c
+	oxr/oxr_system.c
+	oxr/oxr_two_call.h
+	oxr/oxr_verify.cpp
+	oxr/oxr_vulkan.c
+	)
+
+# Use OBJECT to not create a archive, since it just gets in the way.
+add_library(st_oxr OBJECT ${OXR_SOURCE_FILES})
+
+target_include_directories(st_oxr
+	PRIVATE
+	${VULKAN_INCLUDE_DIR}
+	)
+
+set_property(TARGET st_oxr PROPERTY POSITION_INDEPENDENT_CODE ON)
diff --git a/src/xrt/state_trackers/dev/README.md b/src/xrt/state_trackers/dev/README.md
new file mode 100644
index 000000000..7e20dee6a
--- /dev/null
+++ b/src/xrt/state_trackers/dev/README.md
@@ -0,0 +1,6 @@
+
+# OpenXR device layer integrator
+
+This is where the device layer integrator code will go. It takes one or more
+xrt_device and plugs that into the OpenXR device layer interface, once the
+device layer has been finalized.
diff --git a/src/xrt/state_trackers/oxr/oxr_api_action.c b/src/xrt/state_trackers/oxr/oxr_api_action.c
new file mode 100644
index 000000000..c2cd6825f
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_action.c
@@ -0,0 +1,305 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Action related API entrypoint functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include <stdio.h>
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+#include "util/u_debug.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+/*
+ *
+ * Session - action functions.
+ *
+ */
+
+XrResult
+oxr_xrSyncActionData(XrSession session,
+                     uint32_t countActionSets,
+                     const XrActiveActionSet* actionSets)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrSyncActionData");
+
+	if (countActionSets == 0) {
+		return oxr_error(&log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(countActionSets == 0)");
+	}
+
+	for (uint32_t i = 0; i < countActionSets; i++) {
+		struct oxr_action_set* act_set;
+		OXR_VERIFY_ARG_TYPE_AND_NULL(&log, (&actionSets[i]),
+		                             XR_TYPE_ACTIVE_ACTION_SET);
+		OXR_VERIFY_ACTIONSET_NOT_NULL(&log, actionSets[i].actionSet,
+		                              act_set);
+		//! @todo verify path.
+	}
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrSetInteractionProfileSuggestedBindings(
+    XrSession session,
+    const XrInteractionProfileSuggestedBinding* suggestedBindings)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(
+	    &log, session, sess, "xrSetInteractionProfileSuggestedBindings");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(
+	    &log, suggestedBindings,
+	    XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING);
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetCurrentInteractionProfile(XrSession session,
+                                   XrPath topLevelUserPath,
+                                   XrInteractionProfileInfo* interactionProfile)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrGetCurrentInteractionProfile");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, interactionProfile,
+	                             XR_TYPE_INTERACTION_PROFILE_INFO);
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetInputSourceLocalizedName(
+    XrSession session,
+    XrPath source,
+    XrInputSourceLocalizedNameFlags whichComponents,
+    uint32_t bufferCapacityInput,
+    uint32_t* bufferCountOutput,
+    char* buffer)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrGetInputSourceLocalizedName");
+	//! @todo verify path
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+
+/*
+ *
+ * Action set functions
+ *
+ */
+
+XrResult
+oxr_xrCreateActionSet(XrSession session,
+                      const XrActionSetCreateInfo* createInfo,
+                      XrActionSet* actionSet)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrCreateActionSet");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_ACTION_SET_CREATE_INFO);
+	OXR_VERIFY_ARG_NOT_NULL(&log, actionSet);
+	OXR_VERIFY_ARG_SINGLE_LEVEL_FIXED_LENGTH_PATH(
+	    &log, createInfo->actionSetName);
+	OXR_VERIFY_ARG_SINGLE_LEVEL_FIXED_LENGTH_PATH(
+	    &log, createInfo->localizedActionSetName);
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrDestroyActionSet(XrActionSet actionSet)
+{
+	struct oxr_action_set* act_set;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTIONSET_AND_INIT_LOG(&log, actionSet, act_set,
+	                                  "xrDestroyActionSet");
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+
+/*
+ *
+ * Action functions
+ *
+ */
+
+XrResult
+oxr_xrCreateAction(XrActionSet actionSet,
+                   const XrActionCreateInfo* createInfo,
+                   XrAction* action)
+{
+	struct oxr_action_set* act_set;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTIONSET_AND_INIT_LOG(&log, actionSet, act_set,
+	                                  "xrCreateAction");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_ACTION_CREATE_INFO);
+	OXR_VERIFY_ARG_NOT_NULL(&log, action);
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrDestroyAction(XrAction action)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act, "xrDestroyAction");
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetActionStateBoolean(XrAction action,
+                            uint32_t countSubactionPaths,
+                            const XrPath* subactionPaths,
+                            XrActionStateBoolean* data)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrGetActionStateBoolean");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_BOOLEAN);
+	OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
+	//! @todo verify paths
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetActionStateVector1f(XrAction action,
+                             uint32_t countSubactionPaths,
+                             const XrPath* subactionPaths,
+                             XrActionStateVector1f* data)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrGetActionStateVector1f");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_VECTOR1F);
+	OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
+	//! @todo verify paths
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetActionStateVector2f(XrAction action,
+                             uint32_t countSubactionPaths,
+                             const XrPath* subactionPaths,
+                             XrActionStateVector2f* data)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrGetActionStateVector2f");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_VECTOR2F);
+	OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
+	//! @todo verify paths
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetActionStatePose(XrAction action,
+                         XrPath subactionPath,
+                         XrActionStatePose* data)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrGetActionStatePose");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, data, XR_TYPE_ACTION_STATE_POSE);
+	//! @todo verify path
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrGetBoundSourcesForAction(XrAction action,
+                               uint32_t sourceCapacityInput,
+                               uint32_t* sourceCountOutput,
+                               XrPath* sources)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrGetBoundSourcesForAction");
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+
+/*
+ *
+ * Haptic feedback functions.
+ *
+ */
+
+XrResult
+oxr_xrApplyHapticFeedback(XrAction hapticAction,
+                          uint32_t countSubactionPaths,
+                          const XrPath* subactionPaths,
+                          const XrHapticBaseHeader* hapticEvent)
+{
+	struct oxr_action* hapticAct;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, hapticAction, hapticAct,
+	                               "xrApplyHapticFeedback");
+	OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
+	//! @todo verify paths
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrStopHapticFeedback(XrAction hapticAction,
+                         uint32_t countSubactionPaths,
+                         const XrPath* subactionPaths)
+{
+	struct oxr_action* hapticAct;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, hapticAction, hapticAct,
+	                               "xrStopHapticFeedback");
+	OXR_VERIFY_SUBACTION_PATHS(&log, countSubactionPaths, subactionPaths);
+	//! @todo verify paths
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_api_debug.c b/src/xrt/state_trackers/oxr/oxr_api_debug.c
new file mode 100644
index 000000000..0d3f777d9
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_debug.c
@@ -0,0 +1,106 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Debug messaging entrypoints for the OpenXR state tracker.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+#ifdef XR_EXT_debug_utils
+
+
+XrResult
+oxr_xrSetDebugUtilsObjectNameEXT(XrInstance instance,
+                                 const XrDebugUtilsObjectNameInfoEXT* nameInfo)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrSetDebugUtilsObjectNameEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrCreateDebugUtilsMessengerEXT(
+    XrInstance instance,
+    const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
+    XrDebugUtilsMessengerEXT* messenger)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrCreateDebugUtilsMessengerEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger)
+{
+	struct oxr_debug_messenger* mssngr;
+	struct oxr_logger log;
+	OXR_VERIFY_MESSENGER_AND_INIT_LOG(&log, messenger, mssngr,
+	                                  "xrDestroyDebugUtilsMessengerEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrSubmitDebugUtilsMessageEXT(
+    XrInstance instance,
+    XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
+    XrDebugUtilsMessageTypeFlagsEXT messageTypes,
+    const XrDebugUtilsMessengerCallbackDataEXT* callbackData)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrSubmitDebugUtilsMessageEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrSessionBeginDebugUtilsLabelRegionEXT(
+    XrSession session, const XrDebugUtilsLabelEXT* labelInfo)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(
+	    &log, session, sess, "xrSessionBeginDebugUtilsLabelRegionEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrSessionEndDebugUtilsLabelRegionEXT(XrSession session)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrSessionEndDebugUtilsLabelRegionEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+XrResult
+oxr_xrSessionInsertDebugUtilsLabelEXT(XrSession session,
+                                      const XrDebugUtilsLabelEXT* labelInfo)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrSessionInsertDebugUtilsLabelEXT");
+
+	return oxr_error(&log, XR_ERROR_RUNTIME_FAILURE, " not implemented");
+}
+
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_api_funcs.h b/src/xrt/state_trackers/oxr/oxr_api_funcs.h
new file mode 100644
index 000000000..0355f42fc
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_funcs.h
@@ -0,0 +1,534 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Header defining all API functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @defgroup oxr_api OpenXR entrypoints
+ *
+ * Gets called from the client application, does most verification and routes
+ * calls into @ref oxr_main functions.
+ *
+ * @ingroup oxr
+ * @{
+ */
+
+
+/*
+ *
+ * oxr_api_negotiate.c
+ *
+ */
+
+//! OpenXR API function @ep{xrGetInstanceProcAddr}
+XrResult
+oxr_xrGetInstanceProcAddr(XrInstance instance,
+                          const char* name,
+                          PFN_xrVoidFunction* function);
+
+//! OpenXR API function @ep{xrEnumerateApiLayerProperties}
+XrResult
+oxr_xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
+                                  uint32_t* propertyCountOutput,
+                                  XrApiLayerProperties* properties);
+
+
+/*
+ *
+ * oxr_api_instance.c
+ *
+ */
+
+//! OpenXR API function @ep{xrEnumerateInstanceExtensionProperties}
+XrResult
+oxr_xrEnumerateInstanceExtensionProperties(const char* layerName,
+                                           uint32_t propertyCapacityInput,
+                                           uint32_t* propertyCountOutput,
+                                           XrExtensionProperties* properties);
+
+//! OpenXR API function @ep{xrCreateInstance}
+XrResult
+oxr_xrCreateInstance(const XrInstanceCreateInfo* createInfo,
+                     XrInstance* instance);
+
+//! OpenXR API function @ep{xrDestroyInstance}
+XrResult
+oxr_xrDestroyInstance(XrInstance instance);
+
+//! OpenXR API function @ep{xrGetInstanceProperties}
+XrResult
+oxr_xrGetInstanceProperties(XrInstance instance,
+                            XrInstanceProperties* instanceProperties);
+
+//! OpenXR API function @ep{xrPollEvent}
+XrResult
+oxr_xrPollEvent(XrInstance instance, XrEventDataBuffer* eventData);
+
+//! OpenXR API function @ep{xrResultToString}
+XrResult
+oxr_xrResultToString(XrInstance instance,
+                     XrResult value,
+                     char buffer[XR_MAX_RESULT_STRING_SIZE]);
+
+//! OpenXR API function @ep{xrStructureTypeToString}
+XrResult
+oxr_xrStructureTypeToString(XrInstance instance,
+                            XrStructureType value,
+                            char buffer[XR_MAX_STRUCTURE_NAME_SIZE]);
+
+//! OpenXR API function @ep{xrStringToPath}
+XrResult
+oxr_xrStringToPath(XrInstance instance, const char* pathString, XrPath* path);
+
+//! OpenXR API function @ep{xrPathToString}
+XrResult
+oxr_xrPathToString(XrInstance instance,
+                   XrPath path,
+                   uint32_t bufferCapacityInput,
+                   uint32_t* bufferCountOutput,
+                   char* buffer);
+
+//! OpenXR API function @ep{xrConvertTimespecTimeToTimeKHR}
+XrResult
+oxr_xrConvertTimespecTimeToTimeKHR(XrInstance instance,
+                                   const struct timespec* timespecTime,
+                                   XrTime* time);
+
+//! OpenXR API function @ep{xrConvertTimeToTimespecTimeKHR}
+XrResult
+oxr_xrConvertTimeToTimespecTimeKHR(XrInstance instance,
+                                   XrTime time,
+                                   struct timespec* timespecTime);
+
+/*
+ *
+ * oxr_api_system.c
+ *
+ */
+
+//! OpenXR API function @ep{xrGetSystem}
+XrResult
+oxr_xrGetSystem(XrInstance instance,
+                const XrSystemGetInfo* getInfo,
+                XrSystemId* systemId);
+
+//! OpenXR API function @ep{xrGetSystemProperties}
+XrResult
+oxr_xrGetSystemProperties(XrInstance instance,
+                          XrSystemId systemId,
+                          XrSystemProperties* properties);
+
+//! OpenXR API function @ep{xrEnumerateViewConfigurations}
+XrResult
+oxr_xrEnumerateViewConfigurations(
+    XrInstance instance,
+    XrSystemId systemId,
+    uint32_t viewConfigurationTypeCapacityInput,
+    uint32_t* viewConfigurationTypeCountOutput,
+    XrViewConfigurationType* viewConfigurationTypes);
+
+//! OpenXR API function @ep{xrGetViewConfigurationProperties}
+XrResult
+oxr_xrGetViewConfigurationProperties(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrViewConfigurationType viewConfigurationType,
+    XrViewConfigurationProperties* configurationProperties);
+
+//! OpenXR API function @ep{xrEnumerateViewConfigurationViews}
+XrResult
+oxr_xrEnumerateViewConfigurationViews(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrViewConfigurationType viewConfigurationType,
+    uint32_t viewCapacityInput,
+    uint32_t* viewCountOutput,
+    XrViewConfigurationView* views);
+
+//! OpenXR API function @ep{xrEnumerateEnvironmentBlendModes}
+XrResult
+oxr_xrEnumerateEnvironmentBlendModes(
+    XrInstance instance,
+    XrSystemId systemId,
+    uint32_t environmentBlendModeCapacityInput,
+    uint32_t* environmentBlendModeCountOutput,
+    XrEnvironmentBlendMode* environmentBlendModes);
+
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+//! OpenXR API function @ep{xrGetOpenGLGraphicsRequirementsKHR}
+XrResult
+oxr_xrGetOpenGLGraphicsRequirementsKHR(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrGraphicsRequirementsOpenGLKHR* graphicsRequirements);
+#endif
+
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+//! OpenXR API function @ep{xrGetVulkanInstanceExtensionsKHR}
+XrResult
+oxr_xrGetVulkanInstanceExtensionsKHR(XrInstance instance,
+                                     XrSystemId systemId,
+                                     uint32_t namesCapacityInput,
+                                     uint32_t* namesCountOutput,
+                                     char* namesString);
+
+//! OpenXR API function @ep{xrGetVulkanDeviceExtensionsKHR}
+XrResult
+oxr_xrGetVulkanDeviceExtensionsKHR(XrInstance instance,
+                                   XrSystemId systemId,
+                                   uint32_t namesCapacityInput,
+                                   uint32_t* namesCountOutput,
+                                   char* namesString);
+
+//! OpenXR API function @ep{xrGetVulkanGraphicsDeviceKHR}
+XrResult
+oxr_xrGetVulkanGraphicsDeviceKHR(XrInstance instance,
+                                 XrSystemId systemId,
+                                 VkInstance vkInstance,
+                                 VkPhysicalDevice* vkPhysicalDevice);
+
+//! OpenXR API function @ep{xrGetVulkanGraphicsRequirementsKHR}
+XrResult
+oxr_xrGetVulkanGraphicsRequirementsKHR(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrGraphicsRequirementsVulkanKHR* graphicsRequirements);
+#endif
+
+
+/*
+ *
+ * oxr_api_session.c
+ *
+ */
+
+//! OpenXR API function @ep{xrCreateSession}
+XrResult
+oxr_xrCreateSession(XrInstance instance,
+                    const XrSessionCreateInfo* createInfo,
+                    XrSession* session);
+
+//! OpenXR API function @ep{xrDestroySession}
+XrResult
+oxr_xrDestroySession(XrSession session);
+
+//! OpenXR API function @ep{xrBeginSession}
+XrResult
+oxr_xrBeginSession(XrSession session, const XrSessionBeginInfo* beginInfo);
+
+//! OpenXR API function @ep{xrEndSession}
+XrResult
+oxr_xrEndSession(XrSession session);
+
+//! OpenXR API function @ep{xrWaitFrame}
+XrResult
+oxr_xrWaitFrame(XrSession session,
+                const XrFrameWaitInfo* frameWaitInfo,
+                XrFrameState* frameState);
+
+//! OpenXR API function @ep{xrBeginFrame}
+XrResult
+oxr_xrBeginFrame(XrSession session, const XrFrameBeginInfo* frameBeginInfo);
+
+//! OpenXR API function @ep{xrEndFrame}
+XrResult
+oxr_xrEndFrame(XrSession session, const XrFrameEndInfo* frameEndInfo);
+
+//! OpenXR API function @ep{xrLocateViews}
+XrResult
+oxr_xrLocateViews(XrSession session,
+                  const XrViewLocateInfo* viewLocateInfo,
+                  XrViewState* viewState,
+                  uint32_t viewCapacityInput,
+                  uint32_t* viewCountOutput,
+                  XrView* views);
+
+#ifdef XR_KHR_visibility_mask
+//! OpenXR API function @ep{xrGetVisibilityMaskKHR}
+XrResult
+oxr_xrGetVisibilityMaskKHR(XrSession session,
+                           XrViewConfigurationType viewConfigurationType,
+                           uint32_t viewIndex,
+                           XrVisibilityMaskTypeKHR visibilityMaskType,
+                           XrVisibilityMaskKHR* visibilityMask);
+#endif
+
+#ifdef XR_EXT_performance_settings
+//! OpenXR API function @ep{xrPerfSettingsSetPerformanceLevelEXT}
+XrResult
+oxr_xrPerfSettingsSetPerformanceLevelEXT(XrSession session,
+                                         XrPerfSettingsDomainEXT domain,
+                                         XrPerfSettingsLevelEXT level);
+#endif
+
+#ifdef XR_EXT_thermal_query
+//! OpenXR API function @ep{xrThermalGetTemperatureTrendEXT}
+XrResult
+oxr_xrThermalGetTemperatureTrendEXT(
+    XrSession session,
+    XrPerfSettingsDomainEXT domain,
+    XrPerfSettingsNotificationLevelEXT* notificationLevel,
+    float* tempHeadroom,
+    float* tempSlope);
+#endif
+
+
+/*
+ *
+ * oxr_api_space.c
+ *
+ */
+
+//! OpenXR API function @ep{xrEnumerateReferenceSpaces}
+XrResult
+oxr_xrEnumerateReferenceSpaces(XrSession session,
+                               uint32_t spaceCapacityInput,
+                               uint32_t* spaceCountOutput,
+                               XrReferenceSpaceType* spaces);
+
+//! OpenXR API function @ep{xrGetReferenceSpaceBoundsRect}
+XrResult
+oxr_xrGetReferenceSpaceBoundsRect(XrSession session,
+                                  XrReferenceSpaceType referenceSpaceType,
+                                  XrExtent2Df* bounds);
+
+//! OpenXR API function @ep{xrCreateReferenceSpace}
+XrResult
+oxr_xrCreateReferenceSpace(XrSession session,
+                           const XrReferenceSpaceCreateInfo* createInfo,
+                           XrSpace* space);
+
+//! OpenXR API function @ep{xrLocateSpace}
+XrResult
+oxr_xrLocateSpace(XrSpace space,
+                  XrSpace baseSpace,
+                  XrTime time,
+                  XrSpaceRelation* relation);
+
+//! OpenXR API function @ep{xrDestroySpace}
+XrResult
+oxr_xrDestroySpace(XrSpace space);
+
+
+/*
+ *
+ * oxr_api_swapchain.c
+ *
+ */
+
+//! OpenXR API function @ep{xrEnumerateSwapchainFormats}
+XrResult
+oxr_xrEnumerateSwapchainFormats(XrSession session,
+                                uint32_t formatCapacityInput,
+                                uint32_t* formatCountOutput,
+                                int64_t* formats);
+
+//! OpenXR API function @ep{xrCreateSwapchain}
+XrResult
+oxr_xrCreateSwapchain(XrSession session,
+                      const XrSwapchainCreateInfo* createInfo,
+                      XrSwapchain* swapchain);
+
+//! OpenXR API function @ep{xrDestroySwapchain}
+XrResult
+oxr_xrDestroySwapchain(XrSwapchain swapchain);
+
+//! OpenXR API function @ep{xrEnumerateSwapchainImages}
+XrResult
+oxr_xrEnumerateSwapchainImages(XrSwapchain swapchain,
+                               uint32_t imageCapacityInput,
+                               uint32_t* imageCountOutput,
+                               XrSwapchainImageBaseHeader* images);
+
+//! OpenXR API function @ep{xrAcquireSwapchainImage}
+XrResult
+oxr_xrAcquireSwapchainImage(XrSwapchain swapchain,
+                            const XrSwapchainImageAcquireInfo* acquireInfo,
+                            uint32_t* index);
+
+//! OpenXR API function @ep{xrWaitSwapchainImage}
+XrResult
+oxr_xrWaitSwapchainImage(XrSwapchain swapchain,
+                         const XrSwapchainImageWaitInfo* waitInfo);
+
+//! OpenXR API function @ep{xrReleaseSwapchainImage}
+XrResult
+oxr_xrReleaseSwapchainImage(XrSwapchain swapchain,
+                            const XrSwapchainImageReleaseInfo* releaseInfo);
+
+
+/*
+ *
+ * oxr_api_debug.c
+ *
+ */
+
+#ifdef XR_EXT_debug_utils
+
+//! OpenXR API function @ep{xrSetDebugUtilsObjectNameEXT}
+XrResult
+oxr_xrSetDebugUtilsObjectNameEXT(XrInstance instance,
+                                 const XrDebugUtilsObjectNameInfoEXT* nameInfo);
+
+//! OpenXR API function @ep{xrCreateDebugUtilsMessengerEXT}
+XrResult
+oxr_xrCreateDebugUtilsMessengerEXT(
+    XrInstance instance,
+    const XrDebugUtilsMessengerCreateInfoEXT* createInfo,
+    XrDebugUtilsMessengerEXT* messenger);
+
+//! OpenXR API function @ep{xrDestroyDebugUtilsMessengerEXT}
+XrResult
+oxr_xrDestroyDebugUtilsMessengerEXT(XrDebugUtilsMessengerEXT messenger);
+
+//! OpenXR API function @ep{xrSubmitDebugUtilsMessageEXT}
+XrResult
+oxr_xrSubmitDebugUtilsMessageEXT(
+    XrInstance instance,
+    XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
+    XrDebugUtilsMessageTypeFlagsEXT messageTypes,
+    const XrDebugUtilsMessengerCallbackDataEXT* callbackData);
+
+//! OpenXR API function @ep{xrSessionBeginDebugUtilsLabelRegionEXT}
+XrResult
+oxr_xrSessionBeginDebugUtilsLabelRegionEXT(
+    XrSession session, const XrDebugUtilsLabelEXT* labelInfo);
+
+//! OpenXR API function @ep{xrSessionEndDebugUtilsLabelRegionEXT}
+XrResult
+oxr_xrSessionEndDebugUtilsLabelRegionEXT(XrSession session);
+
+//! OpenXR API function @ep{xrSessionInsertDebugUtilsLabelEXT}
+XrResult
+oxr_xrSessionInsertDebugUtilsLabelEXT(XrSession session,
+                                      const XrDebugUtilsLabelEXT* labelInfo);
+#endif
+
+
+/*
+ *
+ * oxr_api_action.c
+ *
+ */
+
+//! OpenXR API function @ep{xrCreateActionSpace}
+XrResult
+oxr_xrCreateActionSpace(XrAction action,
+                        const XrActionSpaceCreateInfo* createInfo,
+                        XrSpace* space);
+
+//! OpenXR API function @ep{xrCreateActionSet}
+XrResult
+oxr_xrCreateActionSet(XrSession session,
+                      const XrActionSetCreateInfo* createInfo,
+                      XrActionSet* actionSet);
+
+//! OpenXR API function @ep{xrDestroyActionSet}
+XrResult
+oxr_xrDestroyActionSet(XrActionSet actionSet);
+
+//! OpenXR API function @ep{xrCreateAction}
+XrResult
+oxr_xrCreateAction(XrActionSet actionSet,
+                   const XrActionCreateInfo* createInfo,
+                   XrAction* action);
+
+//! OpenXR API function @ep{xrDestroyAction}
+XrResult
+oxr_xrDestroyAction(XrAction action);
+
+//! OpenXR API function @ep{xrSetInteractionProfileSuggestedBindings}
+XrResult
+oxr_xrSetInteractionProfileSuggestedBindings(
+    XrSession session,
+    const XrInteractionProfileSuggestedBinding* suggestedBindings);
+
+//! OpenXR API function @ep{xrGetCurrentInteractionProfile}
+XrResult
+oxr_xrGetCurrentInteractionProfile(
+    XrSession session,
+    XrPath topLevelUserPath,
+    XrInteractionProfileInfo* interactionProfile);
+
+//! OpenXR API function @ep{xrGetActionStateBoolean}
+XrResult
+oxr_xrGetActionStateBoolean(XrAction action,
+                            uint32_t countSubactionPaths,
+                            const XrPath* subactionPaths,
+                            XrActionStateBoolean* data);
+
+//! OpenXR API function @ep{xrGetActionStateVector1f}
+XrResult
+oxr_xrGetActionStateVector1f(XrAction action,
+                             uint32_t countSubactionPaths,
+                             const XrPath* subactionPaths,
+                             XrActionStateVector1f* data);
+
+//! OpenXR API function @ep{xrGetActionStateVector2f}
+XrResult
+oxr_xrGetActionStateVector2f(XrAction action,
+                             uint32_t countSubactionPaths,
+                             const XrPath* subactionPaths,
+                             XrActionStateVector2f* data);
+
+//! OpenXR API function @ep{xrGetActionStatePose}
+XrResult
+oxr_xrGetActionStatePose(XrAction action,
+                         XrPath subactionPath,
+                         XrActionStatePose* data);
+
+//! OpenXR API function @ep{xrSyncActionData}
+XrResult
+oxr_xrSyncActionData(XrSession session,
+                     uint32_t countActionSets,
+                     const XrActiveActionSet* actionSets);
+
+//! OpenXR API function @ep{xrGetBoundSourcesForAction}
+XrResult
+oxr_xrGetBoundSourcesForAction(XrAction action,
+                               uint32_t sourceCapacityInput,
+                               uint32_t* sourceCountOutput,
+                               XrPath* sources);
+
+//! OpenXR API function @ep{xrGetInputSourceLocalizedName}
+XrResult
+oxr_xrGetInputSourceLocalizedName(
+    XrSession session,
+    XrPath source,
+    XrInputSourceLocalizedNameFlags whichComponents,
+    uint32_t bufferCapacityInput,
+    uint32_t* bufferCountOutput,
+    char* buffer);
+
+//! OpenXR API function @ep{xrApplyHapticFeedback}
+XrResult
+oxr_xrApplyHapticFeedback(XrAction hapticAction,
+                          uint32_t countSubactionPaths,
+                          const XrPath* subactionPaths,
+                          const XrHapticBaseHeader* hapticEvent);
+
+//! OpenXR API function @ep{xrStopHapticFeedback}
+XrResult
+oxr_xrStopHapticFeedback(XrAction hapticAction,
+                         uint32_t countSubactionPaths,
+                         const XrPath* subactionPaths);
+
+/*!
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_api_instance.c b/src/xrt/state_trackers/oxr/oxr_api_instance.c
new file mode 100644
index 000000000..efce9c48c
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_instance.c
@@ -0,0 +1,219 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds instance related entrypoints.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+#include "xrt/xrt_prober.h"
+
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+static const XrExtensionProperties extension_properties[] = {
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+    {XR_TYPE_EXTENSION_PROPERTIES, NULL, XR_KHR_OPENGL_ENABLE_EXTENSION_NAME,
+     XR_KHR_opengl_enable_SPEC_VERSION},
+#endif
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+    {XR_TYPE_EXTENSION_PROPERTIES, NULL, XR_KHR_VULKAN_ENABLE_EXTENSION_NAME,
+     XR_KHR_vulkan_enable_SPEC_VERSION},
+#endif
+    {XR_TYPE_EXTENSION_PROPERTIES, NULL, XR_KHR_HEADLESS_EXTENSION_NAME,
+     XR_KHR_headless_SPEC_VERSION},
+#ifdef XR_USE_TIMESPEC
+    {XR_TYPE_EXTENSION_PROPERTIES, NULL,
+     XR_KHR_CONVERT_TIMESPEC_TIME_EXTENSION_NAME,
+     XR_KHR_convert_timespec_time_SPEC_VERSION},
+#endif
+};
+
+XrResult
+oxr_xrEnumerateInstanceExtensionProperties(const char* layerName,
+                                           uint32_t propertyCapacityInput,
+                                           uint32_t* propertyCountOutput,
+                                           XrExtensionProperties* properties)
+{
+	struct oxr_logger log;
+	oxr_log_init(&log, "xrEnumerateInstanceExtensionProperties");
+
+	OXR_TWO_CALL_HELPER(&log, propertyCapacityInput, propertyCountOutput,
+	                    properties, ARRAY_SIZE(extension_properties),
+	                    extension_properties);
+}
+
+XrResult
+oxr_xrCreateInstance(const XrInstanceCreateInfo* createInfo,
+                     XrInstance* out_instance)
+{
+	XrResult ret;
+	struct oxr_logger log;
+	oxr_log_init(&log, "xrCreateInstance");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_INSTANCE_CREATE_INFO);
+	struct oxr_instance* inst;
+
+	ret = oxr_instance_create(&log, createInfo, &inst);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*out_instance = oxr_instance_to_openxr(inst);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrDestroyInstance(XrInstance instance)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrDestroyInstance");
+
+	return oxr_instance_destroy(&log, inst);
+}
+
+XrResult
+oxr_xrGetInstanceProperties(XrInstance instance,
+                            XrInstanceProperties* instanceProperties)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetInstanceProperties");
+
+	return oxr_instance_get_properties(&log, inst, instanceProperties);
+}
+
+XrResult
+oxr_xrPollEvent(XrInstance instance, XrEventDataBuffer* eventData)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrPollEvent");
+	OXR_VERIFY_ARG_NOT_NULL(&log, eventData);
+
+	return oxr_poll_event(&log, inst, eventData);
+}
+
+XrResult
+oxr_xrResultToString(XrInstance instance,
+                     XrResult value,
+                     char buffer[XR_MAX_RESULT_STRING_SIZE])
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrResultToString");
+
+	OXR_WARN_ONCE(&log, "fill in properly");
+	buffer[0] = '\0';
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrStructureTypeToString(XrInstance instance,
+                            XrStructureType value,
+                            char buffer[XR_MAX_STRUCTURE_NAME_SIZE])
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrStructureTypeToString");
+
+	OXR_WARN_ONCE(&log, "fill in properly");
+	buffer[0] = '\0';
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrStringToPath(XrInstance instance, const char* pathString, XrPath* path)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrStringToPath");
+
+	OXR_WARN_ONCE(&log, "fill in properly");
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrPathToString(XrInstance instance,
+                   XrPath path,
+                   uint32_t bufferCapacityInput,
+                   uint32_t* bufferCountOutput,
+                   char* buffer)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrPathToString");
+
+	OXR_WARN_ONCE(&log, "fill in properly");
+
+	if (bufferCountOutput != NULL) {
+		*bufferCountOutput = 1;
+	}
+
+	if (buffer != NULL && bufferCapacityInput > 0) {
+		buffer[0] = '\0';
+	}
+
+	return XR_SUCCESS;
+}
+
+// ---- XR_KHR_convert_timespec_time extension
+#ifdef XR_USE_TIMESPEC
+XrResult
+oxr_xrConvertTimespecTimeToTimeKHR(XrInstance instance,
+                                   const struct timespec* timespecTime,
+                                   XrTime* time)
+{
+	//! @todo do we need to check and see if this extension was enabled
+	//! first?
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrConvertTimespecTimeToTimeKHR");
+	OXR_VERIFY_ARG_NOT_NULL(&log, timespecTime);
+	OXR_VERIFY_ARG_NOT_NULL(&log, time);
+	return oxr_instance_convert_timespec_to_time(&log, inst, timespecTime,
+	                                             time);
+}
+
+
+XrResult
+oxr_xrConvertTimeToTimespecTimeKHR(XrInstance instance,
+                                   XrTime time,
+                                   struct timespec* timespecTime)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrConvertTimeToTimespecTimeKHR");
+	OXR_VERIFY_ARG_NOT_NULL(&log, timespecTime);
+	return oxr_instance_convert_time_to_timespec(&log, inst, time,
+	                                             timespecTime);
+}
+
+#endif // XR_USE_TIMESPEC
diff --git a/src/xrt/state_trackers/oxr/oxr_api_negotiate.c b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c
new file mode 100644
index 000000000..75497699c
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_negotiate.c
@@ -0,0 +1,269 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  File for negotiating with the loader.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(negotiate, "OXR_DEBUG_NEGOTIATE", false)
+
+#define PRINT_NEGOTIATE(...)                                                   \
+	do {                                                                   \
+		if (debug_get_bool_option_negotiate()) {                       \
+			fprintf(stderr, __VA_ARGS__);                          \
+		}                                                              \
+	} while (false)
+
+
+XrResult
+xrNegotiateLoaderRuntimeInterface(const XrNegotiateLoaderInfo* loaderInfo,
+                                  XrNegotiateRuntimeRequest* runtimeRequest)
+{
+	PRINT_NEGOTIATE("xrNegotiateLoaderRuntimeInterface\n");
+
+	// Make sure that we understand the structs passed to this function.
+	if (loaderInfo->structType != XR_LOADER_INTERFACE_STRUCT_LOADER_INFO ||
+	    loaderInfo->structVersion != XR_LOADER_INFO_STRUCT_VERSION ||
+	    loaderInfo->structSize != sizeof(XrNegotiateLoaderInfo)) {
+		PRINT_NEGOTIATE("\tloaderInfo bad!\n");
+		return XR_ERROR_INITIALIZATION_FAILED;
+	}
+
+	// Make sure that we understand the structs passed to this function.
+	if (runtimeRequest->structType !=
+	        XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST ||
+	    runtimeRequest->structVersion !=
+	        XR_CURRENT_LOADER_RUNTIME_VERSION ||
+	    runtimeRequest->structSize != sizeof(XrNegotiateRuntimeRequest)) {
+		PRINT_NEGOTIATE("\truntimeRequest bad!\n");
+		return XR_ERROR_INITIALIZATION_FAILED;
+	}
+
+	// TODO: properly define what we support
+	uint16_t supported_major = XR_VERSION_MAJOR(XR_CURRENT_API_VERSION);
+	uint16_t supported_minor = XR_VERSION_MINOR(XR_CURRENT_API_VERSION);
+
+	uint16_t requested_min_major =
+	    XR_VERSION_MAJOR(loaderInfo->minInterfaceVersion);
+	uint16_t requested_min_minor =
+	    XR_VERSION_MINOR(loaderInfo->minInterfaceVersion);
+
+	uint16_t requested_max_major =
+	    XR_VERSION_MAJOR(loaderInfo->maxInterfaceVersion);
+	uint16_t requested_max_minor =
+	    XR_VERSION_MINOR(loaderInfo->maxInterfaceVersion);
+
+	if (supported_major > requested_max_major ||
+	    supported_major < requested_min_major) {
+		PRINT_NEGOTIATE(
+		    "\tXRT - OpenXR doesn't support requested version %d.%d <= "
+		    "%d.%d <= %d.%d",
+		    requested_min_major, requested_min_minor, supported_major,
+		    supported_minor, requested_max_major, requested_max_minor);
+		return XR_ERROR_INITIALIZATION_FAILED;
+	}
+
+	runtimeRequest->getInstanceProcAddr = oxr_xrGetInstanceProcAddr;
+	runtimeRequest->runtimeInterfaceVersion =
+	    XR_CURRENT_LOADER_RUNTIME_VERSION;
+	runtimeRequest->runtimeXrVersion =
+	    XR_MAKE_VERSION(0, XR_HEADER_VERSION, 0);
+
+	PRINT_NEGOTIATE("\tall ok!\n");
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrEnumerateApiLayerProperties(uint32_t propertyCapacityInput,
+                                  uint32_t* propertyCountOutput,
+                                  XrApiLayerProperties* properties)
+{
+	struct oxr_logger log;
+	oxr_log_init(&log, "xrEnumerateApiLayerProperties");
+
+	/* We have no layers inbuilt. */
+	if (propertyCountOutput != NULL) {
+		*propertyCountOutput = 0;
+	}
+
+	return XR_SUCCESS;
+}
+
+/*!
+ * @brief Helper define for generating that GetInstanceProcAddr function.
+ */
+#define ENTRY_IF(funcName)                                                     \
+	if (strcmp(name, #funcName) == 0) {                                    \
+		PFN_##funcName ret = &oxr_##funcName;                          \
+		*function = (PFN_xrVoidFunction)(ret);                         \
+	}
+
+/*!
+ * @brief Helper define for generating that GetInstanceProcAddr function.
+ */
+#define ENTRY_ELSE_IF(funcName)                                                \
+	else if (strcmp(name, #funcName) == 0)                                 \
+	{                                                                      \
+		PFN_##funcName ret = &oxr_##funcName;                          \
+		*function = (PFN_xrVoidFunction)(ret);                         \
+	}
+
+/*!
+ * Handle a non-null instance pointer.
+ */
+static XrResult
+handle_none_null(struct oxr_logger* log,
+                 const char* name,
+                 PFN_xrVoidFunction* function)
+{
+	ENTRY_IF(xrGetInstanceProcAddr)
+	ENTRY_ELSE_IF(xrEnumerateApiLayerProperties)
+	ENTRY_ELSE_IF(xrEnumerateInstanceExtensionProperties)
+	ENTRY_ELSE_IF(xrCreateInstance)
+	ENTRY_ELSE_IF(xrDestroyInstance)
+	ENTRY_ELSE_IF(xrGetInstanceProperties)
+	ENTRY_ELSE_IF(xrPollEvent)
+	ENTRY_ELSE_IF(xrResultToString)
+	ENTRY_ELSE_IF(xrStructureTypeToString)
+	ENTRY_ELSE_IF(xrGetSystem)
+	ENTRY_ELSE_IF(xrGetSystemProperties)
+	ENTRY_ELSE_IF(xrEnumerateEnvironmentBlendModes)
+	ENTRY_ELSE_IF(xrCreateSession)
+	ENTRY_ELSE_IF(xrDestroySession)
+	ENTRY_ELSE_IF(xrEnumerateReferenceSpaces)
+	ENTRY_ELSE_IF(xrCreateReferenceSpace)
+	ENTRY_ELSE_IF(xrGetReferenceSpaceBoundsRect)
+	ENTRY_ELSE_IF(xrCreateActionSpace)
+	ENTRY_ELSE_IF(xrLocateSpace)
+	ENTRY_ELSE_IF(xrDestroySpace)
+	ENTRY_ELSE_IF(xrEnumerateViewConfigurations)
+	ENTRY_ELSE_IF(xrGetViewConfigurationProperties)
+	ENTRY_ELSE_IF(xrEnumerateViewConfigurationViews)
+	ENTRY_ELSE_IF(xrEnumerateSwapchainFormats)
+	ENTRY_ELSE_IF(xrCreateSwapchain)
+	ENTRY_ELSE_IF(xrDestroySwapchain)
+	ENTRY_ELSE_IF(xrEnumerateSwapchainImages)
+	ENTRY_ELSE_IF(xrAcquireSwapchainImage)
+	ENTRY_ELSE_IF(xrWaitSwapchainImage)
+	ENTRY_ELSE_IF(xrReleaseSwapchainImage)
+	ENTRY_ELSE_IF(xrBeginSession)
+	ENTRY_ELSE_IF(xrEndSession)
+	ENTRY_ELSE_IF(xrWaitFrame)
+	ENTRY_ELSE_IF(xrBeginFrame)
+	ENTRY_ELSE_IF(xrEndFrame)
+	ENTRY_ELSE_IF(xrLocateViews)
+	ENTRY_ELSE_IF(xrStringToPath)
+	ENTRY_ELSE_IF(xrPathToString)
+	ENTRY_ELSE_IF(xrCreateActionSet)
+	ENTRY_ELSE_IF(xrDestroyActionSet)
+	ENTRY_ELSE_IF(xrCreateAction)
+	ENTRY_ELSE_IF(xrDestroyAction)
+	ENTRY_ELSE_IF(xrSetInteractionProfileSuggestedBindings)
+	ENTRY_ELSE_IF(xrGetCurrentInteractionProfile)
+	ENTRY_ELSE_IF(xrGetActionStateBoolean)
+	ENTRY_ELSE_IF(xrGetActionStateVector1f)
+	ENTRY_ELSE_IF(xrGetActionStateVector2f)
+	ENTRY_ELSE_IF(xrGetActionStatePose)
+	ENTRY_ELSE_IF(xrSyncActionData)
+	ENTRY_ELSE_IF(xrGetBoundSourcesForAction)
+	ENTRY_ELSE_IF(xrGetInputSourceLocalizedName)
+	ENTRY_ELSE_IF(xrApplyHapticFeedback)
+	ENTRY_ELSE_IF(xrStopHapticFeedback)
+#ifdef XR_KHR_visibility_mask
+	ENTRY_ELSE_IF(xrGetVisibilityMaskKHR)
+#endif
+#ifdef XR_USE_TIMESPEC
+	ENTRY_ELSE_IF(xrConvertTimespecTimeToTimeKHR)
+	ENTRY_ELSE_IF(xrConvertTimeToTimespecTimeKHR)
+#endif
+#ifdef XR_EXT_performance_settings
+	ENTRY_ELSE_IF(xrPerfSettingsSetPerformanceLevelEXT)
+#endif
+#ifdef XR_EXT_thermal_query
+	ENTRY_ELSE_IF(xrThermalGetTemperatureTrendEXT)
+#endif
+#ifdef XR_EXT_debug_utils
+	ENTRY_ELSE_IF(xrSetDebugUtilsObjectNameEXT)
+	ENTRY_ELSE_IF(xrCreateDebugUtilsMessengerEXT)
+	ENTRY_ELSE_IF(xrDestroyDebugUtilsMessengerEXT)
+	ENTRY_ELSE_IF(xrSubmitDebugUtilsMessageEXT)
+	ENTRY_ELSE_IF(xrSessionBeginDebugUtilsLabelRegionEXT)
+	ENTRY_ELSE_IF(xrSessionEndDebugUtilsLabelRegionEXT)
+	ENTRY_ELSE_IF(xrSessionInsertDebugUtilsLabelEXT)
+#endif
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+	ENTRY_ELSE_IF(xrGetOpenGLGraphicsRequirementsKHR)
+#endif
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+	ENTRY_ELSE_IF(xrGetVulkanInstanceExtensionsKHR)
+	ENTRY_ELSE_IF(xrGetVulkanDeviceExtensionsKHR)
+	ENTRY_ELSE_IF(xrGetVulkanGraphicsDeviceKHR)
+	ENTRY_ELSE_IF(xrGetVulkanGraphicsRequirementsKHR)
+#endif
+
+
+	if ((*function) == NULL) {
+		return oxr_error(log, XR_ERROR_FUNCTION_UNSUPPORTED,
+		                 "(name = \"%s\")", name);
+	}
+
+	return XR_SUCCESS;
+}
+
+/*!
+ * Special case a null instance pointer.
+ */
+static XrResult
+handle_null(struct oxr_logger* log,
+            const char* name,
+            PFN_xrVoidFunction* function)
+{
+	ENTRY_IF(xrCreateInstance)
+	ENTRY_ELSE_IF(xrEnumerateInstanceExtensionProperties)
+
+	if ((*function) == NULL) {
+		return oxr_error(log, XR_ERROR_FUNCTION_UNSUPPORTED,
+		                 "(name = \"%s\")", name);
+	}
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrGetInstanceProcAddr(XrInstance instance,
+                          const char* name,
+                          PFN_xrVoidFunction* function)
+{
+	if (instance == NULL) {
+		struct oxr_logger log;
+		oxr_log_init(&log, "xrGetInstanceProcAddr");
+
+		return handle_null(&log, name, function);
+	} else {
+		struct oxr_instance* inst;
+		struct oxr_logger log;
+		OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+		                                 "xrGetInstanceProcAddr");
+
+		return handle_none_null(&log, name, function);
+	}
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_api_session.c b/src/xrt/state_trackers/oxr/oxr_api_session.c
new file mode 100644
index 000000000..afe2b5a0c
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_session.c
@@ -0,0 +1,228 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Session entrypoints for the OpenXR state tracker.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+
+XrResult
+oxr_xrCreateSession(XrInstance instance,
+                    const XrSessionCreateInfo* createInfo,
+                    XrSession* out_session)
+{
+	XrResult ret;
+	struct oxr_instance* inst;
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrCreateSession");
+
+	ret = oxr_verify_XrSessionCreateInfo(&log, createInfo);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	ret = oxr_session_create(&log, &inst->system,
+	                         (XrStructureType*)createInfo->next, &sess);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*out_session = oxr_session_to_openxr(sess);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrDestroySession(XrSession session)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrDestroySession");
+
+	return oxr_session_destroy(&log, sess);
+}
+
+XrResult
+oxr_xrBeginSession(XrSession session, const XrSessionBeginInfo* beginInfo)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrBeginSession");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, beginInfo,
+	                             XR_TYPE_SESSION_BEGIN_INFO);
+
+	return oxr_session_begin(&log, sess, beginInfo);
+}
+
+XrResult
+oxr_xrEndSession(XrSession session)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEndSession");
+
+	return oxr_session_end(&log, sess);
+}
+
+XrResult
+oxr_xrWaitFrame(XrSession session,
+                const XrFrameWaitInfo* frameWaitInfo,
+                XrFrameState* frameState)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrWaitFrame");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, frameState, XR_TYPE_FRAME_STATE);
+	OXR_VERIFY_ARG_NOT_NULL(&log, frameState);
+
+	return oxr_session_frame_wait(&log, sess, frameState);
+}
+
+XrResult
+oxr_xrBeginFrame(XrSession session, const XrFrameBeginInfo* frameBeginInfo)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrBeginFrame");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, frameBeginInfo,
+	                             XR_TYPE_FRAME_BEGIN_INFO);
+
+	return oxr_session_frame_begin(&log, sess);
+}
+
+XrResult
+oxr_xrEndFrame(XrSession session, const XrFrameEndInfo* frameEndInfo)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrEndFrame");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, frameEndInfo,
+	                             XR_TYPE_FRAME_END_INFO);
+
+	return oxr_session_frame_end(&log, sess, frameEndInfo);
+}
+
+XrResult
+oxr_xrLocateViews(XrSession session,
+                  const XrViewLocateInfo* viewLocateInfo,
+                  XrViewState* viewState,
+                  uint32_t viewCapacityInput,
+                  uint32_t* viewCountOutput,
+                  XrView* views)
+{
+	struct oxr_session* sess;
+	struct oxr_space* spc;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess, "xrLocateViews");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, viewLocateInfo,
+	                             XR_TYPE_VIEW_LOCATE_INFO);
+	OXR_VERIFY_SPACE_NOT_NULL(&log, viewLocateInfo->space, spc);
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, viewState, XR_TYPE_VIEW_STATE);
+
+	if (viewCapacityInput == 0) {
+		OXR_VERIFY_ARG_NOT_NULL(&log, viewCountOutput);
+	} else {
+		OXR_VERIFY_ARG_NOT_NULL(&log, views);
+	}
+
+	return oxr_session_views(&log, sess, viewLocateInfo, viewState,
+	                         viewCapacityInput, viewCountOutput, views);
+}
+
+
+/*
+ *
+ * XR_KHR_visibility_mask
+ *
+ */
+
+#ifdef XR_KHR_visibility_mask
+
+XrResult
+oxr_xrGetVisibilityMaskKHR(XrSession session,
+                           XrViewConfigurationType viewConfigurationType,
+                           uint32_t viewIndex,
+                           XrVisibilityMaskTypeKHR visibilityMaskType,
+                           XrVisibilityMaskKHR* visibilityMask)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrGetVisibilityMaskKHR");
+
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+#endif
+
+
+/*
+ *
+ * XR_EXT_performance_settings
+ *
+ */
+
+#ifdef XR_EXT_performance_settings
+
+XrResult
+oxr_xrPerfSettingsSetPerformanceLevelEXT(XrSession session,
+                                         XrPerfSettingsDomainEXT domain,
+                                         XrPerfSettingsLevelEXT level)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrPerfSettingsSetPerformanceLevelEXT");
+
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+#endif
+
+
+/*
+ *
+ * XR_EXT_thermal_query
+ *
+ */
+
+#ifdef XR_EXT_thermal_query
+
+XrResult
+oxr_xrThermalGetTemperatureTrendEXT(
+    XrSession session,
+    XrPerfSettingsDomainEXT domain,
+    XrPerfSettingsNotificationLevelEXT* notificationLevel,
+    float* tempHeadroom,
+    float* tempSlope)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrThermalGetTemperatureTrendEXT");
+
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_api_space.c b/src/xrt/state_trackers/oxr/oxr_api_space.c
new file mode 100644
index 000000000..54e0e9992
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_space.c
@@ -0,0 +1,125 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Space, space, space, SPAAAAAAAAAAAAAAAAAAAAAAAAAACE!
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+XrResult
+oxr_xrCreateActionSpace(XrAction action,
+                        const XrActionSpaceCreateInfo* createInfo,
+                        XrSpace* space)
+{
+	struct oxr_action* act;
+	struct oxr_logger log;
+	OXR_VERIFY_ACTION_AND_INIT_LOG(&log, action, act,
+	                               "xrCreateActionSpace");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_ACTION_SPACE_CREATE_INFO);
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+static const XrReferenceSpaceType session_spaces[] = {
+    XR_REFERENCE_SPACE_TYPE_VIEW,
+    XR_REFERENCE_SPACE_TYPE_LOCAL,
+    XR_REFERENCE_SPACE_TYPE_STAGE,
+};
+
+XrResult
+oxr_xrEnumerateReferenceSpaces(XrSession session,
+                               uint32_t spaceCapacityInput,
+                               uint32_t* spaceCountOutput,
+                               XrReferenceSpaceType* spaces)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrEnumerateReferenceSpaces");
+
+	OXR_TWO_CALL_HELPER(&log, spaceCapacityInput, spaceCountOutput, spaces,
+	                    ARRAY_SIZE(session_spaces), session_spaces);
+}
+
+XrResult
+oxr_xrGetReferenceSpaceBoundsRect(XrSession session,
+                                  XrReferenceSpaceType referenceSpaceType,
+                                  XrExtent2Df* bounds)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrGetReferenceSpaceBoundsRect");
+
+	//! @todo Implement
+	return oxr_error(&log, XR_ERROR_HANDLE_INVALID, " not implemented");
+}
+
+XrResult
+oxr_xrCreateReferenceSpace(XrSession session,
+                           const XrReferenceSpaceCreateInfo* createInfo,
+                           XrSpace* out_space)
+{
+	XrResult ret;
+	struct oxr_session* sess;
+	struct oxr_space* spc;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrCreateReferenceSpace");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_REFERENCE_SPACE_CREATE_INFO);
+
+	ret = oxr_space_reference_create(&log, sess, createInfo, &spc);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*out_space = oxr_space_to_openxr(spc);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrLocateSpace(XrSpace space,
+                  XrSpace baseSpace,
+                  XrTime time,
+                  XrSpaceRelation* relation)
+{
+	struct oxr_space* spc;
+	struct oxr_space* baseSpc;
+	struct oxr_logger log;
+	OXR_VERIFY_SPACE_AND_INIT_LOG(&log, space, spc, "xrLocateSpace");
+	OXR_VERIFY_SPACE_NOT_NULL(&log, baseSpace, baseSpc);
+	OXR_VERIFY_ARG_NOT_NULL(&log, relation);
+
+	return oxr_space_locate(&log, spc, baseSpc, time, relation);
+}
+
+XrResult
+oxr_xrDestroySpace(XrSpace space)
+{
+	struct oxr_space* spc;
+	struct oxr_logger log;
+	OXR_VERIFY_SPACE_AND_INIT_LOG(&log, space, spc, "xrDestroySpace");
+
+	return oxr_space_destroy(&log, spc);
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_api_swapchain.c b/src/xrt/state_trackers/oxr/oxr_api_swapchain.c
new file mode 100644
index 000000000..6d4f221bd
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_swapchain.c
@@ -0,0 +1,146 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Swapchain entrypoints for the OpenXR state tracker.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+XrResult
+oxr_xrEnumerateSwapchainFormats(XrSession session,
+                                uint32_t formatCapacityInput,
+                                uint32_t* formatCountOutput,
+                                int64_t* formats)
+{
+	struct oxr_session* sess;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrEnumerateSwapchainFormats");
+
+	return oxr_session_enumerate_formats(&log, sess, formatCapacityInput,
+	                                     formatCountOutput, formats);
+}
+
+XrResult
+oxr_xrCreateSwapchain(XrSession session,
+                      const XrSwapchainCreateInfo* createInfo,
+                      XrSwapchain* out_swapchain)
+{
+	XrResult ret;
+	struct oxr_session* sess;
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SESSION_AND_INIT_LOG(&log, session, sess,
+	                                "xrCreateSwapchain");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, createInfo,
+	                             XR_TYPE_SWAPCHAIN_CREATE_INFO);
+	OXR_VERIFY_ARG_NOT_NULL(&log, out_swapchain);
+
+	ret = sess->create_swapchain(&log, sess, createInfo, &sc);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*out_swapchain = oxr_swapchain_to_openxr(sc);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrDestroySwapchain(XrSwapchain swapchain)
+{
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
+	                                  "xrDestroySwapchain");
+
+	return sc->destroy(&log, sc);
+}
+
+XrResult
+oxr_xrEnumerateSwapchainImages(XrSwapchain swapchain,
+                               uint32_t imageCapacityInput,
+                               uint32_t* imageCountOutput,
+                               XrSwapchainImageBaseHeader* images)
+{
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
+	                                  "xrEnumerateSwapchainImages");
+	struct xrt_swapchain* xsc = sc->swapchain;
+
+	if (imageCountOutput != NULL) {
+		*imageCountOutput = xsc->num_images;
+	}
+	if (imageCapacityInput == 0) {
+		return XR_SUCCESS;
+	}
+	if (imageCapacityInput < xsc->num_images) {
+		return oxr_error(&log, XR_ERROR_SIZE_INSUFFICIENT,
+		                 "(imageCapacityInput = %u)",
+		                 imageCapacityInput);
+	}
+
+	return sc->enumerate_images(&log, sc, xsc->num_images, images);
+}
+
+XrResult
+oxr_xrAcquireSwapchainImage(XrSwapchain swapchain,
+                            const XrSwapchainImageAcquireInfo* acquireInfo,
+                            uint32_t* index)
+{
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
+	                                  "xrAcquireSwapchainImage");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, acquireInfo,
+	                             XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO);
+	OXR_VERIFY_ARG_NOT_NULL(&log, index);
+
+	return sc->acquire_image(&log, sc, acquireInfo, index);
+}
+
+XrResult
+oxr_xrWaitSwapchainImage(XrSwapchain swapchain,
+                         const XrSwapchainImageWaitInfo* waitInfo)
+{
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
+	                                  "xrWaitSwapchainImage");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, waitInfo,
+	                             XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO);
+
+	return sc->wait_image(&log, sc, waitInfo);
+}
+
+XrResult
+oxr_xrReleaseSwapchainImage(XrSwapchain swapchain,
+                            const XrSwapchainImageReleaseInfo* releaseInfo)
+{
+	struct oxr_swapchain* sc;
+	struct oxr_logger log;
+	OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(&log, swapchain, sc,
+	                                  "xrReleaseSwapchainImage");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, releaseInfo,
+	                             XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO);
+
+	return sc->release_image(&log, sc, releaseInfo);
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_api_system.c b/src/xrt/state_trackers/oxr/oxr_api_system.c
new file mode 100644
index 000000000..52b272328
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_system.c
@@ -0,0 +1,297 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds system related entrypoints.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "xrt/xrt_compiler.h"
+#include "xrt/xrt_gfx_gl.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+#include "oxr_api_funcs.h"
+#include "oxr_api_verify.h"
+
+
+/*!
+ * A helper defines that allocates a logger on the stack and verifies both the
+ * instance and systemId.
+ */
+#define OXR_VERIFY_SYSTEM_AND_GET(log, inst, sysId, system)                    \
+	struct oxr_system* system = NULL;                                      \
+	do {                                                                   \
+		XrResult ret = verify_system_id(log, inst, sysId, &system);    \
+		if (ret != XR_SUCCESS) {                                       \
+			return ret;                                            \
+		}                                                              \
+		assert(system != NULL);                                        \
+	} while (false)
+
+/*!
+ * Function that does the actual verifing.
+ */
+static XrResult
+verify_system_id(struct oxr_logger* log,
+                 struct oxr_instance* inst,
+                 XrSystemId systemId,
+                 struct oxr_system** system)
+{
+	if (systemId != 1) {
+		return oxr_error(log, XR_ERROR_SYSTEM_INVALID,
+		                 "invalid system %lu", systemId);
+	}
+
+	*system = &inst->system;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrGetSystem(XrInstance instance,
+                const XrSystemGetInfo* getInfo,
+                XrSystemId* systemId)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst, "xrGetSystem");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, getInfo, XR_TYPE_SYSTEM_GET_INFO);
+	OXR_VERIFY_ARG_NOT_NULL(&log, systemId);
+
+	struct oxr_system* selected = NULL;
+	struct oxr_system* systems[1] = {&inst->system};
+	uint32_t num_systems = 1;
+
+	XrResult ret = oxr_system_select(&log, systems, num_systems,
+	                                 getInfo->formFactor, &selected);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	*systemId = selected->systemId;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_xrGetSystemProperties(XrInstance instance,
+                          XrSystemId systemId,
+                          XrSystemProperties* properties)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetSystemProperties");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, properties,
+	                             XR_TYPE_SYSTEM_PROPERTIES);
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_system_get_properties(&log, sys, properties);
+}
+
+XrResult
+oxr_xrEnumerateViewConfigurations(
+    XrInstance instance,
+    XrSystemId systemId,
+    uint32_t viewConfigurationTypeCapacityInput,
+    uint32_t* viewConfigurationTypeCountOutput,
+    XrViewConfigurationType* viewConfigurationTypes)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrEnumerateViewConfigurations");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_system_enumerate_view_confs(
+	    &log, sys, viewConfigurationTypeCapacityInput,
+	    viewConfigurationTypeCountOutput, viewConfigurationTypes);
+}
+
+XrResult
+oxr_xrEnumerateEnvironmentBlendModes(
+    XrInstance instance,
+    XrSystemId systemId,
+    uint32_t environmentBlendModeCapacityInput,
+    uint32_t* environmentBlendModeCountOutput,
+    XrEnvironmentBlendMode* environmentBlendModes)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrEnumerateEnvironmentBlendModes");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_system_enumerate_blend_modes(
+	    &log, sys, environmentBlendModeCapacityInput,
+	    environmentBlendModeCountOutput, environmentBlendModes);
+}
+
+XrResult
+oxr_xrGetViewConfigurationProperties(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrViewConfigurationType viewConfigurationType,
+    XrViewConfigurationProperties* configurationProperties)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetViewConfigurationProperties");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, configurationProperties,
+	                             XR_TYPE_VIEW_CONFIGURATION_PROPERTIES);
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_system_get_view_conf_properties(
+	    &log, sys, viewConfigurationType, configurationProperties);
+}
+
+XrResult
+oxr_xrEnumerateViewConfigurationViews(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrViewConfigurationType viewConfigurationType,
+    uint32_t viewCapacityInput,
+    uint32_t* viewCountOutput,
+    XrViewConfigurationView* views)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrEnumerateViewConfigurationViews");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_system_enumerate_view_conf_views(
+	    &log, sys, viewConfigurationType, viewCapacityInput,
+	    viewCountOutput, views);
+}
+
+
+/*
+ *
+ * OpenGL
+ *
+ */
+
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+
+XrResult
+oxr_xrGetOpenGLGraphicsRequirementsKHR(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrGraphicsRequirementsOpenGLKHR* graphicsRequirements)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetOpenGLGraphicsRequirementsKHR");
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, graphicsRequirements,
+	                             XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR);
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	struct xrt_api_requirements ver;
+
+	xrt_gfx_gl_get_versions(&ver);
+
+	graphicsRequirements->minApiVersionSupported =
+	    XR_MAKE_VERSION(ver.min_major, ver.min_minor, ver.min_patch);
+	graphicsRequirements->maxApiVersionSupported =
+	    XR_MAKE_VERSION(ver.max_major, ver.max_minor, ver.max_patch);
+
+	return XR_SUCCESS;
+}
+
+#endif
+
+
+/*
+ *
+ * Vulkan
+ *
+ */
+
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+
+XrResult
+oxr_xrGetVulkanInstanceExtensionsKHR(XrInstance instance,
+                                     XrSystemId systemId,
+                                     uint32_t namesCapacityInput,
+                                     uint32_t* namesCountOutput,
+                                     char* namesString)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetVulkanInstanceExtensionsKHR");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_vk_get_instance_exts(&log, sys, namesCapacityInput,
+	                                namesCountOutput, namesString);
+}
+
+XrResult
+oxr_xrGetVulkanDeviceExtensionsKHR(XrInstance instance,
+                                   XrSystemId systemId,
+                                   uint32_t namesCapacityInput,
+                                   uint32_t* namesCountOutput,
+                                   char* namesString)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetVulkanDeviceExtensionsKHR");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+
+	return oxr_vk_get_device_exts(&log, sys, namesCapacityInput,
+	                              namesCountOutput, namesString);
+}
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+vkGetInstanceProcAddr(VkInstance instance, const char* pName);
+
+XrResult
+oxr_xrGetVulkanGraphicsDeviceKHR(XrInstance instance,
+                                 XrSystemId systemId,
+                                 VkInstance vkInstance,
+                                 VkPhysicalDevice* vkPhysicalDevice)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetVulkanGraphicsDeviceKHR");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+	OXR_VERIFY_ARG_NOT_NULL(&log, vkPhysicalDevice);
+
+	return oxr_vk_get_physical_device(&log, inst, sys, vkInstance,
+	                                  vkGetInstanceProcAddr,
+	                                  vkPhysicalDevice);
+}
+
+XrResult
+oxr_xrGetVulkanGraphicsRequirementsKHR(
+    XrInstance instance,
+    XrSystemId systemId,
+    XrGraphicsRequirementsVulkanKHR* graphicsRequirements)
+{
+	struct oxr_instance* inst;
+	struct oxr_logger log;
+	OXR_VERIFY_INSTANCE_AND_INIT_LOG(&log, instance, inst,
+	                                 "xrGetVulkanGraphicsRequirementsKHR");
+	OXR_VERIFY_SYSTEM_AND_GET(&log, inst, systemId, sys);
+	OXR_VERIFY_ARG_TYPE_AND_NULL(&log, graphicsRequirements,
+	                             XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR);
+
+	return oxr_vk_get_requirements(&log, sys, graphicsRequirements);
+}
+
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_api_verify.h b/src/xrt/state_trackers/oxr/oxr_api_verify.h
new file mode 100644
index 000000000..bf0b88865
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_api_verify.h
@@ -0,0 +1,157 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  File for verifing app input into api functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_api
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define _OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, THING, name,       \
+                                     lookup)                                   \
+	do {                                                                   \
+		oxr_log_init(log, name);                                       \
+		if (thing == NULL) {                                           \
+			return oxr_error(log, XR_ERROR_HANDLE_INVALID,         \
+			                 "(" #thing " == NULL)");              \
+		}                                                              \
+		new_thing = (typeof(new_thing))thing;                          \
+		if (new_thing->debug != OXR_XR_DEBUG_##THING) {                \
+			return oxr_error(log, XR_ERROR_HANDLE_INVALID,         \
+			                 "(" #thing " == %p)",                 \
+			                 (void*)new_thing);                    \
+		}                                                              \
+		oxr_log_set_instance(log, lookup);                             \
+	} while (0)
+
+#define _OXR_VERIFY_SET(log, arg, new_arg, THING)                              \
+	do {                                                                   \
+		if (arg == NULL) {                                             \
+			return oxr_error(log, XR_ERROR_HANDLE_INVALID,         \
+			                 "(" #arg " == NULL)");                \
+		}                                                              \
+		new_arg = (typeof(new_arg))arg;                                \
+		if (new_arg->debug != OXR_XR_DEBUG_##THING) {                  \
+			return oxr_error(log, XR_ERROR_HANDLE_INVALID,         \
+			                 "(" #arg " == %p)", (void*)new_arg);  \
+		}                                                              \
+	} while (0)
+
+
+/*!
+ * @ingroup oxr_api
+ * @{
+ */
+
+// clang-format off
+#define OXR_VERIFY_INSTANCE_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, INSTANCE, name, new_thing)
+#define OXR_VERIFY_MESSENGER_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, MESSENGER, name, new_thing->inst)
+#define OXR_VERIFY_SESSION_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, SESSION, name, new_thing->sys->inst)
+#define OXR_VERIFY_SPACE_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, SPACE, name, new_thing->sess->sys->inst)
+#define OXR_VERIFY_ACTION_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, ACTION, name, new_thing->act_set->sess->sys->inst)
+#define OXR_VERIFY_SWAPCHAIN_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, SWAPCHAIN, name, new_thing->sess->sys->inst)
+#define OXR_VERIFY_ACTIONSET_AND_INIT_LOG(log, thing, new_thing, name) \
+	_OXR_VERIFY_AND_SET_AND_INIT(log, thing, new_thing, ACTIONSET, name, new_thing->sess->sys->inst)
+
+#define OXR_VERIFY_INSTANCE_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, INSTANCE);
+#define OXR_VERIFY_MESSENGER_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, MESSENGER);
+#define OXR_VERIFY_SESSION_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, SESSION);
+#define OXR_VERIFY_SPACE_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, SPACE);
+#define OXR_VERIFY_ACTION_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, ACTION);
+#define OXR_VERIFY_SWAPCHAIN_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, SWAPCHAIN);
+#define OXR_VERIFY_ACTIONSET_NOT_NULL(log, arg, new_arg) _OXR_VERIFY_SET(log, arg, new_arg, ACTIONSET);
+// clang-format on
+
+
+#define OXR_VERIFY_ARG_NOT_NULL(log, arg)                                      \
+	do {                                                                   \
+		if (arg == NULL) {                                             \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 "(" #arg " == NULL)");                \
+		}                                                              \
+	} while (false)
+
+#define OXR_VERIFY_ARG_TYPE_AND_NULL(log, arg, type_enum)                      \
+	do {                                                                   \
+		if (arg == NULL) {                                             \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 "(" #arg "== NULL)");                 \
+		}                                                              \
+		if (arg->type != type_enum) {                                  \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 "(" #arg "->type = %u)", arg->type);  \
+		}                                                              \
+		if (arg->next != NULL) {                                       \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 "(" #arg "->next = %p)", arg->next);  \
+		}                                                              \
+	} while (false)
+
+#define OXR_VERIFY_SUBACTION_PATHS(log, count, paths)                          \
+	do {                                                                   \
+		if (count == 0 && paths != NULL) {                             \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 " " #count " is zero but " #paths     \
+			                 " is not NULL");                      \
+		}                                                              \
+		if (count > 0 && paths == NULL) {                              \
+			return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,     \
+			                 " " #count " is not zero but " #paths \
+			                 " is NULL");                          \
+		}                                                              \
+	} while (false)
+
+#define OXR_VERIFY_ARG_SINGLE_LEVEL_FIXED_LENGTH_PATH(log, path)               \
+	do {                                                                   \
+		XrResult verify_ret = oxr_verify_fixed_size_single_level_path( \
+		    log, path, ARRAY_SIZE(path), #path);                       \
+		if (verify_ret != XR_SUCCESS) {                                \
+			return verify_ret;                                     \
+		}                                                              \
+	} while (false)
+
+
+/*
+ *
+ * Implementation in oxr_verify.cpp
+ *
+ */
+
+XrResult
+oxr_verify_fixed_size_single_level_path(struct oxr_logger*,
+                                        const char* path,
+                                        uint32_t size,
+                                        const char* name);
+
+XrResult
+oxr_verify_XrSessionCreateInfo(struct oxr_logger*, const XrSessionCreateInfo*);
+
+XrResult
+oxr_verify_XrGraphicsBindingOpenGLXlibKHR(
+    struct oxr_logger*, const XrGraphicsBindingOpenGLXlibKHR*);
+
+XrResult
+oxr_verify_XrGraphicsBindingVulkanKHR(struct oxr_logger*,
+                                      const XrGraphicsBindingVulkanKHR*);
+
+/*!
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_event.cpp b/src/xrt/state_trackers/oxr/oxr_event.cpp
new file mode 100644
index 000000000..7ba29bf92
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_event.cpp
@@ -0,0 +1,148 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds event related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+
+struct oxr_event
+{
+public:
+	struct oxr_event *next;
+	size_t length;
+
+
+public:
+	inline void *
+	ptr()
+	{
+		return &this[1];
+	}
+};
+
+
+void
+lock(struct oxr_instance *inst)
+{}
+
+void
+unlock(struct oxr_instance *inst)
+{}
+
+struct oxr_event *
+pop(struct oxr_instance *inst)
+{
+	auto ret = inst->next_event;
+	if (ret == NULL) {
+		return NULL;
+	}
+
+	inst->next_event = ret->next;
+	ret->next = NULL;
+
+	if (ret == inst->last_event) {
+		inst->last_event = NULL;
+	}
+
+	return ret;
+}
+
+void
+push(struct oxr_instance *inst, struct oxr_event *event)
+{
+	auto last = inst->last_event;
+	if (last != NULL) {
+		last->next = event;
+	}
+	inst->last_event = event;
+
+	if (inst->next_event == NULL) {
+		inst->next_event = event;
+	}
+}
+
+#define ALLOC(log, inst, event, extra)                                         \
+	do {                                                                   \
+		XrResult ret =                                                 \
+		    oxr_event_alloc(log, inst, sizeof(**extra), event);        \
+		if (ret != XR_SUCCESS) {                                       \
+			return ret;                                            \
+		}                                                              \
+		*extra = (typeof(*extra))(*event)->ptr();                      \
+	} while (false)
+
+static XrResult
+oxr_event_alloc(struct oxr_logger *log,
+                struct oxr_instance *inst,
+                size_t size,
+                struct oxr_event **out_event)
+{
+	struct oxr_event *event =
+	    (struct oxr_event *)calloc(1, sizeof(struct oxr_event) + size);
+
+	if (event == NULL) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " out of memory");
+	}
+
+	event->next = NULL;
+	event->length = size;
+
+	*out_event = event;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_event_push_XrEventDataSessionStateChanged(struct oxr_logger *log,
+                                              struct oxr_session *sess,
+                                              XrSessionState state,
+                                              XrTime time)
+{
+	struct oxr_instance *inst = sess->sys->inst;
+	XrEventDataSessionStateChanged *changed;
+	struct oxr_event *event;
+
+	ALLOC(log, inst, &event, &changed);
+
+	changed->type = XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED;
+	changed->session = oxr_session_to_openxr(sess);
+	changed->state = state;
+	changed->time = time;
+
+	lock(inst);
+	push(inst, event);
+	unlock(inst);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_poll_event(struct oxr_logger *log,
+               struct oxr_instance *inst,
+               XrEventDataBuffer *eventData)
+{
+	lock(inst);
+	auto event = pop(inst);
+	unlock(inst);
+
+	if (event == NULL) {
+		return XR_EVENT_UNAVAILABLE;
+	}
+
+	memcpy(eventData, event->ptr(), event->length);
+	free(event);
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_instance.c b/src/xrt/state_trackers/oxr/oxr_instance.c
new file mode 100644
index 000000000..96d31a093
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_instance.c
@@ -0,0 +1,155 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds session related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "util/u_debug.h"
+#include "util/u_time.h"
+
+#include "xrt/xrt_compiler.h"
+#include "xrt/xrt_prober.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+DEBUG_GET_ONCE_FLOAT_OPTION(lfov_left, "OXR_OVERRIDE_LFOV_LEFT", 0.0f)
+DEBUG_GET_ONCE_FLOAT_OPTION(lfov_right, "OXR_OVERRIDE_LFOV_RIGHT", 0.0f)
+DEBUG_GET_ONCE_FLOAT_OPTION(lfov_up, "OXR_OVERRIDE_LFOV_UP", 0.0f)
+DEBUG_GET_ONCE_FLOAT_OPTION(lfov_down, "OXR_OVERRIDE_LFOV_DOWN", 0.0f)
+
+static inline int32_t
+radtodeg_for_display(float radians)
+{
+	return (int32_t)(radians * 180 * M_1_PI);
+}
+
+XrResult
+oxr_instance_create(struct oxr_logger *log,
+                    const XrInstanceCreateInfo *createInfo,
+                    struct oxr_instance **out_instance)
+{
+	struct oxr_instance *inst =
+	    (struct oxr_instance *)calloc(1, sizeof(struct oxr_instance));
+	inst->debug = OXR_XR_DEBUG_INSTANCE;
+	inst->prober = xrt_create_prober();
+
+	struct xrt_device *dev =
+	    inst->prober->lelo_dallas_autoprobe(inst->prober);
+
+	const float left_override = debug_get_float_option_lfov_left();
+	if (left_override != 0.0f) {
+		printf(
+		    "Overriding left eye angle_left with %f radians (%i°), "
+		    "and right eye angle_right with %f radians (%i°)\n",
+		    left_override, radtodeg_for_display(left_override),
+		    -left_override, radtodeg_for_display(-left_override));
+		dev->views[0].fov.angle_left = left_override;
+		dev->views[1].fov.angle_right = -left_override;
+	}
+
+	const float right_override = debug_get_float_option_lfov_right();
+	if (right_override != 0.0f) {
+		printf(
+		    "Overriding left eye angle_right with %f radians (%i°), "
+		    "and right eye angle_left with %f radians (%i°)\n",
+		    right_override, radtodeg_for_display(right_override),
+		    -right_override, radtodeg_for_display(-right_override));
+		dev->views[0].fov.angle_right = right_override;
+		dev->views[1].fov.angle_left = -right_override;
+	}
+
+	const float up_override = debug_get_float_option_lfov_up();
+	if (up_override != 0.0f) {
+		printf("Overriding both eyes angle_up with %f radians (%i°)\n",
+		       up_override, radtodeg_for_display(up_override));
+		dev->views[0].fov.angle_up = up_override;
+		dev->views[1].fov.angle_up = up_override;
+	}
+
+	const float down_override = debug_get_float_option_lfov_down();
+	if (down_override != 0.0f) {
+		printf(
+		    "Overriding both eyes angle_down with %f radians (%i°)\n",
+		    down_override, radtodeg_for_display(down_override));
+		dev->views[0].fov.angle_down = down_override;
+		dev->views[1].fov.angle_down = down_override;
+	}
+
+	oxr_system_fill_in(log, inst, 1, &inst->system, dev);
+
+	inst->timekeeping = time_state_create();
+
+	//! @todo check if this (and other creates) failed?
+
+	*out_instance = inst;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_instance_destroy(struct oxr_logger *log, struct oxr_instance *inst)
+{
+	struct xrt_prober *prober = inst->prober;
+	struct xrt_device *dev = inst->system.device;
+
+	if (dev != NULL) {
+		dev->destroy(dev);
+		inst->system.device = NULL;
+	}
+
+	if (prober != NULL) {
+		prober->destroy(prober);
+		inst->prober = NULL;
+	}
+
+	time_state_destroy(inst->timekeeping);
+	inst->timekeeping = NULL;
+
+	free(inst);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_instance_get_properties(struct oxr_logger *log,
+                            struct oxr_instance *inst,
+                            XrInstanceProperties *instanceProperties)
+{
+	instanceProperties->runtimeVersion = XR_MAKE_VERSION(0, 0, 42);
+	strncpy(instanceProperties->runtimeName,
+	        "Monado(XRT) by Collabora et al", XR_MAX_RUNTIME_NAME_SIZE - 1);
+
+	return XR_SUCCESS;
+}
+
+#ifdef XR_USE_TIMESPEC
+
+XrResult
+oxr_instance_convert_time_to_timespec(struct oxr_logger *log,
+                                      struct oxr_instance *inst,
+                                      XrTime time,
+                                      struct timespec *timespecTime)
+{
+	time_state_to_timespec(inst->timekeeping, time, timespecTime);
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_instance_convert_timespec_to_time(struct oxr_logger *log,
+                                      struct oxr_instance *inst,
+                                      const struct timespec *timespecTime,
+                                      XrTime *time)
+{
+	*time = time_state_from_timespec(inst->timekeeping, timespecTime);
+	return XR_SUCCESS;
+}
+#endif // XR_USE_TIMESPEC
diff --git a/src/xrt/state_trackers/oxr/oxr_logger.cpp b/src/xrt/state_trackers/oxr/oxr_logger.cpp
new file mode 100644
index 000000000..bf30dc24f
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_logger.cpp
@@ -0,0 +1,158 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Logging functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "xrt/xrt_compiler.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(entrypoints, "OXR_DEBUG_ENTRYPOINTS", false)
+
+static const char *
+oxr_result_to_string(XrResult result);
+
+
+void
+oxr_log_init(struct oxr_logger *logger, const char *api_func_name)
+{
+	if (debug_get_bool_option_entrypoints()) {
+		fprintf(stderr, "%s\n", api_func_name);
+	}
+
+	logger->inst = NULL;
+	logger->api_func_name = api_func_name;
+}
+
+void
+oxr_log_set_instance(struct oxr_logger *logger, struct oxr_instance *inst)
+{
+	logger->inst = inst;
+}
+
+void
+oxr_log(struct oxr_logger *logger, const char *fmt, ...)
+{
+	if (logger->api_func_name != NULL) {
+		fprintf(stderr, " in %s", logger->api_func_name);
+	}
+
+	va_list args;
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	fprintf(stderr, "\n");
+}
+
+void
+oxr_warn(struct oxr_logger *logger, const char *fmt, ...)
+{
+	if (logger->api_func_name != NULL) {
+		fprintf(stderr, "%s WARNING: ", logger->api_func_name);
+	} else {
+		fprintf(stderr, "WARNING: ");
+	}
+
+	va_list args;
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	fprintf(stderr, "\n");
+}
+
+XrResult
+oxr_error(struct oxr_logger *logger, XrResult result, const char *fmt, ...)
+{
+	if (debug_get_bool_option_entrypoints()) {
+		fprintf(stderr, "\t");
+	}
+
+	fprintf(stderr, "%s", oxr_result_to_string(result));
+
+	if (logger->api_func_name != NULL) {
+		fprintf(stderr, " in %s", logger->api_func_name);
+	}
+
+	va_list args;
+	va_start(args, fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	fprintf(stderr, "\n");
+	return result;
+}
+
+static const char *
+oxr_result_to_string(XrResult result)
+{
+	// clang-format off
+	switch (result) {
+	case XR_SUCCESS: return "XR_SUCCESS";
+	case XR_TIMEOUT_EXPIRED: return "XR_TIMEOUT_EXPIRED";
+	case XR_SESSION_VISIBILITY_UNAVAILABLE: return "XR_SESSION_VISIBILITY_UNAVAILABLE";
+	case XR_SESSION_LOSS_PENDING: return "XR_SESSION_LOSS_PENDING";
+	case XR_EVENT_UNAVAILABLE: return "XR_EVENT_UNAVAILABLE";
+	case XR_STATE_UNAVAILABLE: return "XR_STATE_UNAVAILABLE";
+	case XR_STATE_TYPE_UNAVAILABLE: return "XR_STATE_TYPE_UNAVAILABLE";
+	case XR_SPACE_BOUNDS_UNAVAILABLE: return "XR_SPACE_BOUNDS_UNAVAILABLE";
+	case XR_SESSION_NOT_FOCUSED: return "XR_SESSION_NOT_FOCUSED";
+	case XR_FRAME_DISCARDED: return "XR_FRAME_DISCARDED";
+	case XR_ERROR_VALIDATION_FAILURE: return "XR_ERROR_VALIDATION_FAILURE";
+	case XR_ERROR_RUNTIME_FAILURE: return "XR_ERROR_RUNTIME_FAILURE";
+	case XR_ERROR_OUT_OF_MEMORY: return "XR_ERROR_OUT_OF_MEMORY";
+	case XR_ERROR_RUNTIME_VERSION_INCOMPATIBLE: return "XR_ERROR_RUNTIME_VERSION_INCOMPATIBLE";
+	case XR_ERROR_DRIVER_INCOMPATIBLE: return "XR_ERROR_DRIVER_INCOMPATIBLE";
+	case XR_ERROR_INITIALIZATION_FAILED: return "XR_ERROR_INITIALIZATION_FAILED";
+	case XR_ERROR_FUNCTION_UNSUPPORTED: return "XR_ERROR_FUNCTION_UNSUPPORTED";
+	case XR_ERROR_FEATURE_UNSUPPORTED: return "XR_ERROR_FEATURE_UNSUPPORTED";
+	case XR_ERROR_EXTENSION_NOT_PRESENT: return "XR_ERROR_EXTENSION_NOT_PRESENT";
+	case XR_ERROR_LIMIT_REACHED: return "XR_ERROR_LIMIT_REACHED";
+	case XR_ERROR_SIZE_INSUFFICIENT: return "XR_ERROR_SIZE_INSUFFICIENT";
+	case XR_ERROR_HANDLE_INVALID: return "XR_ERROR_HANDLE_INVALID";
+	case XR_ERROR_INSTANCE_LOST: return "XR_ERROR_INSTANCE_LOST";
+	case XR_ERROR_SESSION_RUNNING: return "XR_ERROR_SESSION_RUNNING";
+	case XR_ERROR_SESSION_NOT_RUNNING: return "XR_ERROR_SESSION_NOT_RUNNING";
+	case XR_ERROR_SESSION_LOST: return "XR_ERROR_SESSION_LOST";
+	case XR_ERROR_SYSTEM_INVALID: return "XR_ERROR_SYSTEM_INVALID";
+	case XR_ERROR_PATH_INVALID: return "XR_ERROR_PATH_INVALID";
+	case XR_ERROR_PATH_COUNT_EXCEEDED: return "XR_ERROR_PATH_COUNT_EXCEEDED";
+	case XR_ERROR_PATH_FORMAT_INVALID: return "XR_ERROR_PATH_FORMAT_INVALID";
+	case XR_ERROR_LAYER_INVALID: return "XR_ERROR_LAYER_INVALID";
+	case XR_ERROR_LAYER_LIMIT_EXCEEDED: return "XR_ERROR_LAYER_LIMIT_EXCEEDED";
+	case XR_ERROR_SWAPCHAIN_RECT_INVALID: return "XR_ERROR_SWAPCHAIN_RECT_INVALID";
+	case XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED: return "XR_ERROR_SWAPCHAIN_FORMAT_UNSUPPORTED";
+	case XR_ERROR_ACTION_TYPE_MISMATCH: return "XR_ERROR_ACTION_TYPE_MISMATCH";
+	case XR_ERROR_REFERENCE_SPACE_UNSUPPORTED: return "XR_ERROR_REFERENCE_SPACE_UNSUPPORTED";
+	case XR_ERROR_FILE_ACCESS_ERROR: return "XR_ERROR_FILE_ACCESS_ERROR";
+	case XR_ERROR_FILE_CONTENTS_INVALID: return "XR_ERROR_FILE_CONTENTS_INVALID";
+	case XR_ERROR_FORM_FACTOR_UNSUPPORTED: return "XR_ERROR_FORM_FACTOR_UNSUPPORTED";
+	case XR_ERROR_FORM_FACTOR_UNAVAILABLE: return "XR_ERROR_FORM_FACTOR_UNAVAILABLE";
+	case XR_ERROR_API_LAYER_NOT_PRESENT: return "XR_ERROR_API_LAYER_NOT_PRESENT";
+	case XR_ERROR_CALL_ORDER_INVALID: return "XR_ERROR_CALL_ORDER_INVALID";
+	case XR_ERROR_GRAPHICS_DEVICE_INVALID: return "XR_ERROR_GRAPHICS_DEVICE_INVALID";
+	case XR_ERROR_POSE_INVALID: return "XR_ERROR_POSE_INVALID";
+	case XR_ERROR_INDEX_OUT_OF_RANGE: return "XR_ERROR_INDEX_OUT_OF_RANGE";
+	case XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED: return "XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED";
+	case XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED: return "XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED";
+	case XR_ERROR_BINDINGS_DUPLICATED: return "XR_ERROR_BINDINGS_DUPLICATED";
+	case XR_ERROR_NAME_DUPLICATED: return "XR_ERROR_NAME_DUPLICATED";
+	case XR_ERROR_NAME_INVALID: return "XR_ERROR_NAME_INVALID";
+	case XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR: return "XR_ERROR_ANDROID_THREAD_SETTINGS_ID_INVALID_KHR";
+	case XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR: return "XR_ERROR_ANDROID_THREAD_SETTINGS_FAILURE_KHR";
+	case XR_ERROR_DEBUG_UTILS_MESSENGER_INVALID_EXT: return "XR_ERROR_DEBUG_UTILS_MESSENGER_INVALID_EXT";
+	default: return "<UNKNOWN>";
+	}
+	// clang-format on
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_logger.h b/src/xrt/state_trackers/oxr/oxr_logger.h
new file mode 100644
index 000000000..b955cb639
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_logger.h
@@ -0,0 +1,69 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Logging functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * Helper macro to log a warning just once.
+ *
+ * @ingroup oxr_main
+ */
+#define OXR_WARN_ONCE(log, ...)                                                \
+	do {                                                                   \
+		static bool _once = false;                                     \
+		if (!_once) {                                                  \
+			_once = true;                                          \
+			oxr_warn(log, __VA_ARGS__);                            \
+		}                                                              \
+	} while (false)
+
+/*!
+ * Logger struct that lives on the stack, one for each call client call.
+ *
+ * @ingroup oxr_main
+ */
+struct oxr_logger
+{
+	struct oxr_instance *inst;
+	const char *api_func_name;
+};
+
+
+/*!
+ * @ingroup oxr_main
+ * @{
+ */
+
+void
+oxr_log_init(struct oxr_logger *logger, const char *api_func_name);
+void
+oxr_log_set_instance(struct oxr_logger *logger, struct oxr_instance *inst);
+void
+oxr_log(struct oxr_logger *logger, const char *fmt, ...)
+    XRT_PRINTF_FORMAT(2, 3);
+void
+oxr_warn(struct oxr_logger *logger, const char *fmt, ...)
+    XRT_PRINTF_FORMAT(2, 3);
+XrResult
+oxr_error(struct oxr_logger *logger, XrResult result, const char *fmt, ...)
+    XRT_PRINTF_FORMAT(3, 4);
+
+/*!
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_objects.h b/src/xrt/state_trackers/oxr/oxr_objects.h
new file mode 100644
index 000000000..815df7f72
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_objects.h
@@ -0,0 +1,585 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Contains the instance struct that a lot of things hangs of on.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#pragma once
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_compositor.h"
+#include "xrt/xrt_vulkan_includes.h"
+#include "xrt/xrt_openxr_includes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @defgroup oxr OpenXR state tracker
+ *
+ * Client application facing code.
+ *
+ * @ingroup xrt
+ */
+
+/*!
+ * @defgroup oxr_main OpenXR main code
+ *
+ * Gets called from @ref oxr_api functions and talks to devices and
+ * @ref comp using @ref xrt_iface.
+ *
+ * @ingroup oxr
+ * @{
+ */
+
+// For corruption and layer checking.
+// clang-format off
+#define OXR_XR_DEBUG_INSTANCE  (*(uint64_t *)"oxrinst\0")
+#define OXR_XR_DEBUG_SESSION   (*(uint64_t *)"oxrsess\0")
+#define OXR_XR_DEBUG_SPACE     (*(uint64_t *)"oxrspac\0")
+#define OXR_XR_DEBUG_ACTION    (*(uint64_t *)"oxracti\0")
+#define OXR_XR_DEBUG_SWAPCHAIN (*(uint64_t *)"oxrswap\0")
+#define OXR_XR_DEBUG_ACTIONSET (*(uint64_t *)"oxraset\0")
+#define OXR_XR_DEBUG_MESSENGER (*(uint64_t *)"oxrmess\0")
+// clang-format on
+
+
+/*
+ *
+ * Forward declare structs.
+ *
+ */
+
+struct oxr_logger;
+struct oxr_instance;
+struct oxr_system;
+struct oxr_session;
+struct oxr_event;
+struct oxr_swapchain;
+struct oxr_space;
+struct oxr_action_set;
+struct oxr_action;
+struct time_state;
+
+
+/*
+ *
+ * oxr_instance.c
+ *
+ */
+
+/*!
+ * To go back to a OpenXR object.
+ */
+XRT_MAYBE_UNUSED static inline XrInstance
+oxr_instance_to_openxr(struct oxr_instance *inst)
+{
+	return (XrInstance)inst;
+}
+
+XrResult
+oxr_instance_create(struct oxr_logger *log,
+                    const XrInstanceCreateInfo *createInfo,
+                    struct oxr_instance **out_inst);
+
+XrResult
+oxr_instance_destroy(struct oxr_logger *log, struct oxr_instance *inst);
+
+XrResult
+oxr_instance_get_properties(struct oxr_logger *log,
+                            struct oxr_instance *inst,
+                            XrInstanceProperties *instanceProperties);
+
+#if XR_USE_TIMESPEC
+
+XrResult
+oxr_instance_convert_time_to_timespec(struct oxr_logger *log,
+                                      struct oxr_instance *inst,
+                                      XrTime time,
+                                      struct timespec *timespecTime);
+XrResult
+oxr_instance_convert_timespec_to_time(struct oxr_logger *log,
+                                      struct oxr_instance *inst,
+                                      const struct timespec *timespecTime,
+                                      XrTime *time);
+#endif // XR_USE_TIMESPEC
+
+/*
+ *
+ * oxr_session.c
+ *
+ */
+
+/*!
+ * To go back to a OpenXR object.
+ */
+XRT_MAYBE_UNUSED static inline XrSession
+oxr_session_to_openxr(struct oxr_session *sess)
+{
+	return (XrSession)sess;
+}
+
+XrResult
+oxr_session_create(struct oxr_logger *log,
+                   struct oxr_system *sys,
+                   XrStructureType *next,
+                   struct oxr_session **out_session);
+
+XrResult
+oxr_session_destroy(struct oxr_logger *log, struct oxr_session *sess);
+
+XrResult
+oxr_session_enumerate_formats(struct oxr_logger *log,
+                              struct oxr_session *sess,
+                              uint32_t formatCapacityInput,
+                              uint32_t *formatCountOutput,
+                              int64_t *formats);
+
+XrResult
+oxr_session_begin(struct oxr_logger *log,
+                  struct oxr_session *sess,
+                  const XrSessionBeginInfo *beginInfo);
+
+XrResult
+oxr_session_end(struct oxr_logger *log, struct oxr_session *sess);
+
+/*!
+ * Get the view space position at the given time in relation to the
+ * local or stage space.
+ */
+XrResult
+oxr_session_get_view_pose_at(struct oxr_logger *,
+                             struct oxr_session *sess,
+                             XrTime at_time,
+                             struct xrt_pose *);
+
+XrResult
+oxr_session_views(struct oxr_logger *log,
+                  struct oxr_session *sess,
+                  const XrViewLocateInfo *viewLocateInfo,
+                  XrViewState *viewState,
+                  uint32_t viewCapacityInput,
+                  uint32_t *viewCountOutput,
+                  XrView *views);
+
+XrResult
+oxr_session_frame_wait(struct oxr_logger *log,
+                       struct oxr_session *sess,
+                       XrFrameState *frameState);
+
+XrResult
+oxr_session_frame_begin(struct oxr_logger *log, struct oxr_session *sess);
+
+XrResult
+oxr_session_frame_end(struct oxr_logger *log,
+                      struct oxr_session *sess,
+                      const XrFrameEndInfo *frameEndInfo);
+
+
+/*
+ *
+ * oxr_space.c
+ *
+ */
+
+/*!
+ * To go back to a OpenXR object.
+ */
+XRT_MAYBE_UNUSED static inline XrSpace
+oxr_space_to_openxr(struct oxr_space *spc)
+{
+	return (XrSpace)spc;
+}
+
+XrResult
+oxr_space_reference_create(struct oxr_logger *log,
+                           struct oxr_session *sess,
+                           const XrReferenceSpaceCreateInfo *createInfo,
+                           struct oxr_space **out_space);
+
+XrResult
+oxr_space_destroy(struct oxr_logger *log, struct oxr_space *spc);
+
+XrResult
+oxr_space_locate(struct oxr_logger *log,
+                 struct oxr_space *spc,
+                 struct oxr_space *baseSpc,
+                 XrTime time,
+                 XrSpaceRelation *relation);
+
+XrResult
+oxr_space_ref_relation(struct oxr_logger *log,
+                       struct oxr_session *sess,
+                       XrReferenceSpaceType space,
+                       XrReferenceSpaceType baseSpc,
+                       XrTime time,
+                       struct xrt_space_relation *out_relation);
+
+
+/*
+ *
+ * oxr_swapchain.c
+ *
+ */
+
+/*!
+ * To go back to a OpenXR object.
+ */
+XRT_MAYBE_UNUSED static inline XrSwapchain
+oxr_swapchain_to_openxr(struct oxr_swapchain *sc)
+{
+	return (XrSwapchain)sc;
+}
+
+XrResult
+oxr_create_swapchain(struct oxr_logger *,
+                     struct oxr_session *sess,
+                     const XrSwapchainCreateInfo *,
+                     struct oxr_swapchain **sc);
+
+
+/*
+ *
+ * oxr_system.c
+ *
+ */
+
+XrResult
+oxr_system_select(struct oxr_logger *log,
+                  struct oxr_system **systems,
+                  uint32_t num_systems,
+                  XrFormFactor form_factor,
+                  struct oxr_system **out_selected);
+
+XrResult
+oxr_system_fill_in(struct oxr_logger *log,
+                   struct oxr_instance *inst,
+                   XrSystemId systemId,
+                   struct oxr_system *sys,
+                   struct xrt_device *dev);
+
+XrResult
+oxr_system_get_properties(struct oxr_logger *log,
+                          struct oxr_system *sys,
+                          XrSystemProperties *properties);
+
+XrResult
+oxr_system_enumerate_view_confs(
+    struct oxr_logger *log,
+    struct oxr_system *sys,
+    uint32_t viewConfigurationTypeCapacityInput,
+    uint32_t *viewConfigurationTypeCountOutput,
+    XrViewConfigurationType *viewConfigurationTypes);
+
+XrResult
+oxr_system_enumerate_blend_modes(struct oxr_logger *log,
+                                 struct oxr_system *sys,
+                                 uint32_t environmentBlendModeCapacityInput,
+                                 uint32_t *environmentBlendModeCountOutput,
+                                 XrEnvironmentBlendMode *environmentBlendModes);
+
+XrResult
+oxr_system_get_view_conf_properties(
+    struct oxr_logger *log,
+    struct oxr_system *sys,
+    XrViewConfigurationType viewConfigurationType,
+    XrViewConfigurationProperties *configurationProperties);
+
+XrResult
+oxr_system_enumerate_view_conf_views(
+    struct oxr_logger *log,
+    struct oxr_system *sys,
+    XrViewConfigurationType viewConfigurationType,
+    uint32_t viewCapacityInput,
+    uint32_t *viewCountOutput,
+    XrViewConfigurationView *views);
+
+
+/*
+ *
+ * oxr_event.cpp
+ *
+ */
+
+XrResult
+oxr_poll_event(struct oxr_logger *log,
+               struct oxr_instance *inst,
+               XrEventDataBuffer *eventData);
+
+XrResult
+oxr_event_push_XrEventDataSessionStateChanged(struct oxr_logger *log,
+                                              struct oxr_session *sess,
+                                              XrSessionState state,
+                                              XrTime time);
+
+
+/*
+ *
+ * OpenGL, located in various files.
+ *
+ */
+
+#ifdef XR_USE_GRAPHICS_API_OPENGL
+#ifdef XR_USE_PLATFORM_XLIB
+
+XrResult
+oxr_session_create_gl_xlib(struct oxr_logger *log,
+                           struct oxr_system *sys,
+                           XrGraphicsBindingOpenGLXlibKHR *next,
+                           struct oxr_session **out_session);
+#endif
+
+XrResult
+oxr_swapchain_gl_create(struct oxr_logger *,
+                        struct oxr_session *sess,
+                        const XrSwapchainCreateInfo *,
+                        struct oxr_swapchain **out_swapchain);
+
+#endif
+
+
+/*
+ *
+ * Vulkan, located in various files.
+ *
+ */
+
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+
+XrResult
+oxr_vk_get_instance_exts(struct oxr_logger *log,
+                         struct oxr_system *sys,
+                         uint32_t namesCapacityInput,
+                         uint32_t *namesCountOutput,
+                         char *namesString);
+
+XrResult
+oxr_vk_get_device_exts(struct oxr_logger *log,
+                       struct oxr_system *sys,
+                       uint32_t namesCapacityInput,
+                       uint32_t *namesCountOutput,
+                       char *namesString);
+
+XrResult
+oxr_vk_get_requirements(struct oxr_logger *log,
+                        struct oxr_system *sys,
+                        XrGraphicsRequirementsVulkanKHR *graphicsRequirements);
+
+XrResult
+oxr_vk_get_physical_device(struct oxr_logger *log,
+                           struct oxr_instance *inst,
+                           struct oxr_system *sys,
+                           VkInstance vkInstance,
+                           PFN_vkGetInstanceProcAddr getProc,
+                           VkPhysicalDevice *vkPhysicalDevice);
+
+XrResult
+oxr_session_create_vk(struct oxr_logger *log,
+                      struct oxr_system *sys,
+                      XrGraphicsBindingVulkanKHR *next,
+                      struct oxr_session **out_session);
+
+XrResult
+oxr_swapchain_vk_create(struct oxr_logger *,
+                        struct oxr_session *sess,
+                        const XrSwapchainCreateInfo *,
+                        struct oxr_swapchain **out_swapchain);
+
+#endif
+
+
+/*
+ *
+ * Structs
+ *
+ */
+
+/*!
+ * Single or multiple devices grouped together to form a system that sessions
+ * can be created from. Might need to open devices in order to get all
+ * properties from it, but shouldn't.
+ *
+ * @obj{XrSystemId}
+ */
+struct oxr_system
+{
+	struct oxr_instance *inst;
+	struct xrt_device *device;
+	XrSystemId systemId;
+
+	XrFormFactor form_factor;
+	XrViewConfigurationType view_config_type;
+	XrViewConfigurationView views[2];
+	uint32_t num_blend_modes;
+	XrEnvironmentBlendMode blend_modes[3];
+};
+
+/*!
+ * Main object that ties everything together.
+ *
+ * @obj{XrInstance}
+ */
+struct oxr_instance
+{
+	uint64_t debug;
+	struct xrt_prober *prober;
+
+	// Hardcoded single system.
+	struct oxr_system system;
+
+	struct time_state *timekeeping;
+
+	// Event queue.
+	struct oxr_event *last_event;
+	struct oxr_event *next_event;
+};
+
+/*!
+ * Object that client program interact with.
+ *
+ * @obj{XrSession}
+ */
+struct oxr_session
+{
+	uint64_t debug;
+	struct oxr_system *sys;
+	struct xrt_compositor *compositor;
+
+	XrSessionState state;
+	bool frame_started;
+
+	/*!
+	 * IPD, to be expanded to a proper 3D relation.
+	 */
+	float ipd_meters;
+
+	uint64_t nominal_frame_interval_ns;
+	float static_prediction_s;
+
+	/*!
+	 * To pipe swapchain creation to right code.
+	 */
+	XrResult (*create_swapchain)(struct oxr_logger *,
+	                             struct oxr_session *sess,
+	                             const XrSwapchainCreateInfo *,
+	                             struct oxr_swapchain **);
+};
+
+/*!
+ * Can be one of 3 references or a space that are bound to actions.
+ *
+ * @obj{XrSpace}
+ */
+struct oxr_space
+{
+	//! Magic value for debugging.
+	uint64_t debug;
+
+	//! Onwer of this space.
+	struct oxr_session *sess;
+
+	//! Pose that was given during creation.
+	struct xrt_pose pose;
+
+	//! What kind of reference space is this, if any.
+	XrReferenceSpaceType type;
+
+	//! Is this a reference space?
+	bool is_reference;
+};
+
+/*!
+ * A set of images used for rendering.
+ *
+ * @obj{XrSwapchain}
+ */
+struct oxr_swapchain
+{
+	//! Magic value for debugging.
+	uint64_t debug;
+
+	//! Onwer of this swapchain.
+	struct oxr_session *sess;
+
+	//! Compositor swapchain.
+	struct xrt_swapchain *swapchain;
+
+	//! Actual state tracked! :D
+	int acquired_index;
+
+	XrResult (*destroy)(struct oxr_logger *, struct oxr_swapchain *);
+
+	XrResult (*enumerate_images)(struct oxr_logger *,
+	                             struct oxr_swapchain *,
+	                             uint32_t,
+	                             XrSwapchainImageBaseHeader *);
+
+	XrResult (*acquire_image)(struct oxr_logger *,
+	                          struct oxr_swapchain *,
+	                          const XrSwapchainImageAcquireInfo *,
+	                          uint32_t *);
+
+	XrResult (*wait_image)(struct oxr_logger *,
+	                       struct oxr_swapchain *,
+	                       const XrSwapchainImageWaitInfo *);
+
+	XrResult (*release_image)(struct oxr_logger *,
+	                          struct oxr_swapchain *,
+	                          const XrSwapchainImageReleaseInfo *);
+};
+
+/*!
+ * A group of actions.
+ *
+ * @obj{XrActionSet}
+ */
+struct oxr_action_set
+{
+	//! Magic value for debugging.
+	uint64_t debug;
+
+	//! Onwer of this messenger.
+	struct oxr_session *sess;
+};
+
+/*!
+ * A single action.
+ *
+ * @obj{XrAction}
+ */
+struct oxr_action
+{
+	//! Magic value for debugging.
+	uint64_t debug;
+
+	//! Onwer of this messenger.
+	struct oxr_action_set *act_set;
+};
+
+/*!
+ * Debug object created by the client program.
+ *
+ * @obj{XrDebugUtilsMessengerEXT}
+ */
+struct oxr_debug_messenger
+{
+	//! Magic value for debugging.
+	uint64_t debug;
+
+	//! Onwer of this messenger.
+	struct oxr_instance *inst;
+};
+
+/*!
+ * @}
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_session.c b/src/xrt/state_trackers/oxr/oxr_session.c
new file mode 100644
index 000000000..7babcae4a
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_session.c
@@ -0,0 +1,498 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds session related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util/u_debug.h"
+#include "math/m_api.h"
+#include "util/u_time.h"
+
+#include "xrt/xrt_device.h"
+#include "xrt/xrt_gfx_xlib.h"
+#include "xrt/xrt_gfx_vk.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(views, "OXR_DEBUG_VIEWS", false)
+DEBUG_GET_ONCE_NUM_OPTION(ipd, "OXR_DEBUG_IPD_MM", 63)
+DEBUG_GET_ONCE_NUM_OPTION(prediction_ms, "OXR_DEBUG_PREDICTION_MS", 11)
+
+static bool
+is_running(XrSessionState state)
+{
+	switch (state) {
+	case XR_SESSION_STATE_RUNNING: return true;
+	case XR_SESSION_STATE_VISIBLE: return true;
+	case XR_SESSION_STATE_FOCUSED: return true;
+	default: return false;
+	}
+}
+
+XrResult
+oxr_session_enumerate_formats(struct oxr_logger *log,
+                              struct oxr_session *sess,
+                              uint32_t formatCapacityInput,
+                              uint32_t *formatCountOutput,
+                              int64_t *formats)
+{
+	struct xrt_compositor *xc = sess->compositor;
+
+	OXR_TWO_CALL_HELPER(log, formatCapacityInput, formatCountOutput,
+	                    formats, xc->num_formats, xc->formats);
+}
+
+XrResult
+oxr_session_begin(struct oxr_logger *log,
+                  struct oxr_session *sess,
+                  const XrSessionBeginInfo *beginInfo)
+{
+	if (is_running(sess->state)) {
+		return oxr_error(log, XR_ERROR_SESSION_RUNNING,
+		                 " session is already running");
+	}
+
+	struct xrt_compositor *xc = sess->compositor;
+	xc->begin_session(
+	    xc, (enum xrt_view_type)beginInfo->primaryViewConfigurationType);
+
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_RUNNING, 0);
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_VISIBLE, 0);
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_FOCUSED, 0);
+
+	sess->state = XR_SESSION_STATE_FOCUSED;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_session_end(struct oxr_logger *log, struct oxr_session *sess)
+{
+	struct xrt_compositor *xc = sess->compositor;
+
+	if (!is_running(sess->state)) {
+		return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING,
+		                 " session is not running");
+	}
+
+	if (sess->frame_started) {
+		xc->discard_frame(xc);
+		sess->frame_started = false;
+	}
+
+	xc->end_session(xc);
+
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_STOPPING, 0);
+	oxr_event_push_XrEventDataSessionStateChanged(log, sess,
+	                                              XR_SESSION_STATE_IDLE, 0);
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_READY, 0);
+
+	sess->state = XR_SESSION_STATE_READY;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_session_get_view_pose_at(struct oxr_logger *log,
+                             struct oxr_session *sess,
+                             XrTime at_time,
+                             struct xrt_pose *pose)
+{
+	// @todo This function needs to be massively expanded to support all
+	//       use cases this drive. The main use of this function is to get
+	//       either the predicted position of the headset device. Right now
+	//       it only returns the current position. But it must also deal
+	//       with past values are allowed by the spec. See displayTime
+	//       argument on the xrLocateViews function. It will also drive
+	//       the function xrLocateSpace view using the view space.
+	// @todo If using orientation tracking only implement a neck model to
+	//       get at least a slightly better position.
+
+	struct xrt_device *xdev = sess->sys->device;
+	struct xrt_space_relation relation;
+	xdev->get_tracked_pose(xdev, &relation);
+	if ((relation.relation_flags &
+	     XRT_SPACE_RELATION_ORIENTATION_VALID_BIT) != 0) {
+		pose->orientation = relation.pose.orientation;
+	} else {
+		pose->orientation.x = 0;
+		pose->orientation.y = 0;
+		pose->orientation.z = 0;
+		pose->orientation.w = 1;
+	}
+	if ((relation.relation_flags & XRT_SPACE_RELATION_POSITION_VALID_BIT) !=
+	    0) {
+		pose->position = relation.pose.position;
+	} else {
+		// "nominal height" 1.6m
+		pose->position.x = 0.0f;
+		pose->position.y = 1.60f;
+		pose->position.z = 0.0f;
+	}
+
+	if ((relation.relation_flags &
+	     XRT_SPACE_RELATION_ANGULAR_VELOCITY_VALID_BIT) != 0) {
+		//! @todo Forcing a fixed amount of prediction for now since
+		//! devices don't tell us timestamps yet.
+		struct xrt_quat predicted;
+		math_quat_integrate_velocity(
+		    &pose->orientation, &relation.angular_velocity,
+		    sess->static_prediction_s, &predicted);
+		if (debug_get_bool_option_views()) {
+
+			fprintf(
+			    stderr,
+			    "\toriginal quat = {%f, %f, %f, %f}  predicted = "
+			    "{%f, %f, %f, %f}\n",
+			    pose->orientation.x, pose->orientation.y,
+			    pose->orientation.z, pose->orientation.w,
+			    predicted.x, predicted.y, predicted.z, predicted.w);
+		}
+		pose->orientation = predicted;
+	}
+
+	return XR_SUCCESS;
+}
+
+void
+print_view_fov(uint32_t index, const struct xrt_fov *fov)
+{
+	if (!debug_get_bool_option_views()) {
+		return;
+	}
+
+	fprintf(stderr, "\tviews[%i].fov = {%f, %f, %f, %f}\n", index,
+	        fov->angle_left, fov->angle_right, fov->angle_up,
+	        fov->angle_down);
+}
+
+void
+print_view_pose(uint32_t index, const struct xrt_pose *pose)
+{
+	if (!debug_get_bool_option_views()) {
+		return;
+	}
+
+	fprintf(stderr, "\tviews[%i].pose = {{%f, %f, %f, %f}, {%f, %f, %f}}\n",
+	        index, pose->orientation.x, pose->orientation.y,
+	        pose->orientation.z, pose->orientation.w, pose->position.x,
+	        pose->position.y, pose->position.z);
+}
+
+
+XrResult
+oxr_session_views(struct oxr_logger *log,
+                  struct oxr_session *sess,
+                  const XrViewLocateInfo *viewLocateInfo,
+                  XrViewState *viewState,
+                  uint32_t viewCapacityInput,
+                  uint32_t *viewCountOutput,
+                  XrView *views)
+{
+	struct xrt_device *xdev = sess->sys->device;
+	struct oxr_space *baseSpc = (struct oxr_space *)viewLocateInfo->space;
+	uint32_t num_views = 2;
+
+	// Does this apply for all calls?
+	if (!baseSpc->is_reference) {
+		viewState->viewStateFlags = 0;
+		return XR_SUCCESS;
+	}
+
+	// Start two call handling.
+	if (viewCountOutput != NULL) {
+		*viewCountOutput = num_views;
+	}
+	if (viewCapacityInput == 0) {
+		return XR_SUCCESS;
+	}
+	if (viewCapacityInput < num_views) {
+		return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT,
+		                 "(viewCapacityInput == %u) need %u",
+		                 viewCapacityInput, num_views);
+	}
+	// End two call handling.
+
+	if (debug_get_bool_option_views()) {
+		fprintf(stderr, "%s\n", __func__);
+		fprintf(stderr, "\tviewLocateInfo->displayTime %lu\n",
+		        viewLocateInfo->displayTime);
+	}
+
+	// Get the viewLocateInfo->space to view space relation.
+	struct xrt_space_relation pure_relation;
+	oxr_space_ref_relation(log, sess, XR_REFERENCE_SPACE_TYPE_VIEW,
+	                       baseSpc->type, viewLocateInfo->displayTime,
+	                       &pure_relation);
+
+	struct xrt_pose pure = pure_relation.pose;
+
+	// @todo the fov information that we get from xdev->views[i].fov is not
+	//       properly filled out in oh_device.c, fix before wasting time on
+	//       debugging weird rendering when adding stuff here.
+
+	for (uint32_t i = 0; i < num_views; i++) {
+		//! @todo Do not hardcode IPD.
+		struct xrt_vec3 eye_relation = {
+		    sess->ipd_meters,
+		    0.0f,
+		    0.0f,
+		};
+		struct xrt_pose view_pose;
+
+		// Get the per view pose from the device.
+		xdev->get_view_pose(xdev, &eye_relation, i, &view_pose);
+
+		// Do the magical space relation dance here.
+		math_pose_openxr_locate(&view_pose, &pure, &baseSpc->pose,
+		                        (struct xrt_pose *)&views[i].pose);
+
+		// Copy the fov information directly from the device.
+		views[i].fov = *(XrFovf *)&xdev->views[i].fov;
+
+		print_view_fov(i, (struct xrt_fov *)&views[i].fov);
+		print_view_pose(i, (struct xrt_pose *)&views[i].pose);
+	}
+
+	// @todo Add tracking bit once we have them.
+	viewState->viewStateFlags = 0;
+	viewState->viewStateFlags |= XR_VIEW_STATE_POSITION_VALID_BIT;
+	viewState->viewStateFlags |= XR_VIEW_STATE_ORIENTATION_VALID_BIT;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_session_frame_wait(struct oxr_logger *log,
+                       struct oxr_session *sess,
+                       XrFrameState *frameState)
+{
+	if (!is_running(sess->state)) {
+		return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING,
+		                 " session is not running");
+	}
+
+	// OK to update this here because xrWaitFrame must be externally
+	// synchronized by the app.
+	timepoint_ns now =
+	    time_state_get_now_and_update(sess->sys->inst->timekeeping);
+
+	// Set defaults - may be overridden by compositor.
+	frameState->predictedDisplayPeriod = sess->nominal_frame_interval_ns;
+	frameState->predictedDisplayTime =
+	    now + frameState->predictedDisplayPeriod;
+
+	struct xrt_compositor *xc = sess->compositor;
+	xc->wait_frame(xc, &frameState->predictedDisplayTime,
+	               &frameState->predictedDisplayPeriod);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_session_frame_begin(struct oxr_logger *log, struct oxr_session *sess)
+{
+	if (!is_running(sess->state)) {
+		return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING,
+		                 " session is not running");
+	}
+
+	struct xrt_compositor *xc = sess->compositor;
+
+	XrResult ret;
+	if (sess->frame_started) {
+		ret = XR_FRAME_DISCARDED;
+		xc->discard_frame(xc);
+	} else {
+		ret = XR_SUCCESS;
+		sess->frame_started = true;
+	}
+
+	xc->begin_frame(xc);
+
+	return ret;
+}
+
+static enum xrt_blend_mode
+oxr_blend_mode_to_xrt(XrEnvironmentBlendMode blend_mode)
+{
+	// clang-format off
+	switch (blend_mode) {
+	case XR_ENVIRONMENT_BLEND_MODE_OPAQUE: return XRT_BLEND_MODE_OPAQUE;
+	case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE: return XRT_BLEND_MODE_ADDITIVE;
+	case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND: return XRT_BLEND_MODE_ALPHA_BLEND;
+	default: return (enum xrt_blend_mode)0;
+	}
+	// clang-format on
+}
+
+XrResult
+oxr_session_frame_end(struct oxr_logger *log,
+                      struct oxr_session *sess,
+                      const XrFrameEndInfo *frameEndInfo)
+{
+	/*
+	 * Session state and call order.
+	 */
+
+	if (!is_running(sess->state)) {
+		return oxr_error(log, XR_ERROR_SESSION_NOT_RUNNING,
+		                 " session is not running");
+	}
+	if (!sess->frame_started) {
+		return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID,
+		                 " frame not begun with xrBeginFrame");
+	}
+
+	struct xrt_compositor *xc = sess->compositor;
+
+	/*
+	 * Early out for discarded frame if layer count is 0,
+	 * since then blend mode, etc. doesn't matter.
+	 */
+	if (frameEndInfo->layerCount == 0) {
+		xc->discard_frame(xc);
+		sess->frame_started = false;
+
+		return XR_SUCCESS;
+	}
+
+	/*
+	 * Blend mode.
+	 */
+
+	enum xrt_blend_mode blend_mode =
+	    oxr_blend_mode_to_xrt(frameEndInfo->environmentBlendMode);
+
+	if (blend_mode == 0) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(frameEndInfo->environmentBlendMode) "
+		                 "unknown environment blend mode");
+	}
+
+	if ((blend_mode & sess->sys->device->blend_mode) == 0) {
+		return oxr_error(log,
+		                 XR_ERROR_ENVIRONMENT_BLEND_MODE_UNSUPPORTED,
+		                 "(frameEndInfo->environmentBlendMode) "
+		                 "is not supported");
+	}
+
+
+	/*
+	 * Layers.
+	 */
+
+	if (frameEndInfo->layers == NULL) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(frameEndInfo->layers == NULL)");
+	}
+	if (frameEndInfo->layers[0]->type !=
+	    XR_TYPE_COMPOSITION_LAYER_PROJECTION) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(frameEndInfo->layers[0]->type)");
+	}
+
+	XrCompositionLayerProjection *proj =
+	    (XrCompositionLayerProjection *)frameEndInfo->layers[0];
+
+	if (proj->viewCount != 2) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(frameEndInfo->layers[0]->viewCount == %u)"
+		                 " must be 2",
+		                 proj->viewCount);
+	}
+
+
+	/*
+	 * Doing the real work.
+	 */
+
+	struct xrt_swapchain *chains[2];
+	uint32_t acquired_index[2];
+	uint32_t num_chains = ARRAY_SIZE(chains);
+
+	for (uint32_t i = 0; i < num_chains; i++) {
+		//! @todo Validate this above.
+		struct oxr_swapchain *sc =
+		    (struct oxr_swapchain *)proj->views[i].subImage.swapchain;
+		chains[i] = sc->swapchain;
+		acquired_index[i] = proj->views[i].subImage.imageArrayIndex;
+	}
+
+	xc->end_frame(xc, blend_mode, chains, acquired_index, num_chains);
+
+	sess->frame_started = false;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_session_create(struct oxr_logger *log,
+                   struct oxr_system *sys,
+                   XrStructureType *next,
+                   struct oxr_session **out_session)
+{
+	struct oxr_session *sess;
+	XrResult ret;
+
+#ifdef XR_USE_PLATFORM_XLIB
+	if (*next == XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) {
+		ret = oxr_session_create_gl_xlib(
+		    log, sys, (XrGraphicsBindingOpenGLXlibKHR *)next, &sess);
+	} else
+#endif
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+	    if (*next == XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) {
+		ret = oxr_session_create_vk(
+		    log, sys, (XrGraphicsBindingVulkanKHR *)next, &sess);
+	} else
+#endif
+	{
+		ret = oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                "(createInfo->next->type)");
+	}
+
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	sess->ipd_meters = debug_get_num_option_ipd() / 1000.0f;
+	//! @todo hard-coding 90Hz
+	sess->nominal_frame_interval_ns = 11111111;
+	sess->static_prediction_s =
+	    debug_get_num_option_prediction_ms() / 1000.0f;
+
+	oxr_event_push_XrEventDataSessionStateChanged(log, sess,
+	                                              XR_SESSION_STATE_IDLE, 0);
+	oxr_event_push_XrEventDataSessionStateChanged(
+	    log, sess, XR_SESSION_STATE_READY, 0);
+	sess->state = XR_SESSION_STATE_READY;
+
+	*out_session = sess;
+
+	return ret;
+}
+
+XrResult
+oxr_session_destroy(struct oxr_logger *log, struct oxr_session *sess)
+{
+	sess->compositor->destroy(sess->compositor);
+	free(sess);
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_session_gl.c b/src/xrt/state_trackers/oxr/oxr_session_gl.c
new file mode 100644
index 000000000..e1761a953
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_session_gl.c
@@ -0,0 +1,46 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds OpenGL-specific session functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ * @ingroup comp_client
+ */
+
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+
+XrResult
+oxr_session_create_gl_xlib(struct oxr_logger *log,
+                           struct oxr_system *sys,
+                           XrGraphicsBindingOpenGLXlibKHR *next,
+                           struct oxr_session **out_session)
+{
+	struct xrt_compositor_gl *xcgl = xrt_gfx_provider_create_gl_xlib(
+	    sys->device, next->xDisplay, next->visualid, next->glxFBConfig,
+	    next->glxDrawable, next->glxContext);
+
+	if (xcgl == NULL) {
+		return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,
+		                 " failed create a compositor");
+	}
+
+	struct oxr_session *sess =
+	    (struct oxr_session *)calloc(1, sizeof(struct oxr_session));
+
+	sess->debug = OXR_XR_DEBUG_SESSION;
+	sess->sys = sys;
+	sess->compositor = &xcgl->base;
+	sess->create_swapchain = oxr_swapchain_gl_create;
+
+	*out_session = sess;
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_session_vk.c b/src/xrt/state_trackers/oxr/oxr_session_vk.c
new file mode 100644
index 000000000..9f2a83a06
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_session_vk.c
@@ -0,0 +1,49 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds Vulkan specific session functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ * @ingroup comp_client
+ */
+
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_vk.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+
+VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL
+vkGetInstanceProcAddr(VkInstance instance, const char *pName);
+
+XrResult
+oxr_session_create_vk(struct oxr_logger *log,
+                      struct oxr_system *sys,
+                      XrGraphicsBindingVulkanKHR *next,
+                      struct oxr_session **out_session)
+{
+	struct xrt_compositor_vk *xcvk = xrt_gfx_vk_provider_create(
+	    sys->device, next->instance, vkGetInstanceProcAddr,
+	    next->physicalDevice, next->device, next->queueFamilyIndex,
+	    next->queueIndex);
+
+	if (xcvk == NULL) {
+		return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,
+		                 " failed create a compositor");
+	}
+
+	struct oxr_session *sess =
+	    (struct oxr_session *)calloc(1, sizeof(struct oxr_session));
+	sess->debug = OXR_XR_DEBUG_SESSION;
+	sess->sys = sys;
+	sess->compositor = &xcvk->base;
+	sess->create_swapchain = oxr_swapchain_vk_create;
+
+	*out_session = sess;
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_space.c b/src/xrt/state_trackers/oxr/oxr_space.c
new file mode 100644
index 000000000..db2654f84
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_space.c
@@ -0,0 +1,260 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  So much space!
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "math/m_api.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+DEBUG_GET_ONCE_BOOL_OPTION(space, "OXR_DEBUG_SPACE", false)
+
+const struct xrt_pose origin = {{0.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}};
+
+static XrResult
+check_reference_space_type(struct oxr_logger *log, XrReferenceSpaceType type)
+{
+	switch (type) {
+	case XR_REFERENCE_SPACE_TYPE_VIEW: return XR_SUCCESS;
+	case XR_REFERENCE_SPACE_TYPE_LOCAL: return XR_SUCCESS;
+	case XR_REFERENCE_SPACE_TYPE_STAGE: return XR_SUCCESS;
+#if 0
+		return oxr_error(log, XR_ERROR_REFERENCE_SPACE_UNSUPPORTED,
+		                 "(createInfo->referenceSpaceType = "
+		                 "XR_REFERENCE_SPACE_TYPE_STAGE)");
+#endif
+	default:
+		return oxr_error(log, XR_ERROR_REFERENCE_SPACE_UNSUPPORTED,
+		                 "(createInfo->referenceSpaceType = "
+		                 "<UNKNOWN>)");
+	}
+}
+
+XrResult
+oxr_space_reference_create(struct oxr_logger *log,
+                           struct oxr_session *sess,
+                           const XrReferenceSpaceCreateInfo *createInfo,
+                           struct oxr_space **out_space)
+{
+	XrResult ret;
+
+	ret = check_reference_space_type(log, createInfo->referenceSpaceType);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	if (!math_pose_validate(
+	        (struct xrt_pose *)&createInfo->poseInReferenceSpace)) {
+		return oxr_error(log, XR_ERROR_POSE_INVALID,
+		                 "(createInfo->poseInReferenceSpace)");
+	}
+
+	struct oxr_space *spc =
+	    (struct oxr_space *)calloc(1, sizeof(struct oxr_space));
+	spc->debug = OXR_XR_DEBUG_SPACE;
+	spc->sess = sess;
+	spc->is_reference = true;
+	spc->type = createInfo->referenceSpaceType;
+	memcpy(&spc->pose, &createInfo->poseInReferenceSpace,
+	       sizeof(spc->pose));
+
+	*out_space = spc;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_space_destroy(struct oxr_logger *log, struct oxr_space *spc)
+{
+	free(spc);
+	return XR_SUCCESS;
+}
+
+static const char *
+get_ref_space_type_short_str(struct oxr_space *spc)
+{
+	if (!spc->is_reference) {
+		return "action?";
+	}
+
+	switch (spc->type) {
+	case XR_REFERENCE_SPACE_TYPE_VIEW: return "view";
+	case XR_REFERENCE_SPACE_TYPE_LOCAL: return "local";
+	case XR_REFERENCE_SPACE_TYPE_STAGE: return "stage";
+	default: return "unknown";
+	}
+}
+
+/*!
+ * This returns only the relation between two spaces without any of the app
+ * given relations applied, assumes that both spaces are reference spaces.
+ */
+XrResult
+oxr_space_ref_relation(struct oxr_logger *log,
+                       struct oxr_session *sess,
+                       XrReferenceSpaceType space,
+                       XrReferenceSpaceType baseSpc,
+                       XrTime time,
+                       struct xrt_space_relation *out_relation)
+{
+	// Treat stage space as the local space.
+	if (space == XR_REFERENCE_SPACE_TYPE_STAGE) {
+		space = XR_REFERENCE_SPACE_TYPE_LOCAL;
+	}
+
+	// Treat stage space as the local space.
+	if (baseSpc == XR_REFERENCE_SPACE_TYPE_STAGE) {
+		baseSpc = XR_REFERENCE_SPACE_TYPE_LOCAL;
+	}
+
+	math_relation_reset(out_relation);
+
+	if (space == XR_REFERENCE_SPACE_TYPE_VIEW &&
+	    baseSpc == XR_REFERENCE_SPACE_TYPE_LOCAL) {
+		oxr_session_get_view_pose_at(log, sess, time,
+		                             &out_relation->pose);
+
+		out_relation->relation_flags = (enum xrt_space_relation_flags)(
+		    XRT_SPACE_RELATION_POSITION_VALID_BIT |
+		    XRT_SPACE_RELATION_POSITION_TRACKED_BIT |
+		    XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
+		    XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
+
+	} else if (space == XR_REFERENCE_SPACE_TYPE_LOCAL &&
+	           baseSpc == XR_REFERENCE_SPACE_TYPE_VIEW) {
+		oxr_session_get_view_pose_at(log, sess, time,
+		                             &out_relation->pose);
+		math_pose_invert(&out_relation->pose, &out_relation->pose);
+
+		out_relation->relation_flags = (enum xrt_space_relation_flags)(
+		    XRT_SPACE_RELATION_POSITION_VALID_BIT |
+		    XRT_SPACE_RELATION_POSITION_TRACKED_BIT |
+		    XRT_SPACE_RELATION_ORIENTATION_VALID_BIT |
+		    XRT_SPACE_RELATION_ORIENTATION_TRACKED_BIT);
+
+	} else if (space == baseSpc) {
+		// math_relation_reset() sets to identity.
+
+	} else {
+		out_relation->relation_flags = 0;
+		return XR_SUCCESS;
+	}
+
+	return XR_SUCCESS;
+}
+
+/*!
+ * This returns only the relation between two directly-associated spaces without
+ * any of the app given relations applied.
+ */
+static XrResult
+get_pure_space_relation(struct oxr_logger *log,
+                        struct oxr_space *spc,
+                        struct oxr_space *baseSpc,
+                        XrTime time,
+                        struct xrt_space_relation *out_relation)
+{
+	struct oxr_session *sess = spc->sess;
+
+	if (spc->is_reference && baseSpc->is_reference) {
+		return oxr_space_ref_relation(
+		    log, sess, spc->type, baseSpc->type, time, out_relation);
+	} else if (!spc->is_reference && !baseSpc->is_reference) {
+		// @todo Deal with action to action by keeping a true_space that
+		//       we can always go via. Aka poor mans space graph.
+		// WARNING order not thought through here!
+		// struct xrt_pose pose1;
+		// struct xrt_pose pose2;
+		// get_pure_space_relation(log, session->true_space, baseSpc,
+		//                         time, &pose1);
+		// get_pure_space_relation(log, space, session->true_space,
+		//                         time, &pose2);
+		// math_pose_relate_2(&pose1, &pose2, out_pose);
+		out_relation->relation_flags = 0;
+		return XR_SUCCESS;
+	} else {
+		// @todo deal with action space poses.
+		out_relation->relation_flags = 0;
+		return XR_SUCCESS;
+	}
+}
+
+static void
+print_pose(const char *prefix, struct xrt_pose *pose)
+{
+	if (!debug_get_bool_option_space()) {
+		return;
+	}
+
+	struct xrt_vec3 *p = &pose->position;
+	struct xrt_quat *q = &pose->orientation;
+
+	fprintf(stderr, "%s (%f, %f, %f) (%f, %f, %f, %f)\n", prefix, p->x,
+	        p->y, p->z, q->x, q->y, q->z, q->w);
+}
+
+static void
+print_space(const char *name, struct oxr_space *spc)
+{
+	if (!debug_get_bool_option_space()) {
+		return;
+	}
+
+	const char *type_str = get_ref_space_type_short_str(spc);
+	fprintf(stderr, "\t%s->type %s\n\t%s->pose", name, type_str, name);
+	print_pose("", &spc->pose);
+}
+
+XrResult
+oxr_space_locate(struct oxr_logger *log,
+                 struct oxr_space *spc,
+                 struct oxr_space *baseSpc,
+                 XrTime time,
+                 XrSpaceRelation *relation)
+{
+	if (debug_get_bool_option_space()) {
+		fprintf(stderr, "%s\n", __func__);
+	}
+	print_space("space", spc);
+	print_space("baseSpace", baseSpc);
+
+	// Get the pure space relation.
+	//! @todo for longer paths in "space graph" than one edge, this will be
+	//! a loop.
+	struct xrt_space_relation pure;
+	XrResult ret = get_pure_space_relation(log, spc, baseSpc, time, &pure);
+	if (ret != XR_SUCCESS) {
+		relation->relationFlags = 0;
+		return ret;
+	}
+
+	// Combine space and base space poses with pure relation
+	struct xrt_space_relation result;
+	math_relation_openxr_locate(&spc->pose, &pure, &baseSpc->pose, &result);
+
+	// Copy
+	relation->pose = *(XrPosef *)&result.pose;
+	relation->linearVelocity = *(XrVector3f *)&result.linear_velocity;
+	relation->angularVelocity = *(XrVector3f *)&result.angular_velocity;
+	relation->linearAcceleration =
+	    *(XrVector3f *)&result.linear_acceleration;
+	relation->angularAcceleration =
+	    *(XrVector3f *)&result.angular_acceleration;
+	relation->relationFlags = result.relation_flags;
+
+	print_pose("\trelation->pose", (struct xrt_pose *)&relation->pose);
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain.c b/src/xrt/state_trackers/oxr/oxr_swapchain.c
new file mode 100644
index 000000000..55ad5d03f
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_swapchain.c
@@ -0,0 +1,115 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds swapchain related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+static XrResult
+oxr_swapchain_acquire_image(struct oxr_logger *log,
+                            struct oxr_swapchain *sc,
+                            const XrSwapchainImageAcquireInfo *acquireInfo,
+                            uint32_t *out_index)
+{
+	uint32_t index;
+	if (sc->acquired_index >= 0) {
+		return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID,
+		                 " image already acquired");
+	}
+
+	struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
+	if (!xsc->acquire_image(xsc, &index)) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " call to xsc->acquire_image failed");
+	}
+
+	sc->acquired_index = (int)index;
+	*out_index = index;
+
+	return XR_SUCCESS;
+}
+
+static XrResult
+oxr_swapchain_wait_image(struct oxr_logger *log,
+                         struct oxr_swapchain *sc,
+                         const XrSwapchainImageWaitInfo *waitInfo)
+{
+	if (sc->acquired_index < 0) {
+		return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID,
+		                 " no image acquired");
+	}
+
+	struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
+	if (!xsc->wait_image(xsc, waitInfo->timeout,
+	                     (uint32_t)sc->acquired_index)) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " call to xsc->wait_image failed");
+	}
+
+	return XR_SUCCESS;
+}
+
+static XrResult
+oxr_swapchain_release_image(struct oxr_logger *log,
+                            struct oxr_swapchain *sc,
+                            const XrSwapchainImageReleaseInfo *releaseInfo)
+{
+	if (sc->acquired_index < 0) {
+		return oxr_error(log, XR_ERROR_CALL_ORDER_INVALID,
+		                 " no image acquired");
+	}
+
+	struct xrt_swapchain *xsc = (struct xrt_swapchain *)sc->swapchain;
+	if (!xsc->release_image(xsc, (uint32_t)sc->acquired_index)) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " call to xsc->release_image failed");
+	}
+	sc->acquired_index = -1;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_create_swapchain(struct oxr_logger *log,
+                     struct oxr_session *sess,
+                     const XrSwapchainCreateInfo *createInfo,
+                     struct oxr_swapchain **out_swapchain)
+{
+	struct xrt_swapchain *xsc = sess->compositor->create_swapchain(
+	    sess->compositor,
+	    (enum xrt_swapchain_create_flags)createInfo->createFlags,
+	    (enum xrt_swapchain_usage_bits)createInfo->usageFlags,
+	    createInfo->format, createInfo->sampleCount, createInfo->width,
+	    createInfo->height, createInfo->faceCount, createInfo->arraySize,
+	    createInfo->mipCount);
+
+	if (xsc == NULL) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " failed to create swapchain");
+	}
+
+	struct oxr_swapchain *sc =
+	    (struct oxr_swapchain *)calloc(1, sizeof(struct oxr_swapchain));
+	sc->debug = OXR_XR_DEBUG_SWAPCHAIN;
+	sc->sess = sess;
+	sc->swapchain = xsc;
+	sc->acquire_image = oxr_swapchain_acquire_image;
+	sc->wait_image = oxr_swapchain_wait_image;
+	sc->release_image = oxr_swapchain_release_image;
+	sc->acquired_index = -1;
+
+	*out_swapchain = sc;
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c b/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c
new file mode 100644
index 000000000..c4075c8ac
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_swapchain_gl.c
@@ -0,0 +1,72 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds OpenGL swapchain related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ * @ingroup comp_client
+ */
+
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+static XrResult
+oxr_swapchain_gl_destroy(struct oxr_logger *log, struct oxr_swapchain *sc)
+{
+	if (sc->acquired_index >= 0) {
+		sc->release_image(log, sc, NULL);
+	}
+
+	if (sc->swapchain != NULL) {
+		sc->swapchain->destroy(sc->swapchain);
+		sc->swapchain = NULL;
+	}
+
+	return XR_SUCCESS;
+}
+
+static XrResult
+oxr_swapchain_gl_enumerate_images(struct oxr_logger *log,
+                                  struct oxr_swapchain *sc,
+                                  uint32_t count,
+                                  XrSwapchainImageBaseHeader *images)
+{
+	struct xrt_swapchain_gl *xsc = (struct xrt_swapchain_gl *)sc->swapchain;
+	XrSwapchainImageOpenGLKHR *gl_imgs =
+	    (XrSwapchainImageOpenGLKHR *)images;
+
+	for (uint32_t i = 0; i < count; i++) {
+		gl_imgs[i].image = xsc->images[i];
+	}
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_swapchain_gl_create(struct oxr_logger *log,
+                        struct oxr_session *sess,
+                        const XrSwapchainCreateInfo *createInfo,
+                        struct oxr_swapchain **out_swapchain)
+{
+	struct oxr_swapchain *sc;
+	XrResult ret;
+
+	ret = oxr_create_swapchain(log, sess, createInfo, &sc);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	sc->destroy = oxr_swapchain_gl_destroy;
+	sc->enumerate_images = oxr_swapchain_gl_enumerate_images;
+
+	*out_swapchain = sc;
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c b/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c
new file mode 100644
index 000000000..8d63ccdfb
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_swapchain_vk.c
@@ -0,0 +1,75 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds Vulkan swapchain related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ * @ingroup comp_client
+ */
+
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_xlib.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+
+
+static XrResult
+oxr_swapchain_vk_destroy(struct oxr_logger *log, struct oxr_swapchain *sc)
+{
+	if (sc->acquired_index >= 0) {
+		sc->release_image(log, sc, NULL);
+	}
+
+	sc->acquired_index = 0;
+
+	if (sc->swapchain != NULL) {
+		sc->swapchain->destroy(sc->swapchain);
+		sc->swapchain = NULL;
+	}
+
+	return XR_SUCCESS;
+}
+
+static XrResult
+oxr_swapchain_vk_enumerate_images(struct oxr_logger *log,
+                                  struct oxr_swapchain *sc,
+                                  uint32_t count,
+                                  XrSwapchainImageBaseHeader *images)
+{
+	struct xrt_swapchain_vk *xscvk =
+	    (struct xrt_swapchain_vk *)sc->swapchain;
+	XrSwapchainImageVulkanKHR *vk_imgs =
+	    (XrSwapchainImageVulkanKHR *)images;
+
+	for (uint32_t i = 0; i < count; i++) {
+		vk_imgs[i].image = xscvk->images[i];
+	}
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_swapchain_vk_create(struct oxr_logger *log,
+                        struct oxr_session *sess,
+                        const XrSwapchainCreateInfo *createInfo,
+                        struct oxr_swapchain **out_swapchain)
+{
+	struct oxr_swapchain *sc;
+	XrResult ret;
+
+	ret = oxr_create_swapchain(log, sess, createInfo, &sc);
+	if (ret != XR_SUCCESS) {
+		return ret;
+	}
+
+	sc->destroy = oxr_swapchain_vk_destroy;
+	sc->enumerate_images = oxr_swapchain_vk_enumerate_images;
+
+	*out_swapchain = sc;
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_system.c b/src/xrt/state_trackers/oxr/oxr_system.c
new file mode 100644
index 000000000..26e935abc
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_system.c
@@ -0,0 +1,192 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds system related entrypoints.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "xrt/xrt_device.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+
+static bool
+oxr_system_matches(struct oxr_logger *log,
+                   struct oxr_system *sys,
+                   XrFormFactor form_factor)
+{
+	return form_factor == sys->form_factor;
+}
+
+XrResult
+oxr_system_select(struct oxr_logger *log,
+                  struct oxr_system **systems,
+                  uint32_t num_systems,
+                  XrFormFactor form_factor,
+                  struct oxr_system **out_selected)
+{
+	struct oxr_system *selected = NULL;
+	for (uint32_t i = 0; i < num_systems; i++) {
+		if (oxr_system_matches(log, systems[i], form_factor)) {
+			selected = systems[i];
+			break;
+		}
+	}
+
+	if (selected == NULL) {
+		return oxr_error(log, XR_ERROR_FORM_FACTOR_UNSUPPORTED,
+		                 "(getInfo->formFactor) no matching system");
+	}
+
+	*out_selected = selected;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_system_fill_in(struct oxr_logger *log,
+                   struct oxr_instance *inst,
+                   XrSystemId systemId,
+                   struct oxr_system *sys,
+                   struct xrt_device *xdev)
+{
+	if (xdev == NULL) {
+		return oxr_error(log, XR_ERROR_INITIALIZATION_FAILED,
+		                 " failed to probe device");
+	}
+
+	sys->device = xdev;
+	sys->inst = inst;
+	sys->systemId = systemId;
+
+	// clang-format off
+	sys->form_factor =      XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
+	sys->view_config_type = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
+
+	sys->views[0].recommendedImageRectWidth       = xdev->views[0].display.w_pixels;
+	sys->views[0].maxImageRectWidth               = xdev->views[0].display.w_pixels;
+	sys->views[0].recommendedImageRectHeight      = xdev->views[0].display.h_pixels;
+	sys->views[0].maxImageRectHeight              = xdev->views[0].display.h_pixels;
+	sys->views[0].recommendedSwapchainSampleCount = 1;
+	sys->views[0].maxSwapchainSampleCount         = 1;
+
+	sys->views[1].recommendedImageRectWidth       = xdev->views[1].display.w_pixels;
+	sys->views[1].maxImageRectWidth               = xdev->views[1].display.w_pixels;
+	sys->views[1].recommendedImageRectHeight      = xdev->views[1].display.h_pixels;
+	sys->views[1].maxImageRectHeight              = xdev->views[1].display.h_pixels;
+	sys->views[1].recommendedSwapchainSampleCount = 1;
+	sys->views[1].maxSwapchainSampleCount         = 1;
+
+	uint32_t i = 0;
+	if (xdev->blend_mode & XRT_BLEND_MODE_OPAQUE) {
+		sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
+	}
+	if (xdev->blend_mode & XRT_BLEND_MODE_ADDITIVE) {
+		sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
+	}
+	if (xdev->blend_mode & XRT_BLEND_MODE_ALPHA_BLEND) {
+		sys->blend_modes[i++] = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
+	}
+	sys->num_blend_modes = i;
+
+	assert(i < ARRAY_SIZE(sys->blend_modes));
+
+	// clang-format on
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_system_get_properties(struct oxr_logger *log,
+                          struct oxr_system *sys,
+                          XrSystemProperties *properties)
+{
+	properties->vendorId = 42;
+	properties->systemId = sys->systemId;
+	properties->graphicsProperties.maxViewCount = 2;
+	/*!
+	 * @todo conforming implementations must support at
+	 * leastXR_MIN_COMPOSITION_LAYERS_SUPPORTED layers.
+	 */
+	properties->graphicsProperties.maxLayerCount = 1;
+	properties->graphicsProperties.maxSwapchainImageWidth = 1024 * 16;
+	properties->graphicsProperties.maxSwapchainImageHeight = 1024 * 16;
+	properties->trackingProperties.orientationTracking = XR_TRUE;
+	properties->trackingProperties.positionTracking = XR_FALSE;
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_system_enumerate_view_confs(struct oxr_logger *log,
+                                struct oxr_system *sys,
+                                uint32_t viewConfigurationTypeCapacityInput,
+                                uint32_t *viewConfigurationTypeCountOutput,
+                                XrViewConfigurationType *viewConfigurationTypes)
+{
+	OXR_TWO_CALL_HELPER(log, viewConfigurationTypeCapacityInput,
+	                    viewConfigurationTypeCountOutput,
+	                    viewConfigurationTypes, 1, &sys->view_config_type);
+}
+
+XrResult
+oxr_system_enumerate_blend_modes(struct oxr_logger *log,
+                                 struct oxr_system *sys,
+                                 uint32_t environmentBlendModeCapacityInput,
+                                 uint32_t *environmentBlendModeCountOutput,
+                                 XrEnvironmentBlendMode *environmentBlendModes)
+{
+	OXR_TWO_CALL_HELPER(log, environmentBlendModeCapacityInput,
+	                    environmentBlendModeCountOutput,
+	                    environmentBlendModes, sys->num_blend_modes,
+	                    sys->blend_modes);
+}
+
+XrResult
+oxr_system_get_view_conf_properties(
+    struct oxr_logger *log,
+    struct oxr_system *sys,
+    XrViewConfigurationType viewConfigurationType,
+    XrViewConfigurationProperties *configurationProperties)
+{
+	if (viewConfigurationType != sys->view_config_type) {
+		return oxr_error(log,
+		                 XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
+		                 "invalid view configuration type");
+	}
+
+	// clang-format off
+	configurationProperties->viewConfigurationType = sys->view_config_type;
+	configurationProperties->fovMutable = false;
+	// clang-format on
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_system_enumerate_view_conf_views(
+    struct oxr_logger *log,
+    struct oxr_system *sys,
+    XrViewConfigurationType viewConfigurationType,
+    uint32_t viewCapacityInput,
+    uint32_t *viewCountOutput,
+    XrViewConfigurationView *views)
+{
+	if (viewConfigurationType != sys->view_config_type) {
+		return oxr_error(log,
+		                 XR_ERROR_VIEW_CONFIGURATION_TYPE_UNSUPPORTED,
+		                 "invalid view configuration type");
+	}
+
+	OXR_TWO_CALL_HELPER(log, viewCapacityInput, viewCountOutput, views, 2,
+	                    sys->views);
+}
diff --git a/src/xrt/state_trackers/oxr/oxr_two_call.h b/src/xrt/state_trackers/oxr/oxr_two_call.h
new file mode 100644
index 000000000..0ab83c516
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_two_call.h
@@ -0,0 +1,40 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Two call helper functions.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define OXR_TWO_CALL_HELPER(log, cnt_input, cnt_output, output, count, data)   \
+	do {                                                                   \
+		if (cnt_output != NULL) {                                      \
+			*cnt_output = count;                                   \
+		}                                                              \
+		if (cnt_input == 0) {                                          \
+			return XR_SUCCESS;                                     \
+		}                                                              \
+		if (cnt_input < count) {                                       \
+			return oxr_error(log, XR_ERROR_SIZE_INSUFFICIENT,      \
+			                 #cnt_input);                          \
+		}                                                              \
+		for (uint32_t i = 0; i < count; i++) {                         \
+			(output)[i] = (data)[i];                               \
+		}                                                              \
+		return XR_SUCCESS;                                             \
+	} while (false)
+
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_verify.cpp b/src/xrt/state_trackers/oxr/oxr_verify.cpp
new file mode 100644
index 000000000..4814b7aa8
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_verify.cpp
@@ -0,0 +1,145 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  File for verifing app input into api functions.
+ * @author Ryan Pavlik <ryan.pavlik@collabora.com>
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ * @ingroup oxr_api
+ */
+
+#include <stdio.h>
+
+#include "xrt/xrt_compiler.h"
+#include "util/u_debug.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_api_verify.h"
+
+
+/*
+ *
+ * Path verification.
+ *
+ */
+
+bool
+contains_zero(const char* path, uint32_t size)
+{
+	for (uint32_t i = 0; i < size; i++) {
+		if (path[i] == '\0') {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+XrResult
+oxr_verify_fixed_size_single_level_path(struct oxr_logger* log,
+                                        const char* path,
+                                        uint32_t size,
+                                        const char* name)
+{
+	if (size == 0) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(%s) internal runtime error", name);
+	}
+
+	if (path[0] == '\0') {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(%s) can not be empty", name);
+	}
+
+	if (!contains_zero(path, size)) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "(%s) must include zero termination '\\0'.",
+		                 name);
+	}
+
+	//! @todo verify more!
+
+	return XR_SUCCESS;
+}
+
+
+/*
+ *
+ * Other verification.
+ *
+ */
+
+XrResult
+oxr_verify_XrSessionCreateInfo(struct oxr_logger* log,
+                               const XrSessionCreateInfo* createInfo)
+{
+	if (createInfo->type != XR_TYPE_SESSION_CREATE_INFO) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->type");
+	}
+
+	if (createInfo->next == NULL) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next");
+	}
+
+	XrStructureType* next_type = (XrStructureType*)createInfo->next;
+#ifdef XR_USE_PLATFORM_XLIB
+	if (*next_type == XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) {
+		return oxr_verify_XrGraphicsBindingOpenGLXlibKHR(
+		    log, (XrGraphicsBindingOpenGLXlibKHR*)createInfo->next);
+	} else
+#endif
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+	    if (*next_type == XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) {
+		return oxr_verify_XrGraphicsBindingVulkanKHR(
+		    log, (XrGraphicsBindingVulkanKHR*)createInfo->next);
+	} else
+#endif
+	{
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next->type");
+	}
+
+	return XR_SUCCESS;
+}
+
+#ifdef XR_USE_PLATFORM_XLIB
+XrResult
+oxr_verify_XrGraphicsBindingOpenGLXlibKHR(
+    struct oxr_logger* log, const XrGraphicsBindingOpenGLXlibKHR* next)
+{
+	if (next->type != XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next->type");
+	}
+
+	if (next->next != NULL) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next->next");
+	}
+
+	return XR_SUCCESS;
+}
+#endif
+
+#ifdef XR_USE_GRAPHICS_API_VULKAN
+XrResult
+oxr_verify_XrGraphicsBindingVulkanKHR(struct oxr_logger* log,
+                                      const XrGraphicsBindingVulkanKHR* next)
+{
+	if (next->type != XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next->type");
+	}
+
+	if (next->next != NULL) {
+		return oxr_error(log, XR_ERROR_VALIDATION_FAILURE,
+		                 "createInfo->next->next");
+	}
+
+	return XR_SUCCESS;
+}
+#endif
diff --git a/src/xrt/state_trackers/oxr/oxr_vulkan.c b/src/xrt/state_trackers/oxr/oxr_vulkan.c
new file mode 100644
index 000000000..1f5f36228
--- /dev/null
+++ b/src/xrt/state_trackers/oxr/oxr_vulkan.c
@@ -0,0 +1,129 @@
+// Copyright 2018-2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  Holds Vulkan related functions.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ * @ingroup oxr_main
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "xrt/xrt_gfx_vk.h"
+
+#include "oxr_objects.h"
+#include "oxr_logger.h"
+#include "oxr_two_call.h"
+
+
+#define GET_PROC(name) PFN_##name name = (PFN_##name)getProc(vkInstance, #name)
+
+XrResult
+oxr_vk_get_instance_exts(struct oxr_logger *log,
+                         struct oxr_system *sys,
+                         uint32_t namesCapacityInput,
+                         uint32_t *namesCountOutput,
+                         char *namesString)
+{
+	size_t length = strlen(xrt_gfx_vk_instance_extensions) + 1;
+
+	OXR_TWO_CALL_HELPER(log, namesCapacityInput, namesCountOutput,
+	                    namesString, length,
+	                    xrt_gfx_vk_instance_extensions);
+}
+
+XrResult
+oxr_vk_get_device_exts(struct oxr_logger *log,
+                       struct oxr_system *sys,
+                       uint32_t namesCapacityInput,
+                       uint32_t *namesCountOutput,
+                       char *namesString)
+{
+	size_t length = strlen(xrt_gfx_vk_device_extensions) + 1;
+
+	OXR_TWO_CALL_HELPER(log, namesCapacityInput, namesCountOutput,
+	                    namesString, length, xrt_gfx_vk_device_extensions);
+}
+
+XrResult
+oxr_vk_get_requirements(struct oxr_logger *log,
+                        struct oxr_system *sys,
+                        XrGraphicsRequirementsVulkanKHR *graphicsRequirements)
+{
+	struct xrt_api_requirements ver;
+
+	xrt_gfx_vk_get_versions(&ver);
+	graphicsRequirements->minApiVersionSupported =
+	    XR_MAKE_VERSION(ver.min_major, ver.min_minor, ver.min_patch);
+	graphicsRequirements->maxApiVersionSupported =
+	    XR_MAKE_VERSION(ver.max_major, ver.max_minor, ver.max_patch);
+
+	return XR_SUCCESS;
+}
+
+XrResult
+oxr_vk_get_physical_device(struct oxr_logger *log,
+                           struct oxr_instance *inst,
+                           struct oxr_system *sys,
+                           VkInstance vkInstance,
+                           PFN_vkGetInstanceProcAddr getProc,
+                           VkPhysicalDevice *vkPhysicalDevice)
+{
+	GET_PROC(vkEnumeratePhysicalDevices);
+	GET_PROC(vkGetPhysicalDeviceProperties);
+	VkResult vk_ret;
+	uint32_t count;
+
+	vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, NULL);
+	if (vk_ret != VK_SUCCESS) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " vkEnumeratePhysicalDevices returned %u",
+		                 vk_ret);
+	}
+	if (count == 0) {
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " vkEnumeratePhysicalDevices returned zero "
+		                 "VkPhysicalDevices");
+	}
+
+	VkPhysicalDevice *phys = calloc(count, sizeof(VkPhysicalDevice));
+	vk_ret = vkEnumeratePhysicalDevices(vkInstance, &count, phys);
+	if (vk_ret != VK_SUCCESS) {
+		free(phys);
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " vkEnumeratePhysicalDevices returned %u",
+		                 vk_ret);
+	}
+	if (count == 0) {
+		free(phys);
+		return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
+		                 " vkEnumeratePhysicalDevices returned zero "
+		                 "VkPhysicalDevices");
+	}
+
+	if (count > 1) {
+		OXR_WARN_ONCE(log,
+		              "super intelligent device selection algorithm "
+		              "can't handle more then one VkPhysicalDevice, "
+		              "picking the first discrete gpu in the list.");
+	}
+
+	// as a first-step to 'intelligent' selection, prefer a 'discrete' gpu
+	// if it is present
+	uint32_t gpu_index = 0;
+	for (uint32_t i = 0; i < count; i++) {
+		VkPhysicalDeviceProperties pdp;
+		vkGetPhysicalDeviceProperties(phys[i], &pdp);
+		if (pdp.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) {
+			gpu_index = i;
+		}
+	}
+
+	*vkPhysicalDevice = phys[gpu_index];
+
+	free(phys);
+
+	return XR_SUCCESS;
+}
diff --git a/src/xrt/targets/CMakeLists.txt b/src/xrt/targets/CMakeLists.txt
new file mode 100644
index 000000000..2db892278
--- /dev/null
+++ b/src/xrt/targets/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+######
+# This is where we collect all of the pieces from the different parts of
+# the source tree and build a complete driver or integration part.
+
+add_subdirectory(openxr)
diff --git a/src/xrt/targets/openxr/CMakeLists.txt b/src/xrt/targets/openxr/CMakeLists.txt
new file mode 100644
index 000000000..d6b046034
--- /dev/null
+++ b/src/xrt/targets/openxr/CMakeLists.txt
@@ -0,0 +1,98 @@
+# Copyright 2019, Collabora, Ltd.
+# SPDX-License-Identifier: BSL-1.0
+
+######
+# Create a loadable OpenXR driver.
+
+# set(RUNTIME_BARE_PREFIX xrt)
+# set(RUNTIME_PREFIX ${RUNTIME_BARE_PREFIX}_)
+
+set(RUNTIME_BARE_SUFFIX monado)
+set(RUNTIME_SUFFIX _${RUNTIME_BARE_SUFFIX})
+
+set(RUNTIME_TARGET ${RUNTIME_PREFIX}openxr${RUNTIME_SUFFIX} CACHE INTERNAL "" FORCE)
+
+set(XR_API_MAJOR "0")
+
+
+# $LIBPATH is a generator expression that is evaluated after configure_file, so we have to use file(GENERATE) instead
+
+###
+# Generate runtime manifest with absolute path to runtime intended for development without installing
+file(
+	GENERATE
+	OUTPUT "${CMAKE_BINARY_DIR}/${RUNTIME_TARGET}-dev.json"
+	CONTENT
+"{
+    \"file_format_version\": \"1.0.0\",
+    \"runtime\": {
+        \"library_path\": \"$<TARGET_SONAME_FILE:${RUNTIME_TARGET}>\"
+    }
+}
+")
+
+###
+# Generate runtime manifest with relative path to runtime intendend for installed release build
+# (assumes the runtime library is in the loader's search path)
+file(
+	GENERATE
+	OUTPUT "${CMAKE_BINARY_DIR}/${RUNTIME_TARGET}.json"
+	CONTENT
+"{
+    \"file_format_version\": \"1.0.0\",
+    \"runtime\": {
+        \"library_path\": \"$<TARGET_SONAME_FILE_NAME:${RUNTIME_TARGET}>\"
+    }
+}
+")
+
+include_directories(
+	${CMAKE_CURRENT_SOURCE_DIR}/../../include
+	${CMAKE_CURRENT_SOURCE_DIR}/../../drivers
+	)
+
+set(SOURCE_FILES
+	target.c
+	)
+
+
+# Siiiiiiiigh, there is no target_link_directories
+# or a way to add directories to a target.
+link_directories(${OPENHMD_LIBRARY_DIRS})
+
+# depends on above generated files
+add_library(${RUNTIME_TARGET} SHARED
+	${MANIFEST_DEV_PATH}
+	${MANIFEST_PATH}
+	${SOURCE_FILES}
+	$<TARGET_OBJECTS:aux_util>
+	$<TARGET_OBJECTS:aux_math>
+	$<TARGET_OBJECTS:comp>
+	$<TARGET_OBJECTS:drv_ohmd>
+	$<TARGET_OBJECTS:st_oxr>
+	)
+
+target_link_libraries(${RUNTIME_TARGET}
+	${OPENHMD_LIBRARIES}
+	${Vulkan_LIBRARIES}
+	${XCB_LIBRARIES}
+	)
+
+target_compile_definitions(${RUNTIME_TARGET} PRIVATE XRT_HAVE_OHMD)
+
+if(TARGET drv_hdk)
+	target_sources(${RUNTIME_TARGET} PRIVATE $<TARGET_OBJECTS:drv_hdk>)
+	target_link_libraries(${RUNTIME_TARGET} ${HIDAPI_LIBRARIES})
+	target_compile_definitions(${RUNTIME_TARGET} PRIVATE XRT_HAVE_HDK)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+	include(GNUInstallDirs)
+	install(TARGETS ${RUNTIME_TARGET}
+		LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+		ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+		RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+	install(FILES "${CMAKE_BINARY_DIR}/${RUNTIME_TARGET}.json" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/openxr/${XR_API_MAJOR}/")
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
+	# TODO: install target on windows
+endif()
diff --git a/src/xrt/targets/openxr/libopenxr.version b/src/xrt/targets/openxr/libopenxr.version
new file mode 100644
index 000000000..1581ef8d3
--- /dev/null
+++ b/src/xrt/targets/openxr/libopenxr.version
@@ -0,0 +1,4 @@
+OPENXR {
+	global: xrNegotiateLoaderRuntimeInterface; # Only one exported symbol.
+	local: *;                                  # Hide everything else.
+};
diff --git a/src/xrt/targets/openxr/target.c b/src/xrt/targets/openxr/target.c
new file mode 100644
index 000000000..9bdd1613c
--- /dev/null
+++ b/src/xrt/targets/openxr/target.c
@@ -0,0 +1,102 @@
+// Copyright 2019, Collabora, Ltd.
+// SPDX-License-Identifier: BSL-1.0
+/*!
+ * @file
+ * @brief  The thing that binds all of the OpenXR driver together.
+ * @author Jakob Bornecrantz <jakob@collabora.com>
+ */
+
+#include "xrt/xrt_prober.h"
+
+#include <stdlib.h>
+
+#ifdef XRT_HAVE_OHMD
+#include "ohmd/oh_interface.h"
+#endif
+
+#ifdef XRT_HAVE_HDK
+#include "hdk/hdk_interface.h"
+#endif
+
+
+typedef struct xrt_prober *(*prober_creator)();
+
+
+static const prober_creator DRIVERS[] = {
+#ifdef XRT_HAVE_HDK
+    // Returns NULL if none found, so OK to go first.
+    hdk_create_prober,
+#endif
+
+#ifdef XRT_HAVE_OHMD
+    oh_create_prober,
+#endif
+
+};
+
+#define NUM_PROBERS (ARRAY_SIZE(DRIVERS))
+
+/*!
+ * An xrt_prober that contains other xrt_probers.
+ */
+struct xrt_meta_prober
+{
+	struct xrt_prober base;
+	struct xrt_prober *probers[NUM_PROBERS];
+};
+
+
+static inline struct xrt_meta_prober *
+xrt_meta_prober(struct xrt_prober *p)
+{
+	return (struct xrt_meta_prober *)p;
+}
+
+static void
+xrt_meta_prober_destroy(struct xrt_prober *p)
+{
+	struct xrt_meta_prober *mp = xrt_meta_prober(p);
+	for (size_t i = 0; i < NUM_PROBERS; i++) {
+		if (mp->probers[i]) {
+			mp->probers[i]->destroy(mp->probers[i]);
+			mp->probers[i] = NULL;
+		}
+	}
+
+	free(p);
+}
+
+static struct xrt_device *
+xrt_meta_prober_autoprobe(struct xrt_prober *p)
+{
+	struct xrt_meta_prober *mp = xrt_meta_prober(p);
+	for (size_t i = 0; i < NUM_PROBERS; i++) {
+		if (mp->probers[i]) {
+			struct xrt_device *ret =
+			    mp->probers[i]->lelo_dallas_autoprobe(
+			        mp->probers[i]);
+			if (ret) {
+				return ret;
+			}
+		}
+	}
+
+	/* Couldn't find any prober that works. */
+	return NULL;
+}
+
+struct xrt_prober *
+xrt_create_prober()
+{
+	struct xrt_meta_prober *p =
+	    (struct xrt_meta_prober *)calloc(1, sizeof(struct xrt_meta_prober));
+
+	for (size_t i = 0; i < NUM_PROBERS; i++) {
+		p->probers[i] = DRIVERS[i]();
+	}
+
+	p->base.lelo_dallas_autoprobe = xrt_meta_prober_autoprobe;
+	p->base.destroy = xrt_meta_prober_destroy;
+
+	return &p->base;
+}
-- 
GitLab