GPU: OpenXR integration (#14837)

Based on Beyley's initial draft in #11601.

Co-authored-by: Beyley Cardellio <ep1cm1n10n123@gmail.com>
Co-authored-by: Ethan Lee <flibitijibibo@gmail.com>
This commit is contained in:
Aaron Benjamin
2026-01-30 17:18:51 -05:00
committed by GitHub
parent 8fa8c331a5
commit 9a91d7236a
36 changed files with 19723 additions and 102 deletions

View File

@@ -39,6 +39,7 @@ LOCAL_SRC_FILES := \
$(wildcard $(LOCAL_PATH)/src/io/generic/*.c) \
$(wildcard $(LOCAL_PATH)/src/gpu/*.c) \
$(wildcard $(LOCAL_PATH)/src/gpu/vulkan/*.c) \
$(wildcard $(LOCAL_PATH)/src/gpu/xr/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \

View File

@@ -391,6 +391,7 @@ set_option(SDL_LIBUDEV "Enable libudev support" ON)
set_option(SDL_ASAN "Use AddressSanitizer to detect memory errors" OFF)
set_option(SDL_CCACHE "Use Ccache to speed up build" OFF)
set_option(SDL_CLANG_TIDY "Run clang-tidy static analysis" OFF)
dep_option(SDL_GPU_OPENXR "Build SDL_GPU with OpenXR support" ON "SDL_GPU;NOT RISCOS" OFF)
set(SDL_VENDOR_INFO "" CACHE STRING "Vendor name and/or version to add to SDL_REVISION")
@@ -1272,6 +1273,8 @@ sdl_glob_sources(
"${SDL3_SOURCE_DIR}/src/filesystem/*.h"
"${SDL3_SOURCE_DIR}/src/gpu/*.c"
"${SDL3_SOURCE_DIR}/src/gpu/*.h"
"${SDL3_SOURCE_DIR}/src/gpu/xr/*.c"
"${SDL3_SOURCE_DIR}/src/gpu/xr/*.h"
"${SDL3_SOURCE_DIR}/src/joystick/*.c"
"${SDL3_SOURCE_DIR}/src/joystick/*.h"
"${SDL3_SOURCE_DIR}/src/haptic/*.c"
@@ -3550,6 +3553,9 @@ if(SDL_GPU)
set(SDL_VIDEO_RENDER_GPU 1)
set(HAVE_RENDER_GPU TRUE)
endif()
if(SDL_GPU_OPENXR)
set(HAVE_GPU_OPENXR 1)
endif()
endif()
# Dummies

View File

@@ -927,6 +927,12 @@
<CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'">CompileAsCpp</CompileAs>
</ClCompile>
<ClCompile Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_gpu_openxr.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_openxrdyn.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\src\gpu\xr\SDL_gpu_openxr_c.h" />
<ClInclude Include="..\..\src\gpu\xr\SDL_openxr_internal.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\core\windows\version.rc" />

View File

@@ -52,6 +52,9 @@
<ClCompile Include="..\..\src\gpu\SDL_gpu.c" />
<ClCompile Include="..\..\src\gpu\d3d12\SDL_gpu_d3d12.c" />
<ClCompile Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_gpu_openxr.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_openxrdyn.c" />
<ClInclude Include="..\..\src\gpu\xr\SDL_openxr_internal.h" />
<ClCompile Include="..\..\src\haptic\dummy\SDL_syshaptic.c" />
<ClCompile Include="..\..\src\haptic\SDL_haptic.c" />
<ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />

View File

@@ -475,6 +475,8 @@
<ClInclude Include="..\..\src\gpu\d3d12\D3D12_Blit.h" />
<ClInclude Include="..\..\src\gpu\SDL_sysgpu.h" />
<ClInclude Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan_vkfuncs.h" />
<ClInclude Include="..\..\src\gpu\xr\SDL_gpu_openxr_c.h" />
<ClInclude Include="..\..\src\gpu\xr\SDL_openxr_internal.h" />
<ClInclude Include="..\..\src\hidapi\SDL_hidapi_windows.h" />
<ClInclude Include="..\..\src\hidapi\windows\hidapi_cfgmgr32.h" />
<ClInclude Include="..\..\src\hidapi\windows\hidapi_descriptor_reconstruct.h" />
@@ -629,6 +631,8 @@
<ClCompile Include="..\..\src\gpu\SDL_gpu.c" />
<ClCompile Include="..\..\src\gpu\d3d12\SDL_gpu_d3d12.c" />
<ClCompile Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_gpu_openxr.c" />
<ClCompile Include="..\..\src\gpu\xr\SDL_openxrdyn.c" />
<ClCompile Include="..\..\src\io\generic\SDL_asyncio_generic.c" />
<ClCompile Include="..\..\src\io\SDL_asyncio.c" />
<ClCompile Include="..\..\src\main\generic\SDL_sysmain_callbacks.c" />

View File

@@ -981,6 +981,15 @@
<ClInclude Include="..\..\src\gpu\SDL_sysgpu.h">
<Filter>gpu</Filter>
</ClInclude>
<ClInclude Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan_vkfuncs.h">
<Filter>gpu</Filter>
</ClInclude>
<ClInclude Include="..\..\src\gpu\xr\SDL_gpu_openxr_c.h">
<Filter>gpu</Filter>
</ClInclude>
<ClInclude Include="..\..\src\gpu\xr\SDL_openxr_internal.h">
<Filter>gpu</Filter>
</ClInclude>
<ClInclude Include="..\..\include\SDL3\SDL_storage.h" />
<ClInclude Include="..\..\include\SDL3\SDL_time.h" />
<ClInclude Include="..\..\src\core\SDL_core_unsupported.h" />
@@ -1953,6 +1962,26 @@
<ClCompile Include="..\..\src\gpu\SDL_gpu.c">
<Filter>gpu</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gpu\d3d12\SDL_gpu_d3d12.c">
<Filter>gpu</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gpu\vulkan\SDL_gpu_vulkan.c">
<Filter>gpu</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gpu\xr\SDL_gpu_openxr.c">
<Filter>gpu</Filter>
</ClCompile>
<ClCompile Include="..\..\src\gpu\xr\SDL_openxrdyn.c">
<Filter>gpu</Filter>
</ClCompile>
<ClCompile Include="..\..\src\process\SDL_process.c" />
<ClCompile Include="..\..\src\process\windows\SDL_windowsprocess.c" />
<ClCompile Include="..\..\src\render\gpu\SDL_pipeline_gpu.c" />
<ClCompile Include="..\..\src\render\gpu\SDL_render_gpu.c" />
<ClCompile Include="..\..\src\render\gpu\SDL_shaders_gpu.c" />
<ClCompile Include="..\..\src\storage\generic\SDL_genericstorage.c" />
<ClCompile Include="..\..\src\storage\steam\SDL_steamstorage.c" />
<ClCompile Include="..\..\src\storage\SDL_storage.c" />
<ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_steam_triton.c">
<Filter>joystick\hidapi</Filter>
</ClCompile>

View File

@@ -366,6 +366,10 @@
E4F257952C81903800FCEAFC /* SDL_gpu_vulkan.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F257832C81903800FCEAFC /* SDL_gpu_vulkan.c */; };
E4F257962C81903800FCEAFC /* SDL_gpu.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F257852C81903800FCEAFC /* SDL_gpu.c */; };
E4F257972C81903800FCEAFC /* SDL_sysgpu.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F257862C81903800FCEAFC /* SDL_sysgpu.h */; };
E4F257982C81903800FCEAFC /* SDL_gpu_openxr.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F257882C81903800FCEAFC /* SDL_gpu_openxr.c */; };
E4F257992C81903800FCEAFC /* SDL_openxrdyn.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F257892C81903800FCEAFC /* SDL_openxrdyn.c */; };
E4F2579A2C81903800FCEAFC /* SDL_gpu_openxr_c.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F2578A2C81903800FCEAFC /* SDL_gpu_openxr_c.h */; };
E4F2579B2C81903800FCEAFC /* SDL_openxr_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F2578C2C81903800FCEAFC /* SDL_openxr_internal.h */; };
E4F7981A2AD8D84800669F54 /* SDL_core_unsupported.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F798192AD8D84800669F54 /* SDL_core_unsupported.c */; };
E4F7981C2AD8D85500669F54 /* SDL_dynapi_unsupported.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F7981B2AD8D85500669F54 /* SDL_dynapi_unsupported.h */; };
E4F7981E2AD8D86A00669F54 /* SDL_render_unsupported.c in Sources */ = {isa = PBXBuildFile; fileRef = E4F7981D2AD8D86A00669F54 /* SDL_render_unsupported.c */; };
@@ -937,6 +941,10 @@
E4F257832C81903800FCEAFC /* SDL_gpu_vulkan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gpu_vulkan.c; sourceTree = "<group>"; };
E4F257852C81903800FCEAFC /* SDL_gpu.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gpu.c; sourceTree = "<group>"; };
E4F257862C81903800FCEAFC /* SDL_sysgpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysgpu.h; sourceTree = "<group>"; };
E4F257882C81903800FCEAFC /* SDL_gpu_openxr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gpu_openxr.c; sourceTree = "<group>"; };
E4F257892C81903800FCEAFC /* SDL_openxrdyn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_openxrdyn.c; sourceTree = "<group>"; };
E4F2578A2C81903800FCEAFC /* SDL_gpu_openxr_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gpu_openxr_c.h; sourceTree = "<group>"; };
E4F2578C2C81903800FCEAFC /* SDL_openxr_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_openxr_internal.h; sourceTree = "<group>"; };
E4F798192AD8D84800669F54 /* SDL_core_unsupported.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_core_unsupported.c; sourceTree = "<group>"; };
E4F7981B2AD8D85500669F54 /* SDL_dynapi_unsupported.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_dynapi_unsupported.h; sourceTree = "<group>"; };
E4F7981D2AD8D86A00669F54 /* SDL_render_unsupported.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_render_unsupported.c; sourceTree = "<group>"; };
@@ -2354,11 +2362,23 @@
path = vulkan;
sourceTree = "<group>";
};
E4F2578B2C81903800FCEAFC /* xr */ = {
isa = PBXGroup;
children = (
E4F257882C81903800FCEAFC /* SDL_gpu_openxr.c */,
E4F257892C81903800FCEAFC /* SDL_openxrdyn.c */,
E4F2578A2C81903800FCEAFC /* SDL_gpu_openxr_c.h */,
E4F2578C2C81903800FCEAFC /* SDL_openxr_internal.h */,
);
path = xr;
sourceTree = "<group>";
};
E4F257872C81903800FCEAFC /* gpu */ = {
isa = PBXGroup;
children = (
E4F257812C81903800FCEAFC /* metal */,
E4F257842C81903800FCEAFC /* vulkan */,
E4F2578B2C81903800FCEAFC /* xr */,
E4F257852C81903800FCEAFC /* SDL_gpu.c */,
E4F257862C81903800FCEAFC /* SDL_sysgpu.h */,
);
@@ -2946,6 +2966,8 @@
A7D8A95723E2514000DCD162 /* SDL_atomic.c in Sources */,
A75FDBCE23EA380300529352 /* SDL_hidapi_rumble.c in Sources */,
E4F257952C81903800FCEAFC /* SDL_gpu_vulkan.c in Sources */,
E4F257982C81903800FCEAFC /* SDL_gpu_openxr.c in Sources */,
E4F257992C81903800FCEAFC /* SDL_openxrdyn.c in Sources */,
A7D8BB2723E2514500DCD162 /* SDL_displayevents.c in Sources */,
A7D8AB2523E2514100DCD162 /* SDL_log.c in Sources */,
A7D8AE8823E2514100DCD162 /* SDL_cocoaopengl.m in Sources */,

View File

@@ -2364,6 +2364,20 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER "SDL.gpu.device.create.vulkan.options"
#define SDL_PROP_GPU_DEVICE_CREATE_METAL_ALLOW_MACFAMILY1_BOOLEAN "SDL.gpu.device.create.metal.allowmacfamily1"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN "SDL.gpu.device.create.xr.enable"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER "SDL.gpu.device.create.xr.instance_out"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER "SDL.gpu.device.create.xr.system_id_out"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER "SDL.gpu.device.create.xr.version"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER "SDL.gpu.device.create.xr.form_factor"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_COUNT_NUMBER "SDL.gpu.device.create.xr.extensions.count"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_NAMES_POINTER "SDL.gpu.device.create.xr.extensions.names"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_COUNT_NUMBER "SDL.gpu.device.create.xr.layers.count"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_NAMES_POINTER "SDL.gpu.device.create.xr.layers.names"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_NAME_STRING "SDL.gpu.device.create.xr.application.name"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_VERSION_NUMBER "SDL.gpu.device.create.xr.application.version"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_NAME_STRING "SDL.gpu.device.create.xr.engine.name"
#define SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_VERSION_NUMBER "SDL.gpu.device.create.xr.engine.version"
/**
* A structure specifying additional options when using Vulkan.

View File

@@ -1145,6 +1145,18 @@ extern "C" {
*/
#define SDL_HINT_GPU_DRIVER "SDL_GPU_DRIVER"
/**
* A variable that specifies the library name to use when loading the OpenXR loader.
*
* By default, SDL will try the system default name, but on some platforms like Windows,
* debug builds of the OpenXR loader have a different name, and are not always directly compatible with release applications.
* Setting this hint allows you to compensate for this difference in your app when applicable.
*
* This hint should be set before the OpenXR loader is loaded.
* For example, creating an OpenXR GPU device will load the OpenXR loader.
*/
#define SDL_HINT_OPENXR_LIBRARY "SDL_OPENXR_LIBRARY"
/**
* A variable to control whether SDL_hid_enumerate() enumerates all HID
* devices or only controllers.

207
include/SDL3/SDL_openxr.h Normal file
View File

@@ -0,0 +1,207 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/**
* # CategoryOpenXR
*
* Functions for creating OpenXR handles for SDL_gpu contexts.
*
* For the most part, OpenXR operates independent of SDL, but
* the graphics initialization depends on direct support from SDL_gpu.
*
*/
#ifndef SDL_openxr_h_
#define SDL_openxr_h_
#include <SDL3/SDL_stdinc.h>
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_begin_code.h>
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
extern "C" {
#endif
#if defined(OPENXR_H_)
#define NO_SDL_OPENXR_TYPEDEFS 1
#endif /* OPENXR_H_ */
#if !defined(NO_SDL_OPENXR_TYPEDEFS)
#define XR_NULL_HANDLE 0
#if !defined(XR_DEFINE_HANDLE)
#define XR_DEFINE_HANDLE(object) typedef Uint64 object;
#endif /* XR_DEFINE_HANDLE */
typedef enum XrStructureType {
XR_TYPE_SESSION_CREATE_INFO = 8,
XR_TYPE_SWAPCHAIN_CREATE_INFO = 9,
} XrStructureType;
XR_DEFINE_HANDLE(XrInstance)
XR_DEFINE_HANDLE(XrSystemId)
XR_DEFINE_HANDLE(XrSession)
XR_DEFINE_HANDLE(XrSwapchain)
typedef struct {
XrStructureType type;
const void* next;
} XrSessionCreateInfo;
typedef struct {
XrStructureType type;
const void* next;
} XrSwapchainCreateInfo;
typedef enum XrResult {
XR_ERROR_FUNCTION_UNSUPPORTED = -7,
XR_ERROR_HANDLE_INVALID = -12,
} XrResult;
#define PFN_xrGetInstanceProcAddr SDL_FunctionPointer
#endif /* NO_SDL_OPENXR_TYPEDEFS */
/**
* Creates an OpenXR session. The OpenXR system ID is pulled from the passed GPU context.
*
* \param device a GPU context.
* \param createinfo the create info for the OpenXR session, sans the system ID.
* \param session a pointer filled in with an OpenXR session created for the given device.
* \returns the result of the call.
*
* \sa SDL_CreateGPUDeviceWithProperties
*/
extern SDL_DECLSPEC XrResult SDLCALL SDL_CreateGPUXRSession(SDL_GPUDevice *device, const XrSessionCreateInfo *createinfo, XrSession *session);
/**
* Queries the GPU device for supported XR swapchain image formats.
*
* The returned pointer should be allocated with SDL_malloc() and will be
* passed to SDL_free().
*
* \param device a GPU context.
* \param session an OpenXR session created for the given device.
* \param num_formats a pointer filled with the number of supported XR swapchain formats.
* \returns a 0 terminated array of supported formats or NULL on failure;
* call SDL_GetError() for more information. This should be freed
* with SDL_free() when it is no longer needed.
*
* \sa SDL_CreateGPUXRSwapchain
*/
extern SDL_DECLSPEC SDL_GPUTextureFormat * SDLCALL SDL_GetGPUXRSwapchainFormats(SDL_GPUDevice *device, XrSession session, int *num_formats);
/**
* Creates an OpenXR swapchain.
*
* The array returned via `textures` is sized according to
*`xrEnumerateSwapchainImages`, and thus should only be accessed via index
* values returned from `xrAcquireSwapchainImage`.
*
* Applications are still allowed to call `xrEnumerateSwapchainImages` on the
* returned XrSwapchain if they need to get the exact size of the array.
*
* \param device a GPU context.
* \param session an OpenXR session created for the given device.
* \param createinfo the create info for the OpenXR swapchain, sans the format.
* \param format a supported format for the OpenXR swapchain.
* \param swapchain a pointer filled in with the created OpenXR swapchain.
* \param textures a pointer filled in with the array of created swapchain images.
* \returns the result of the call.
*
* \sa SDL_CreateGPUDeviceWithProperties
* \sa SDL_CreateGPUXRSession
* \sa SDL_GetGPUXRSwapchainFormats
* \sa SDL_DestroyGPUXRSwapchain
*/
extern SDL_DECLSPEC XrResult SDLCALL SDL_CreateGPUXRSwapchain(
SDL_GPUDevice *device,
XrSession session,
const XrSwapchainCreateInfo *createinfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures);
/**
* Destroys and OpenXR swapchain previously returned by SDL_CreateGPUXRSwapchain.
*
* \param device a GPU context.
* \param swapchain a swapchain previously returned by SDL_CreateGPUXRSwapchain.
* \param swapchainImages an array of swapchain images returned by the same call to SDL_CreateGPUXRSwapchain.
* \returns the result of the call.
*
* \sa SDL_CreateGPUDeviceWithProperties
* \sa SDL_CreateGPUXRSession
* \sa SDL_CreateGPUXRSwapchain
*/
extern SDL_DECLSPEC XrResult SDLCALL SDL_DestroyGPUXRSwapchain(SDL_GPUDevice *device, XrSwapchain swapchain, SDL_GPUTexture **swapchainImages);
/**
* Dynamically load the OpenXR loader. This can be called at any time.
*
* SDL keeps a reference count of the OpenXR loader, calling this function multiple
* times will increment that count, rather than loading the library multiple times.
*
* If not called, this will be implicitly called when creating a GPU device with OpenXR.
*
* This function will use the platform default OpenXR loader name,
* unless the `SDL_HINT_OPENXR_LIBRARY` hint is set.
*
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
* \threadsafety This function is not thread safe.
*
* \sa SDL_HINT_OPENXR_LIBRARY
*/
extern SDL_DECLSPEC bool SDLCALL SDL_OpenXR_LoadLibrary(void);
/**
* Unload the OpenXR loader previously loaded by SDL_OpenXR_LoadLibrary.
*
* SDL keeps a reference count of the OpenXR loader, calling this function will decrement that count.
* Once the reference count reaches zero, the library is unloaded.
*
* \threadsafety This function is not thread safe.
*/
extern SDL_DECLSPEC void SDLCALL SDL_OpenXR_UnloadLibrary(void);
/**
* Get the address of the `xrGetInstanceProcAddr` function.
*
* This should be called after either calling SDL_OpenXR_LoadLibrary() or
* creating an OpenXR SDL_GPUDevice.
*
* The actual type of the returned function pointer is PFN_xrGetInstanceProcAddr,
* but that isn't always available. You should include the OpenXR headers before this header,
* or cast the return value of this function to the correct type.
*
* \returns the function pointer for `xrGetInstanceProcAddr` or NULL on
* failure; call SDL_GetError() for more information.
*/
extern SDL_DECLSPEC PFN_xrGetInstanceProcAddr SDLCALL SDL_OpenXR_GetXrGetInstanceProcAddr(void);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
#endif
#include <SDL3/SDL_close_code.h>
#endif /* SDL_openxr_h_ */

View File

@@ -488,6 +488,7 @@
#cmakedefine SDL_GPU_D3D12 1
#cmakedefine SDL_GPU_VULKAN 1
#cmakedefine SDL_GPU_METAL 1
#cmakedefine HAVE_GPU_OPENXR 1
#cmakedefine SDL_GPU_PRIVATE 1

View File

@@ -193,6 +193,7 @@
#define SDL_VIDEO_VULKAN 1
#define SDL_VIDEO_RENDER_VULKAN 1
#define SDL_GPU_VULKAN 1
#define HAVE_GPU_OPENXR 1
#define SDL_VIDEO_RENDER_GPU 1
#endif

View File

@@ -289,6 +289,7 @@ typedef unsigned int uintptr_t;
#endif
#define SDL_GPU_D3D12 1
#define SDL_GPU_VULKAN 1
#define HAVE_GPU_OPENXR 1
#define SDL_VIDEO_RENDER_GPU 1
/* Enable system power support */

View File

@@ -233,6 +233,7 @@
#undef SDL_GPU_D3D12
#undef SDL_GPU_METAL
#undef SDL_GPU_VULKAN
#undef HAVE_GPU_OPENXR
#undef SDL_VIDEO_RENDER_GPU
#endif // SDL_GPU_DISABLED

View File

@@ -38,6 +38,7 @@
#endif
#include <SDL3/SDL.h>
#include <SDL3/SDL_openxr.h>
#define SDL_MAIN_NOIMPL // don't drag in header-only implementation of SDL_main
#include <SDL3/SDL_main.h>
#include "../core/SDL_core_unsupported.h"
@@ -597,6 +598,7 @@ static void SDL_InitDynamicAPI(void)
#else // SDL_DYNAMIC_API
#include <SDL3/SDL.h>
#include <SDL3/SDL_openxr.h>
Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize);
Sint32 SDL_DYNAPI_entry(Uint32 apiver, void *table, Uint32 tablesize)

View File

@@ -1272,6 +1272,13 @@ SDL3_0.0.0 {
SDL_LoadSurface;
SDL_SetWindowFillDocument;
SDL_TryLockJoysticks;
SDL_CreateGPUXRSession;
SDL_GetGPUXRSwapchainFormats;
SDL_CreateGPUXRSwapchain;
SDL_DestroyGPUXRSwapchain;
SDL_OpenXR_LoadLibrary;
SDL_OpenXR_UnloadLibrary;
SDL_OpenXR_GetXrGetInstanceProcAddr;
# extra symbols go here (don't modify this line)
local: *;
};

View File

@@ -1298,3 +1298,10 @@
#define SDL_LoadSurface SDL_LoadSurface_REAL
#define SDL_SetWindowFillDocument SDL_SetWindowFillDocument_REAL
#define SDL_TryLockJoysticks SDL_TryLockJoysticks_REAL
#define SDL_CreateGPUXRSession SDL_CreateGPUXRSession_REAL
#define SDL_GetGPUXRSwapchainFormats SDL_GetGPUXRSwapchainFormats_REAL
#define SDL_CreateGPUXRSwapchain SDL_CreateGPUXRSwapchain_REAL
#define SDL_DestroyGPUXRSwapchain SDL_DestroyGPUXRSwapchain_REAL
#define SDL_OpenXR_LoadLibrary SDL_OpenXR_LoadLibrary_REAL
#define SDL_OpenXR_UnloadLibrary SDL_OpenXR_UnloadLibrary_REAL
#define SDL_OpenXR_GetXrGetInstanceProcAddr SDL_OpenXR_GetXrGetInstanceProcAddr_REAL

View File

@@ -1306,3 +1306,10 @@ SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadSurface_IO,(SDL_IOStream *a,bool b),(a,b),r
SDL_DYNAPI_PROC(SDL_Surface*,SDL_LoadSurface,(const char *a),(a),return)
SDL_DYNAPI_PROC(bool,SDL_SetWindowFillDocument,(SDL_Window *a,bool b),(a,b),return)
SDL_DYNAPI_PROC(bool,SDL_TryLockJoysticks,(void),(),return)
SDL_DYNAPI_PROC(XrResult,SDL_CreateGPUXRSession,(SDL_GPUDevice *a,const XrSessionCreateInfo *b,XrSession *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_GPUTextureFormat*,SDL_GetGPUXRSwapchainFormats,(SDL_GPUDevice *a,XrSession b,int *c),(a,b,c),return)
SDL_DYNAPI_PROC(XrResult,SDL_CreateGPUXRSwapchain,(SDL_GPUDevice *a,XrSession b,const XrSwapchainCreateInfo *c,SDL_GPUTextureFormat d,XrSwapchain *e,SDL_GPUTexture ***f),(a,b,c,d,e,f),return)
SDL_DYNAPI_PROC(XrResult,SDL_DestroyGPUXRSwapchain,(SDL_GPUDevice *a,XrSwapchain b,SDL_GPUTexture **c),(a,b,c),return)
SDL_DYNAPI_PROC(bool,SDL_OpenXR_LoadLibrary,(void),(),return)
SDL_DYNAPI_PROC(void,SDL_OpenXR_UnloadLibrary,(void),(),)
SDL_DYNAPI_PROC(PFN_xrGetInstanceProcAddr,SDL_OpenXR_GetXrGetInstanceProcAddr,(void),(),return)

View File

@@ -607,6 +607,13 @@ static const SDL_GPUBootstrap * SDL_GPUSelectBackend(SDL_PropertiesID props)
return NULL;
}
#ifndef HAVE_GPU_OPENXR
if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false)) {
SDL_SetError("OpenXR is not enabled in this build of SDL");
return NULL;
}
#endif
gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER);
if (gpudriver == NULL) {
gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL);
@@ -752,6 +759,13 @@ void SDL_DestroyGPUDevice(SDL_GPUDevice *device)
device->DestroyDevice(device);
}
XrResult SDL_DestroyGPUXRSwapchain(SDL_GPUDevice *device, XrSwapchain swapchain, SDL_GPUTexture **swapchainImages)
{
CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
return device->DestroyXRSwapchain(device->driverData, swapchain, swapchainImages);
}
int SDL_GetNumGPUDrivers(void)
{
#ifndef SDL_GPU_DISABLED
@@ -3567,3 +3581,36 @@ SDL_GPUTextureFormat SDL_GetGPUTextureFormatFromPixelFormat(SDL_PixelFormat form
return SDL_GPU_TEXTUREFORMAT_INVALID;
}
}
XrResult SDL_CreateGPUXRSession(
SDL_GPUDevice *device,
const XrSessionCreateInfo *createinfo,
XrSession *session)
{
CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
return device->CreateXRSession(device->driverData, createinfo, session);
}
SDL_GPUTextureFormat* SDL_GetGPUXRSwapchainFormats(
SDL_GPUDevice *device,
XrSession session,
int *num_formats)
{
CHECK_DEVICE_MAGIC(device, NULL);
return device->GetXRSwapchainFormats(device->driverData, session, num_formats);
}
XrResult SDL_CreateGPUXRSwapchain(
SDL_GPUDevice *device,
XrSession session,
const XrSwapchainCreateInfo *createinfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures)
{
CHECK_DEVICE_MAGIC(device, XR_ERROR_HANDLE_INVALID);
return device->CreateXRSwapchain(device->driverData, session, createinfo, format, swapchain, textures);
}

View File

@@ -24,6 +24,8 @@
#ifndef SDL_GPU_DRIVER_H
#define SDL_GPU_DRIVER_H
#include <SDL3/SDL_openxr.h>
// GraphicsDevice Limits
#define MAX_TEXTURE_SAMPLERS_PER_STAGE 16
@@ -669,6 +671,11 @@ struct SDL_GPUDevice
void (*DestroyDevice)(SDL_GPUDevice *device);
XrResult (*DestroyXRSwapchain)(
SDL_GPURenderer *device,
XrSwapchain swapchain,
SDL_GPUTexture **swapchainImages);
SDL_PropertiesID (*GetDeviceProperties)(SDL_GPUDevice *device);
// State Creation
@@ -705,6 +712,24 @@ struct SDL_GPUDevice
Uint32 size,
const char *debugName);
XrResult (*CreateXRSession)(
SDL_GPURenderer *driverData,
const XrSessionCreateInfo *createinfo,
XrSession *session);
SDL_GPUTextureFormat* (*GetXRSwapchainFormats)(
SDL_GPURenderer *driverData,
XrSession session,
int *num_formats);
XrResult (*CreateXRSwapchain)(
SDL_GPURenderer *driverData,
XrSession session,
const XrSwapchainCreateInfo *createinfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures);
// Debug Naming
void (*SetBufferName)(
@@ -1105,6 +1130,7 @@ struct SDL_GPUDevice
result->func = name##_##func;
#define ASSIGN_DRIVER(name) \
ASSIGN_DRIVER_FUNC(DestroyDevice, name) \
ASSIGN_DRIVER_FUNC(DestroyXRSwapchain, name) \
ASSIGN_DRIVER_FUNC(GetDeviceProperties, name) \
ASSIGN_DRIVER_FUNC(CreateComputePipeline, name) \
ASSIGN_DRIVER_FUNC(CreateGraphicsPipeline, name) \
@@ -1113,6 +1139,9 @@ struct SDL_GPUDevice
ASSIGN_DRIVER_FUNC(CreateTexture, name) \
ASSIGN_DRIVER_FUNC(CreateBuffer, name) \
ASSIGN_DRIVER_FUNC(CreateTransferBuffer, name) \
ASSIGN_DRIVER_FUNC(CreateXRSession, name) \
ASSIGN_DRIVER_FUNC(GetXRSwapchainFormats, name) \
ASSIGN_DRIVER_FUNC(CreateXRSwapchain, name) \
ASSIGN_DRIVER_FUNC(SetBufferName, name) \
ASSIGN_DRIVER_FUNC(SetTextureName, name) \
ASSIGN_DRIVER_FUNC(InsertDebugLabel, name) \

View File

@@ -26,6 +26,14 @@
#include "../../events/SDL_windowevents_c.h"
#include "../../core/windows/SDL_windows.h"
#include "../../video/directx/SDL_d3d12.h"
#ifdef HAVE_GPU_OPENXR
#define XR_USE_GRAPHICS_API_D3D12 1
#include "../xr/SDL_openxr_internal.h"
#include "../xr/SDL_openxrdyn.h"
#include "../xr/SDL_gpu_openxr.h"
#endif
#include "../SDL_sysgpu.h"
#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
@@ -584,6 +592,30 @@ static DXGI_FORMAT SDLToD3D12_TypelessFormat[] = {
};
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TypelessFormat, SDL_arraysize(SDLToD3D12_TypelessFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
#ifdef HAVE_GPU_OPENXR
// For XR sRGB format selection - maps DXGI sRGB formats to SDL formats
typedef struct TextureFormatPair
{
DXGI_FORMAT dxgi;
SDL_GPUTextureFormat sdl;
} TextureFormatPair;
static TextureFormatPair SDLToD3D12_TextureFormat_SrgbOnly[] = {
{ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB },
{ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB },
{ DXGI_FORMAT_BC1_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB },
{ DXGI_FORMAT_BC2_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB },
{ DXGI_FORMAT_BC3_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB },
{ DXGI_FORMAT_BC7_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB },
};
// Forward declarations for XR helper functions
static bool D3D12_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension);
static XrResult D3D12_INTERNAL_GetXrGraphicsRequirements(XrInstance instance, XrSystemId systemId, D3D_FEATURE_LEVEL *minimumFeatureLevel, LUID *adapter);
static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter);
static bool D3D12_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 supportedFormatsCount, SDL_GPUTextureFormat *sdlFormat, DXGI_FORMAT *dxgiFormat);
#endif /* HAVE_GPU_OPENXR */
static D3D12_COMPARISON_FUNC SDLToD3D12_CompareOp[] = {
D3D12_COMPARISON_FUNC_NEVER, // INVALID
D3D12_COMPARISON_FUNC_NEVER, // NEVER
@@ -789,6 +821,9 @@ typedef struct D3D12TextureContainer
bool canBeCycled;
char *debugName;
// XR swapchain images are managed by OpenXR runtime
bool externallyManaged;
} D3D12TextureContainer;
// Null views represent by heap = NULL
@@ -819,6 +854,9 @@ struct D3D12Texture
D3D12StagingDescriptor srvHandle;
SDL_AtomicInt referenceCount;
// XR swapchain images are managed by OpenXR runtime
bool externallyManaged;
};
typedef struct D3D12Sampler
@@ -977,6 +1015,13 @@ struct D3D12Renderer
SDL_Mutex *windowLock;
SDL_Mutex *fenceLock;
SDL_Mutex *disposeLock;
#ifdef HAVE_GPU_OPENXR
// OpenXR state
XrInstance xrInstance;
XrSystemId xrSystemId;
XrInstancePfns *xr;
#endif
};
struct D3D12CommandBuffer
@@ -1409,7 +1454,8 @@ static void D3D12_INTERNAL_DestroyTexture(
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&texture->srvHandle);
if (texture->resource) {
// XR swapchain images are owned by the OpenXR runtime
if (texture->resource && !texture->externallyManaged) {
ID3D12Resource_Release(texture->resource);
}
@@ -8623,6 +8669,25 @@ static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
return false;
}
#ifdef HAVE_GPU_OPENXR
// Check for OpenXR support if requested
bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
if (xr) {
if (!SDL_OpenXR_LoadLibrary()) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to load OpenXR");
return false;
}
XrExtensionProperties gpuExtension;
if (!D3D12_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find " XR_KHR_D3D12_ENABLE_EXTENSION_NAME " extension");
SDL_OpenXR_UnloadLibrary();
return false;
}
SDL_OpenXR_UnloadLibrary();
}
#endif
return true;
#endif
}
@@ -8824,6 +8889,403 @@ static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoLogger(D3D12Renderer *rend
}
#endif
// OpenXR D3D12 Support
#ifdef HAVE_GPU_OPENXR
static bool D3D12_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension)
{
XrResult result;
Uint32 extension_count;
Uint32 i;
result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL);
if (result != XR_SUCCESS) {
return false;
}
XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties));
for (i = 0; i < extension_count; i++) {
extension_properties[i] = (XrExtensionProperties){ XR_TYPE_EXTENSION_PROPERTIES };
}
result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties);
if (result != XR_SUCCESS) {
SDL_free(extension_properties);
return false;
}
for (i = 0; i < extension_count; i++) {
XrExtensionProperties extension = extension_properties[i];
if (SDL_strcmp(extension.extensionName, XR_KHR_D3D12_ENABLE_EXTENSION_NAME) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_D3D12_ENABLE_EXTENSION_NAME " extension");
*found_extension = extension;
SDL_free(extension_properties);
return true;
}
}
SDL_free(extension_properties);
return false;
}
static XrResult D3D12_INTERNAL_GetXrGraphicsRequirements(XrInstance instance, XrSystemId systemId, D3D_FEATURE_LEVEL *minimumFeatureLevel, LUID *adapter)
{
XrResult xrResult;
PFN_xrGetD3D12GraphicsRequirementsKHR xrGetD3D12GraphicsRequirementsKHR;
if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction *)&xrGetD3D12GraphicsRequirementsKHR)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetD3D12GraphicsRequirementsKHR");
return xrResult;
}
XrGraphicsRequirementsD3D12KHR graphicsRequirementsD3D12 = { XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR };
if ((xrResult = xrGetD3D12GraphicsRequirementsKHR(instance, systemId, &graphicsRequirementsD3D12)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get D3D12 graphics requirements, got OpenXR error %d", xrResult);
return xrResult;
}
*adapter = graphicsRequirementsD3D12.adapterLuid;
*minimumFeatureLevel = graphicsRequirementsD3D12.minFeatureLevel;
return XR_SUCCESS;
}
static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter)
{
HRESULT res;
// We need to iterate over all the adapters in the system to find the one with the matching LUID
for (Uint32 adapterIndex = 0;; adapterIndex++) {
// EnumAdapters1 will fail with DXGI_ERROR_NOT_FOUND when there are no more adapters to enumerate.
IDXGIAdapter1 *adapter;
res = IDXGIFactory1_EnumAdapters1(factory, adapterIndex, &adapter);
if (FAILED(res)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get an adapter when iterating, i: %d, res: %ld", adapterIndex, res);
return false;
}
DXGI_ADAPTER_DESC1 adapterDesc;
res = IDXGIAdapter1_GetDesc1(adapter, &adapterDesc);
if (FAILED(res)) {
IDXGIAdapter1_Release(adapter);
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get description of adapter, i: %d, res %ld", adapterIndex, res);
return false;
}
if (SDL_memcmp(&adapterDesc.AdapterLuid, &luid, sizeof(luid)) == 0) {
*outAdapter = adapter;
return true;
}
IDXGIAdapter1_Release(adapter);
}
}
static bool D3D12_INTERNAL_FindXRSrgbSwapchain(
int64_t *supportedFormats,
Uint32 supportedFormatsCount,
SDL_GPUTextureFormat *sdlFormat,
DXGI_FORMAT *dxgiFormat)
{
for (Uint32 i = 0; i < SDL_arraysize(SDLToD3D12_TextureFormat_SrgbOnly); i++) {
for (Uint32 j = 0; j < supportedFormatsCount; j++) {
if (SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi == supportedFormats[j]) {
*sdlFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].sdl;
*dxgiFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi;
return true;
}
}
}
return false;
}
#endif /* HAVE_GPU_OPENXR */
static XrResult D3D12_DestroyXRSwapchain(
SDL_GPURenderer *driverData,
XrSwapchain swapchain,
SDL_GPUTexture **swapchainImages)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12_Wait(driverData);
Uint32 swapchainCount;
result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL);
if (result != XR_SUCCESS) {
return result;
}
// We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason
for (Uint32 i = 0; i < swapchainCount; i++) {
D3D12Texture *container = (D3D12Texture *)swapchainImages[i];
if (!container->externallyManaged) {
SDL_SetError("Invalid GPU Texture handle.");
return XR_ERROR_HANDLE_INVALID;
}
D3D12_INTERNAL_DestroyTexture(container);
// Free the container now that it's unused
SDL_free(container);
}
SDL_free(swapchainImages);
return renderer->xr->xrDestroySwapchain(swapchain);
#else
(void)driverData;
(void)swapchain;
(void)swapchainImages;
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
static SDL_GPUTextureFormat* D3D12_GetXRSwapchainFormats(
SDL_GPURenderer *driverData,
XrSession session,
int *num_formats)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
Uint32 i, j, num_supported_formats;
int64_t *supported_formats;
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL);
if (result != XR_SUCCESS) {
return NULL;
}
supported_formats = SDL_stack_alloc(int64_t, num_supported_formats);
result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats);
if (result != XR_SUCCESS) {
SDL_stack_free(supported_formats);
return NULL;
}
// FIXME: For now we're just searching for the optimal format, not all supported formats.
// FIXME: Expand this search for all SDL_GPU formats!
SDL_GPUTextureFormat sdlFormat;
DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN;
// The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list
if (!D3D12_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &dxgiFormat)) {
// Iterate over all formats the runtime supports
for (i = 0; i < num_supported_formats && dxgiFormat == DXGI_FORMAT_UNKNOWN; i++) {
// Iterate over all formats we support
for (j = 0; j < SDL_arraysize(SDLToD3D12_TextureFormat); j++) {
// Pick the first format the runtime wants that we also support, the runtime should return these in order of preference
if (SDLToD3D12_TextureFormat[j] == supported_formats[i]) {
dxgiFormat = (DXGI_FORMAT)supported_formats[i];
sdlFormat = j;
break;
}
}
}
}
SDL_stack_free(supported_formats);
if (dxgiFormat == DXGI_FORMAT_UNKNOWN) {
SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL");
return NULL;
}
SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2);
retval[0] = sdlFormat;
retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID;
*num_formats = 1;
return retval;
#else
SDL_SetError("SDL not built with OpenXR support");
return NULL;
#endif
}
static XrResult D3D12_CreateXRSwapchain(
SDL_GPURenderer *driverData,
XrSession session,
const XrSwapchainCreateInfo *oldCreateInfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
Uint32 layerIndex, levelIndex;
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
XrSwapchainCreateInfo createInfo = *oldCreateInfo;
createInfo.format = SDLToD3D12_TextureFormat[format];
result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain);
if (result != XR_SUCCESS) {
return result;
}
Uint32 swapchainImageCount;
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL);
if (result != XR_SUCCESS) {
return result;
}
XrSwapchainImageD3D12KHR *swapchainImages = (XrSwapchainImageD3D12KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageD3D12KHR));
for (layerIndex = 0; layerIndex < swapchainImageCount; layerIndex++) {
swapchainImages[layerIndex].type = XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR;
}
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages);
if (result != XR_SUCCESS) {
SDL_free(swapchainImages);
return result;
}
D3D12TextureContainer **textureContainers = (D3D12TextureContainer **)SDL_calloc(swapchainImageCount, sizeof(D3D12TextureContainer *));
Uint32 depth = 1;
for (Uint32 idx = 0; idx < swapchainImageCount; idx++) {
ID3D12Resource *d3d12Texture = swapchainImages[idx].texture;
D3D12Texture *texture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture));
texture->resource = d3d12Texture;
texture->externallyManaged = true;
SDL_SetAtomicInt(&texture->referenceCount, 0);
texture->subresourceCount = createInfo.arraySize * createInfo.mipCount;
texture->subresources = (D3D12TextureSubresource *)SDL_calloc(
texture->subresourceCount,
sizeof(D3D12TextureSubresource));
for (layerIndex = 0; layerIndex < createInfo.arraySize; layerIndex += 1) {
for (levelIndex = 0; levelIndex < createInfo.mipCount; levelIndex += 1) {
Uint32 subresourceIndex = D3D12_INTERNAL_CalcSubresource(
levelIndex,
layerIndex,
createInfo.mipCount);
texture->subresources[subresourceIndex].parent = texture;
texture->subresources[subresourceIndex].layer = layerIndex;
texture->subresources[subresourceIndex].level = levelIndex;
texture->subresources[subresourceIndex].depth = depth;
texture->subresources[subresourceIndex].index = subresourceIndex;
texture->subresources[subresourceIndex].rtvHandles = NULL;
texture->subresources[subresourceIndex].uavHandle.heap = NULL;
texture->subresources[subresourceIndex].dsvHandle.heap = NULL;
if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) {
texture->subresources[subresourceIndex].rtvHandles = (D3D12StagingDescriptor *)SDL_calloc(depth, sizeof(D3D12StagingDescriptor));
for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) {
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
&texture->subresources[subresourceIndex].rtvHandles[depthIndex]);
rtvDesc.Format = SDLToD3D12_TextureFormat[format];
// For XR we typically use 2D array textures for stereo rendering
if (createInfo.arraySize > 1) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = levelIndex;
rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
rtvDesc.Texture2DArray.ArraySize = 1;
rtvDesc.Texture2DArray.PlaneSlice = 0;
} else {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = levelIndex;
rtvDesc.Texture2D.PlaneSlice = 0;
}
ID3D12Device_CreateRenderTargetView(
renderer->device,
texture->resource,
&rtvDesc,
texture->subresources[subresourceIndex].rtvHandles[depthIndex].cpuHandle);
}
}
}
}
textureContainers[idx] = (D3D12TextureContainer *)SDL_malloc(sizeof(D3D12TextureContainer));
D3D12TextureContainer *container = textureContainers[idx];
SDL_zero(container->header.info);
container->header.info.width = createInfo.width;
container->header.info.height = createInfo.height;
container->header.info.format = format;
container->header.info.layer_count_or_depth = createInfo.arraySize;
container->header.info.num_levels = createInfo.mipCount;
container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
container->externallyManaged = true;
container->canBeCycled = false;
container->activeTexture = texture;
container->textureCapacity = 1;
container->textureCount = 1;
container->textures = (D3D12Texture **)SDL_malloc(
container->textureCapacity * sizeof(D3D12Texture *));
container->textures[0] = container->activeTexture;
container->debugName = NULL;
texture->container = container;
texture->containerIndex = 0;
}
*textures = (SDL_GPUTexture **)textureContainers;
SDL_free(swapchainImages);
return XR_SUCCESS;
#else
(void)driverData;
(void)session;
(void)oldCreateInfo;
(void)format;
(void)swapchain;
(void)textures;
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
static XrResult D3D12_CreateXRSession(
SDL_GPURenderer *driverData,
const XrSessionCreateInfo *createinfo,
XrSession *session)
{
#ifdef HAVE_GPU_OPENXR
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
// Copy out the existing next ptr so that we can append it to the end of the chain we create
const void *XR_MAY_ALIAS currentNextPtr = createinfo->next;
XrGraphicsBindingD3D12KHR graphicsBinding = { XR_TYPE_GRAPHICS_BINDING_D3D12_KHR };
graphicsBinding.device = renderer->device;
graphicsBinding.queue = renderer->commandQueue;
graphicsBinding.next = currentNextPtr;
XrSessionCreateInfo sessionCreateInfo = *createinfo;
sessionCreateInfo.systemId = renderer->xrSystemId;
sessionCreateInfo.next = &graphicsBinding;
return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session);
#else
(void)driverData;
(void)createinfo;
(void)session;
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
{
SDL_GPUDevice *result;
@@ -8942,29 +9404,100 @@ static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SD
IDXGIFactory5_Release(factory5);
}
// Select the appropriate device for rendering
res = IDXGIFactory4_QueryInterface(
renderer->factory,
D3D_GUID(D3D_IID_IDXGIFactory6),
(void **)&factory6);
if (SUCCEEDED(res)) {
res = IDXGIFactory6_EnumAdapterByGpuPreference(
factory6,
0,
preferLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
D3D_GUID(D3D_IID_IDXGIAdapter1),
(void **)&renderer->adapter);
IDXGIFactory6_Release(factory6);
} else {
res = IDXGIFactory4_EnumAdapters1(
renderer->factory,
0,
&renderer->adapter);
}
#ifdef HAVE_GPU_OPENXR
bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
XrInstance *xrInstance = (XrInstance *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL);
XrSystemId *xrSystemId = (XrSystemId *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL);
D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0;
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not find adapter for D3D12Device", NULL);
if (xr) {
XrExtensionProperties gpuExtension;
if (!xrInstance) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("You must specify an out pointer for the OpenXR instance", NULL);
}
if (!xrSystemId) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("You must specify an out pointer for the OpenXR system ID", NULL);
}
if (!SDL_OpenXR_LoadLibrary()) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("This should have failed in PrepareDevice first!", NULL);
}
if (!D3D12_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR D3D12 extension");
SDL_OpenXR_UnloadLibrary();
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Failed to find XR_KHR_D3D12_enable extension", NULL);
}
if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR");
SDL_OpenXR_UnloadLibrary();
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Failed to initialize OpenXR", NULL);
}
renderer->xrInstance = *xrInstance;
renderer->xrSystemId = *xrSystemId;
LUID xrAdapter;
if (D3D12_INTERNAL_GetXrGraphicsRequirements(*xrInstance, *xrSystemId, &featureLevel, &xrAdapter) != XR_SUCCESS) {
SDL_OpenXR_UnloadLibrary();
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Failed to get XR graphics requirements", NULL);
}
// Need factory1 again for adapter enumeration
IDXGIFactory1 *factory1ForXr;
res = pCreateDXGIFactory1(
&D3D_IID_IDXGIFactory1,
(void **)&factory1ForXr);
if (FAILED(res)) {
SDL_OpenXR_UnloadLibrary();
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create DXGIFactory for XR adapter lookup", NULL);
}
if (!D3D12_INTERNAL_GetAdapterByLuid(xrAdapter, factory1ForXr, &renderer->adapter)) {
IDXGIFactory1_Release(factory1ForXr);
SDL_OpenXR_UnloadLibrary();
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Failed to find adapter matching XR LUID", NULL);
}
IDXGIFactory1_Release(factory1ForXr);
} else
#endif /* HAVE_GPU_OPENXR */
{
// Select the appropriate device for rendering
res = IDXGIFactory4_QueryInterface(
renderer->factory,
D3D_GUID(D3D_IID_IDXGIFactory6),
(void **)&factory6);
if (SUCCEEDED(res)) {
res = IDXGIFactory6_EnumAdapterByGpuPreference(
factory6,
0,
preferLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
D3D_GUID(D3D_IID_IDXGIAdapter1),
(void **)&renderer->adapter);
IDXGIFactory6_Release(factory6);
} else {
res = IDXGIFactory4_EnumAdapters1(
renderer->factory,
0,
&renderer->adapter);
}
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not find adapter for D3D12Device", NULL);
}
}
// Get information about the selected adapter. Used for logging info.

View File

@@ -26,6 +26,12 @@
#include <Metal/Metal.h>
#include <QuartzCore/CoreAnimation.h>
#ifdef HAVE_GPU_OPENXR
#define XR_USE_GRAPHICS_API_METAL 1
#include "../xr/SDL_openxr_internal.h"
#include "../xr/SDL_openxrdyn.h"
#endif
#include "../SDL_sysgpu.h"
// Defines
@@ -4337,6 +4343,10 @@ static bool METAL_SupportsTextureFormat(
static bool METAL_PrepareDriver(SDL_VideoDevice *this, SDL_PropertiesID props)
{
if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false)) {
return false;
}
if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN, false) &&
!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN, false)) {
return false;
@@ -4499,6 +4509,45 @@ static void METAL_INTERNAL_DestroyBlitResources(
SDL_free(renderer->blitPipelines);
}
static XrResult METAL_DestroyXRSwapchain(
SDL_GPURenderer *driverData,
XrSwapchain swapchain,
SDL_GPUTexture **swapchainImages)
{
SDL_SetError("The metal backend does not currently support OpenXR");
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
static SDL_GPUTextureFormat* METAL_GetXRSwapchainFormats(
SDL_GPURenderer *driverData,
XrSession session,
int *num_formats)
{
SDL_SetError("The metal backend does not currently support OpenXR");
return NULL;
}
static XrResult METAL_CreateXRSwapchain(
SDL_GPURenderer *driverData,
XrSession session,
const XrSwapchainCreateInfo *oldCreateInfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures)
{
SDL_SetError("The metal backend does not currently support OpenXR");
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
static XrResult METAL_CreateXRSession(
SDL_GPURenderer *driverData,
const XrSessionCreateInfo *createinfo,
XrSession *session)
{
SDL_SetError("The metal backend does not currently support OpenXR");
return XR_ERROR_FUNCTION_UNSUPPORTED;
}
static SDL_GPUDevice *METAL_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
{
@autoreleasepool {

View File

@@ -29,6 +29,13 @@
#define VK_NO_PROTOTYPES
#include "../../video/khronos/vulkan/vulkan.h"
#ifdef HAVE_GPU_OPENXR
#define XR_USE_GRAPHICS_API_VULKAN 1
#include "../xr/SDL_openxr_internal.h"
#include "../xr/SDL_openxrdyn.h"
#include "../xr/SDL_gpu_openxr.h"
#endif
#include <SDL3/SDL_vulkan.h>
#include "../SDL_sysgpu.h"
@@ -88,6 +95,37 @@ static VkPresentModeKHR SDLToVK_PresentMode[] = {
VK_PRESENT_MODE_MAILBOX_KHR
};
// NOTE: this is behind an ifdef guard because without, it would trigger an "unused variable" error when OpenXR support is disabled
#ifdef HAVE_GPU_OPENXR
typedef struct TextureFormatPair {
VkFormat vk;
SDL_GPUTextureFormat sdl;
} TextureFormatPair;
static TextureFormatPair SDLToVK_TextureFormat_SrgbOnly[] = {
{VK_FORMAT_R8G8B8A8_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB},
{VK_FORMAT_B8G8R8A8_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB},
{VK_FORMAT_BC1_RGBA_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB},
{VK_FORMAT_BC2_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB},
{VK_FORMAT_BC3_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB},
{VK_FORMAT_BC7_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB},
{VK_FORMAT_ASTC_4x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB},
{VK_FORMAT_ASTC_5x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB},
{VK_FORMAT_ASTC_5x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB},
{VK_FORMAT_ASTC_6x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB},
{VK_FORMAT_ASTC_6x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB},
{VK_FORMAT_ASTC_8x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB},
{VK_FORMAT_ASTC_8x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB},
{VK_FORMAT_ASTC_8x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB},
{VK_FORMAT_ASTC_10x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB},
{VK_FORMAT_ASTC_10x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB},
{VK_FORMAT_ASTC_10x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB},
{VK_FORMAT_ASTC_10x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB},
{VK_FORMAT_ASTC_12x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB},
{VK_FORMAT_ASTC_12x12_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB},
};
#endif // HAVE_GPU_OPENXR
static VkFormat SDLToVK_TextureFormat[] = {
VK_FORMAT_UNDEFINED, // INVALID
VK_FORMAT_R8_UNORM, // A8_UNORM
@@ -609,6 +647,7 @@ struct VulkanTexture
VulkanTextureSubresource *subresources;
bool markedForDestroy; // so that defrag doesn't double-free
bool externallyManaged; // true for XR swapchain images
SDL_AtomicInt referenceCount;
};
@@ -624,6 +663,7 @@ struct VulkanTextureContainer
char *debugName;
bool canBeCycled;
bool externallyManaged; // true for XR swapchain images
};
typedef enum VulkanBufferUsageMode
@@ -1113,6 +1153,14 @@ struct VulkanRenderer
Uint8 outofBARMemoryWarning;
Uint8 fillModeOnlyWarning;
// OpenXR
Uint32 minimumVkVersion;
#ifdef HAVE_GPU_OPENXR
XrInstance xrInstance; // a non-null instance also states this vk device was created by OpenXR
XrSystemId xrSystemId;
XrInstancePfns *xr;
#endif
bool debugMode;
bool preferLowPower;
bool requireHardwareAcceleration;
@@ -3026,7 +3074,8 @@ static void VULKAN_INTERNAL_DestroyTexture(
NULL);
}
if (texture->image) {
/* Don't free an externally managed VkImage (e.g. XR swapchain images) */
if (texture->image && !texture->externallyManaged) {
renderer->vkDestroyImage(
renderer->logicalDevice,
texture->image,
@@ -11846,7 +11895,31 @@ static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeat
createInfo.enabledLayerCount = 0;
}
vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance);
#ifdef HAVE_GPU_OPENXR
if (renderer->xrInstance) {
XrResult xrResult;
PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR;
if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanInstanceKHR");
SDL_stack_free((char *)instanceExtensionNames);
return 0;
}
XrVulkanInstanceCreateInfoKHR xrCreateInfo = {XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR};
xrCreateInfo.vulkanCreateInfo = &createInfo;
xrCreateInfo.systemId = renderer->xrSystemId;
xrCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
SDL_assert(xrCreateInfo.pfnGetInstanceProcAddr);
if ((xrResult = xrCreateVulkanInstanceKHR(renderer->xrInstance, &xrCreateInfo, &renderer->instance, &vulkanResult)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create vulkan instance, reason %d, %d", xrResult, vulkanResult);
SDL_stack_free((char *)instanceExtensionNames);
return 0;
}
} else
#endif // HAVE_GPU_OPENXR
{
vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance);
}
SDL_stack_free((char *)instanceExtensionNames);
if (vulkanResult != VK_SUCCESS) {
@@ -12133,87 +12206,139 @@ static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, V
Uint32 suitableQueueFamilyIndex;
Uint64 highestRank;
vulkanResult = renderer->vkEnumeratePhysicalDevices(
renderer->instance,
&physicalDeviceCount,
NULL);
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0);
if (physicalDeviceCount == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support");
return 0;
}
physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount);
physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount);
vulkanResult = renderer->vkEnumeratePhysicalDevices(
renderer->instance,
&physicalDeviceCount,
physicalDevices);
/* This should be impossible to hit, but from what I can tell this can
* be triggered not because the array is too small, but because there
* were drivers that turned out to be bogus, so this is the loader's way
* of telling us that the list is now smaller than expected :shrug:
*/
if (vulkanResult == VK_INCOMPLETE) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway...");
vulkanResult = VK_SUCCESS;
}
if (vulkanResult != VK_SUCCESS) {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"vkEnumeratePhysicalDevices failed: %s",
VkErrorMessages(vulkanResult));
SDL_stack_free(physicalDevices);
SDL_stack_free(physicalDeviceExtensions);
return 0;
}
// Any suitable device will do, but we'd like the best
suitableIndex = -1;
suitableQueueFamilyIndex = 0;
highestRank = 0;
for (i = 0; i < physicalDeviceCount; i += 1) {
#ifdef HAVE_GPU_OPENXR
// When XR is enabled, let the OpenXR runtime choose the physical device
if (renderer->xrInstance) {
XrResult xrResult;
VulkanExtensions xrPhysicalDeviceExtensions;
Uint32 queueFamilyIndex;
Uint64 deviceRank;
PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR;
xrResult = xrGetInstanceProcAddr(
renderer->xrInstance,
"xrGetVulkanGraphicsDevice2KHR",
(PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR);
if (xrResult != XR_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsDevice2KHR, result: %d", xrResult);
return 0;
}
XrVulkanGraphicsDeviceGetInfoKHR graphicsDeviceGetInfo;
SDL_zero(graphicsDeviceGetInfo);
graphicsDeviceGetInfo.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR;
graphicsDeviceGetInfo.systemId = renderer->xrSystemId;
graphicsDeviceGetInfo.vulkanInstance = renderer->instance;
xrResult = xrGetVulkanGraphicsDevice2KHR(
renderer->xrInstance,
&graphicsDeviceGetInfo,
&renderer->physicalDevice);
if (xrResult != XR_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetVulkanGraphicsDevice2KHR failed, result: %d", xrResult);
return 0;
}
// Verify the XR-chosen device is suitable
if (!VULKAN_INTERNAL_IsDeviceSuitable(
renderer,
features,
physicalDevices[i],
&physicalDeviceExtensions[i],
renderer->physicalDevice,
&xrPhysicalDeviceExtensions,
&queueFamilyIndex)) {
// Device does not meet the minimum requirements, skip it entirely
continue;
SDL_LogError(SDL_LOG_CATEGORY_GPU, "The physical device chosen by the OpenXR runtime is not suitable");
return 0;
}
deviceRank = highestRank;
if (VULKAN_INTERNAL_GetDeviceRank(
renderer,
physicalDevices[i],
&physicalDeviceExtensions[i],
&deviceRank)) {
/* Use this for rendering.
* Note that this may override a previous device that
* supports rendering, but shares the same device rank.
*/
suitableIndex = i;
suitableQueueFamilyIndex = queueFamilyIndex;
highestRank = deviceRank;
}
}
renderer->supports = xrPhysicalDeviceExtensions;
renderer->queueFamilyIndex = queueFamilyIndex;
} else
#endif // HAVE_GPU_OPENXR
{
vulkanResult = renderer->vkEnumeratePhysicalDevices(
renderer->instance,
&physicalDeviceCount,
NULL);
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0);
if (physicalDeviceCount == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support");
return 0;
}
physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount);
physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount);
vulkanResult = renderer->vkEnumeratePhysicalDevices(
renderer->instance,
&physicalDeviceCount,
physicalDevices);
/* This should be impossible to hit, but from what I can tell this can
* be triggered not because the array is too small, but because there
* were drivers that turned out to be bogus, so this is the loader's way
* of telling us that the list is now smaller than expected :shrug:
*/
if (vulkanResult == VK_INCOMPLETE) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway...");
vulkanResult = VK_SUCCESS;
}
if (vulkanResult != VK_SUCCESS) {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"vkEnumeratePhysicalDevices failed: %s",
VkErrorMessages(vulkanResult));
SDL_stack_free(physicalDevices);
SDL_stack_free(physicalDeviceExtensions);
return 0;
}
// Any suitable device will do, but we'd like the best
suitableIndex = -1;
suitableQueueFamilyIndex = 0;
highestRank = 0;
for (i = 0; i < physicalDeviceCount; i += 1) {
Uint32 queueFamilyIndex;
Uint64 deviceRank;
if (!VULKAN_INTERNAL_IsDeviceSuitable(
renderer,
features,
physicalDevices[i],
&physicalDeviceExtensions[i],
&queueFamilyIndex)) {
// Device does not meet the minimum requirements, skip it entirely
continue;
}
deviceRank = highestRank;
if (VULKAN_INTERNAL_GetDeviceRank(
renderer,
physicalDevices[i],
&physicalDeviceExtensions[i],
&deviceRank)) {
/* Use this for rendering.
* Note that this may override a previous device that
* supports rendering, but shares the same device rank.
*/
suitableIndex = i;
suitableQueueFamilyIndex = queueFamilyIndex;
highestRank = deviceRank;
}
}
if (suitableIndex != -1) {
renderer->supports = physicalDeviceExtensions[suitableIndex];
renderer->physicalDevice = physicalDevices[suitableIndex];
renderer->queueFamilyIndex = suitableQueueFamilyIndex;
} else {
SDL_stack_free(physicalDevices);
SDL_stack_free(physicalDeviceExtensions);
return 0;
}
if (suitableIndex != -1) {
renderer->supports = physicalDeviceExtensions[suitableIndex];
renderer->physicalDevice = physicalDevices[suitableIndex];
renderer->queueFamilyIndex = suitableQueueFamilyIndex;
} else {
SDL_stack_free(physicalDevices);
SDL_stack_free(physicalDeviceExtensions);
return 0;
}
renderer->physicalDeviceProperties.sType =
@@ -12241,8 +12366,6 @@ static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, V
renderer->physicalDevice,
&renderer->memoryProperties);
SDL_stack_free(physicalDevices);
SDL_stack_free(physicalDeviceExtensions);
return 1;
}
@@ -12384,11 +12507,36 @@ static Uint8 VULKAN_INTERNAL_CreateLogicalDevice(
deviceCreateInfo.pEnabledFeatures = &features->desiredVulkan10DeviceFeatures;
}
vulkanResult = renderer->vkCreateDevice(
renderer->physicalDevice,
&deviceCreateInfo,
NULL,
&renderer->logicalDevice);
#ifdef HAVE_GPU_OPENXR
if (renderer->xrInstance) {
XrResult xrResult;
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR;
if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanDeviceKHR");
SDL_stack_free((void *)deviceExtensions);
return 0;
}
XrVulkanDeviceCreateInfoKHR xrDeviceCreateInfo = {XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR};
xrDeviceCreateInfo.vulkanCreateInfo = &deviceCreateInfo;
xrDeviceCreateInfo.systemId = renderer->xrSystemId;
xrDeviceCreateInfo.vulkanPhysicalDevice = renderer->physicalDevice;
xrDeviceCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
SDL_assert(xrDeviceCreateInfo.pfnGetInstanceProcAddr);
if ((xrResult = xrCreateVulkanDeviceKHR(renderer->xrInstance, &xrDeviceCreateInfo, &renderer->logicalDevice, &vulkanResult)) != XR_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR Vulkan logical device, result %d, %d", xrResult, vulkanResult);
SDL_stack_free((void *)deviceExtensions);
return 0;
}
} else
#endif // HAVE_GPU_OPENXR
{
vulkanResult = renderer->vkCreateDevice(
renderer->physicalDevice,
&deviceCreateInfo,
NULL,
&renderer->logicalDevice);
}
SDL_stack_free((void *)deviceExtensions);
CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0);
@@ -12487,6 +12635,67 @@ static bool VULKAN_INTERNAL_PrepareVulkan(
return true;
}
#ifdef HAVE_GPU_OPENXR
static bool VULKAN_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension)
{
XrResult result;
Uint32 extension_count;
Uint32 i;
result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL);
if (result != XR_SUCCESS)
return false;
XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties));
for (i = 0; i < extension_count; i++)
extension_properties[i] = (XrExtensionProperties){XR_TYPE_EXTENSION_PROPERTIES};
result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties);
if (result != XR_SUCCESS) {
SDL_free(extension_properties);
return false;
}
for (i = 0; i < extension_count; i++) {
XrExtensionProperties extension = extension_properties[i];
// NOTE: as generally recommended, we support KHR_vulkan_enable2 *only*
// see https://fredemmott.com/blog/2024/11/25/best-practices-for-openxr-api-layers.html
if (SDL_strcmp(extension.extensionName, XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME) == 0) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME " extension");
*found_extension = extension;
SDL_free(extension_properties);
return true;
}
}
SDL_free(extension_properties);
return false;
}
static XrResult VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(XrVersion *minimumVulkanApiVersion, XrInstance instance, XrSystemId systemId)
{
XrResult xrResult;
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR;
if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsRequirements2KHR");
return xrResult;
}
XrGraphicsRequirementsVulkanKHR graphicsRequirementsVulkan = {XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR};
if ((xrResult = xrGetVulkanGraphicsRequirements2KHR(instance, systemId, &graphicsRequirementsVulkan)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get vulkan graphics requirements, got OpenXR error %d", xrResult);
return xrResult;
}
*minimumVulkanApiVersion = graphicsRequirementsVulkan.minApiVersionSupported;
return XR_SUCCESS;
}
#endif // HAVE_GPU_OPENXR
static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
{
// Set up dummy VulkanRenderer
@@ -12506,6 +12715,79 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
return false;
}
#ifdef HAVE_GPU_OPENXR
XrResult xrResult;
XrInstancePfns *instancePfns = NULL;
XrInstance xrInstance = XR_NULL_HANDLE;
XrSystemId xrSystemId = XR_NULL_HANDLE;
bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
#ifdef SDL_PLATFORM_ANDROID
/* On Android/Quest, don't test XR in PrepareDriver. The Quest OpenXR runtime
* can't handle having its instance created and destroyed during preparation
* and then recreated during device creation. Just return true for XR mode
* and let CreateDevice do the real work. */
if (xr) {
SDL_Vulkan_UnloadLibrary();
return true;
}
#endif
if (xr) {
if (!SDL_OpenXR_LoadLibrary()) {
SDL_SetError("Failed to load OpenXR loader or a required symbol");
SDL_Vulkan_UnloadLibrary();
return false;
}
XrExtensionProperties gpuExtension;
if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
SDL_SetError("Failed to find a suitable OpenXR GPU extension.");
SDL_Vulkan_UnloadLibrary();
SDL_OpenXR_UnloadLibrary();
return false;
}
const char *extensionName = gpuExtension.extensionName;
if ((xrResult = xrCreateInstance(&(XrInstanceCreateInfo){
.type = XR_TYPE_INSTANCE_CREATE_INFO,
.applicationInfo = {
.apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0),
.applicationName = "SDL",
},
.enabledExtensionCount = 1,
.enabledExtensionNames = &extensionName,
},
&xrInstance)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance");
SDL_Vulkan_UnloadLibrary();
SDL_OpenXR_UnloadLibrary();
return false;
}
instancePfns = SDL_OPENXR_LoadInstanceSymbols(xrInstance);
if (!instancePfns) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load needed OpenXR instance symbols");
SDL_Vulkan_UnloadLibrary();
SDL_OpenXR_UnloadLibrary();
return false;
}
if ((xrResult = instancePfns->xrGetSystem(xrInstance, &(XrSystemGetInfo){
.type = XR_TYPE_SYSTEM_GET_INFO,
.formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY),
},
&xrSystemId)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system");
instancePfns->xrDestroyInstance(xrInstance);
SDL_Vulkan_UnloadLibrary();
SDL_OpenXR_UnloadLibrary();
SDL_free(instancePfns);
return false;
}
}
#endif // HAVE_GPU_OPENXR
renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer));
if (renderer) {
// This needs to be set early for log filtering
@@ -12513,11 +12795,44 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
renderer->preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false);
renderer->minimumVkVersion = VK_API_VERSION_1_0;
#ifdef HAVE_GPU_OPENXR
renderer->xrInstance = xrInstance;
renderer->xrSystemId = xrSystemId;
if (xr) {
XrVersion minimumVkVersionXr;
xrResult = VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVkVersionXr, xrInstance, xrSystemId);
if (xrResult != XR_SUCCESS) {
SDL_SetError("Failed to get the minimum supported Vulkan API version.");
instancePfns->xrDestroyInstance(xrInstance);
SDL_Vulkan_UnloadLibrary();
SDL_OpenXR_UnloadLibrary();
SDL_free(instancePfns);
SDL_free(renderer);
return false;
}
renderer->minimumVkVersion = VK_MAKE_API_VERSION(
0,
XR_VERSION_MAJOR(minimumVkVersionXr),
XR_VERSION_MINOR(minimumVkVersionXr),
XR_VERSION_PATCH(minimumVkVersionXr));
}
#endif // HAVE_GPU_OPENXR
result = VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props);
if (result) {
renderer->vkDestroyInstance(renderer->instance, NULL);
}
#ifdef HAVE_GPU_OPENXR
if (instancePfns) {
instancePfns->xrDestroyInstance(xrInstance);
SDL_free(instancePfns);
SDL_OpenXR_UnloadLibrary();
}
#endif // HAVE_GPU_OPENXR
SDL_free(renderer);
}
SDL_Vulkan_UnloadLibrary();
@@ -12525,6 +12840,278 @@ static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
return result;
}
static XrResult VULKAN_DestroyXRSwapchain(
SDL_GPURenderer *driverData,
XrSwapchain swapchain,
SDL_GPUTexture **swapchainImages)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
VULKAN_Wait(driverData);
Uint32 swapchainCount;
result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL);
if (result != XR_SUCCESS) {
return result;
}
// We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason
for (Uint32 i = 0; i < swapchainCount; i++) {
VulkanTextureContainer *container = (VulkanTextureContainer *)swapchainImages[i];
if (!container->externallyManaged) {
SDL_SetError("Invalid GPU Texture handle.");
return XR_ERROR_HANDLE_INVALID;
}
VULKAN_INTERNAL_DestroyTexture(renderer, container->activeTexture);
// Free the container now that it's unused
SDL_free(container);
}
SDL_free(swapchainImages);
return renderer->xr->xrDestroySwapchain(swapchain);
#else
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
#ifdef HAVE_GPU_OPENXR
static bool VULKAN_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 numFormats, SDL_GPUTextureFormat *sdlFormat, int64_t *vkFormat)
{
for (Uint32 i = 0; i < SDL_arraysize(SDLToVK_TextureFormat_SrgbOnly); i++) {
for (Uint32 j = 0; j < numFormats; j++) {
if (SDLToVK_TextureFormat_SrgbOnly[i].vk == supportedFormats[j]) {
*sdlFormat = SDLToVK_TextureFormat_SrgbOnly[i].sdl;
*vkFormat = SDLToVK_TextureFormat_SrgbOnly[i].vk;
return true;
}
}
}
return false;
}
#endif // HAVE_GPU_OPENXR
static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats(
SDL_GPURenderer *driverData,
XrSession session,
int *num_formats)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
Uint32 i, j, num_supported_formats;
int64_t *supported_formats;
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL);
if (result != XR_SUCCESS) return NULL;
supported_formats = SDL_stack_alloc(int64_t, num_supported_formats);
result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats);
if (result != XR_SUCCESS) {
SDL_stack_free(supported_formats);
return NULL;
}
// FIXME: For now we're just searching for the optimal format, not all supported formats.
// FIXME: Expand this search for all SDL_GPU formats!
SDL_GPUTextureFormat sdlFormat;
int64_t vkFormat = VK_FORMAT_UNDEFINED;
// The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list
if (!VULKAN_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &vkFormat)) {
// Iterate over all formats the runtime supports
for (i = 0; i < num_supported_formats && vkFormat == VK_FORMAT_UNDEFINED; i++) {
// Iterate over all formats we support
for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) {
// Pick the first format the runtime wants that we also support, the runtime should return these in order of preference
if (SDLToVK_TextureFormat[j] == supported_formats[i]) {
vkFormat = supported_formats[i];
sdlFormat = j;
break;
}
}
}
}
SDL_stack_free(supported_formats);
if (vkFormat == VK_FORMAT_UNDEFINED) {
SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL");
return NULL;
}
SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2);
retval[0] = sdlFormat;
retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID;
*num_formats = 1;
return retval;
#else
SDL_SetError("SDL not built with OpenXR support");
return NULL;
#endif
}
static XrResult VULKAN_CreateXRSwapchain(
SDL_GPURenderer *driverData,
XrSession session,
const XrSwapchainCreateInfo *oldCreateInfo,
SDL_GPUTextureFormat format,
XrSwapchain *swapchain,
SDL_GPUTexture ***textures)
{
#ifdef HAVE_GPU_OPENXR
XrResult result;
Uint32 i, j;
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
XrSwapchainCreateInfo createInfo = *oldCreateInfo;
createInfo.format = SDLToVK_TextureFormat[format];
result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain);
if (result != XR_SUCCESS) return result;
Uint32 swapchainImageCount;
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL);
if (result != XR_SUCCESS) return result;
XrSwapchainImageVulkan2KHR *swapchainImages = (XrSwapchainImageVulkan2KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageVulkan2KHR));
for (i = 0; i < swapchainImageCount; i++) swapchainImages[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR;
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages);
if (result != XR_SUCCESS) {
SDL_free(swapchainImages);
return result;
}
VulkanTextureContainer **textureContainers = (VulkanTextureContainer **)SDL_calloc(swapchainImageCount, sizeof(VulkanTextureContainer *));
for (Uint32 idx = 0; idx < swapchainImageCount; idx++) {
VkImage vkImage = swapchainImages[idx].image;
VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture));
texture->swizzle = SwizzleForSDLFormat(format);
texture->depth = 1;
texture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
SDL_SetAtomicInt(&texture->referenceCount, 0);
texture->image = vkImage;
texture->externallyManaged = true;
texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
texture->subresourceCount = createInfo.arraySize * createInfo.mipCount;
texture->subresources = SDL_calloc(
texture->subresourceCount,
sizeof(VulkanTextureSubresource));
for (i = 0; i < createInfo.arraySize; i += 1) {
for (j = 0; j < createInfo.mipCount; j += 1) {
Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex(
j,
i,
createInfo.mipCount);
if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) {
texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc(sizeof(VkImageView));
if (!VULKAN_INTERNAL_CreateRenderTargetView(
renderer,
texture,
i,
j,
SDLToVK_TextureFormat[format],
texture->swizzle,
&texture->subresources[subresourceIndex].renderTargetViews[0])) {
VULKAN_INTERNAL_DestroyTexture(renderer, texture);
SDL_SetError("Failed to create render target view");
return XR_ERROR_RUNTIME_FAILURE;
}
}
texture->subresources[subresourceIndex].parent = texture;
texture->subresources[subresourceIndex].layer = i;
texture->subresources[subresourceIndex].level = j;
}
}
// Transition to the default barrier state
VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer);
VULKAN_INTERNAL_TextureTransitionToDefaultUsage(
renderer,
barrierCommandBuffer,
VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED,
texture);
VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture);
VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer);
textureContainers[idx] = SDL_malloc(sizeof(VulkanTextureContainer));
VulkanTextureContainer *container = textureContainers[idx];
SDL_zero(container->header.info);
container->header.info.width = createInfo.width;
container->header.info.height = createInfo.height;
container->header.info.format = format;
container->header.info.layer_count_or_depth = createInfo.arraySize;
container->header.info.num_levels = createInfo.mipCount;
container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
container->externallyManaged = true;
container->canBeCycled = false;
container->activeTexture = texture;
container->textureCapacity = 1;
container->textureCount = 1;
container->textures = SDL_malloc(
container->textureCapacity * sizeof(VulkanTexture *));
container->textures[0] = container->activeTexture;
container->debugName = NULL;
}
*textures = (SDL_GPUTexture **)textureContainers;
SDL_free(swapchainImages);
return XR_SUCCESS;
#else
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
static XrResult VULKAN_CreateXRSession(
SDL_GPURenderer *driverData,
const XrSessionCreateInfo *createinfo,
XrSession *session)
{
#ifdef HAVE_GPU_OPENXR
VulkanRenderer *renderer = (VulkanRenderer *)driverData;
// Copy out the existing next ptr so that we can append it to the end of the chain we create
const void *XR_MAY_ALIAS currentNextPtr = createinfo->next;
// KHR_vulkan_enable and KHR_vulkan_enable2 share this structure, so we don't need to change any logic here to handle both
XrGraphicsBindingVulkanKHR graphicsBinding = {XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR};
graphicsBinding.instance = renderer->instance;
graphicsBinding.physicalDevice = renderer->physicalDevice;
graphicsBinding.device = renderer->logicalDevice;
graphicsBinding.queueFamilyIndex = renderer->queueFamilyIndex;
graphicsBinding.queueIndex = 0; // we only ever have one queue, so hardcode queue index 0
graphicsBinding.next = currentNextPtr;
XrSessionCreateInfo sessionCreateInfo = *createinfo;
sessionCreateInfo.systemId = renderer->xrSystemId;
sessionCreateInfo.next = &graphicsBinding;
return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session);
#else
SDL_SetError("SDL not built with OpenXR support");
return XR_ERROR_FUNCTION_UNSUPPORTED;
#endif
}
static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
{
VulkanRenderer *renderer;
@@ -12552,9 +13139,83 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S
renderer->debugMode = debugMode;
renderer->preferLowPower = preferLowPower;
renderer->allowedFramesInFlight = 2;
renderer->minimumVkVersion = VK_API_VERSION_1_0;
#ifdef HAVE_GPU_OPENXR
bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false);
XrInstance *xrInstance = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL);
XrSystemId *xrSystemId = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL);
if (xr) {
XrExtensionProperties gpuExtension;
if (!xrInstance) {
SDL_SetError("You must specify an out pointer for the OpenXR instance");
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
if (!xrSystemId) {
SDL_SetError("You must specify an out pointer for the OpenXR system ID");
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
if (!SDL_OpenXR_LoadLibrary()) {
SDL_assert(!"This should have failed in PrepareDevice first!");
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR vulkan extension");
SDL_OpenXR_UnloadLibrary();
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR");
SDL_OpenXR_UnloadLibrary();
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
renderer->xrInstance = *xrInstance;
renderer->xrSystemId = *xrSystemId;
XrVersion minimumVulkanApiVersion;
if (VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVulkanApiVersion, *xrInstance, *xrSystemId) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR graphics requirements");
renderer->xr->xrDestroyInstance(*xrInstance);
SDL_OpenXR_UnloadLibrary();
SDL_free(renderer->xr);
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;
}
renderer->minimumVkVersion = VK_MAKE_VERSION(
XR_VERSION_MAJOR(minimumVulkanApiVersion),
XR_VERSION_MINOR(minimumVulkanApiVersion),
XR_VERSION_PATCH(minimumVulkanApiVersion));
}
#endif // HAVE_GPU_OPENXR
if (!VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props)) {
SET_STRING_ERROR("Failed to initialize Vulkan!");
#ifdef HAVE_GPU_OPENXR
if (xr) {
renderer->xr->xrDestroyInstance(*xrInstance);
SDL_OpenXR_UnloadLibrary();
SDL_free(renderer->xr);
}
#endif // HAVE_GPU_OPENXR
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
return NULL;

199
src/gpu/xr/SDL_gpu_openxr.c Normal file
View File

@@ -0,0 +1,199 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef HAVE_GPU_OPENXR
#include "SDL_gpu_openxr.h"
#ifdef SDL_PLATFORM_ANDROID
#include "../../core/android/SDL_android.h"
#endif
#define VALIDATION_LAYER_API_NAME "XR_APILAYER_LUNARG_core_validation"
/* On Android, the OpenXR loader is initialized by SDL_OpenXR_LoadLibrary() in SDL_openxrdyn.c
* which must be called before this. That function handles the complex initialization using
* direct SDL_LoadFunction calls to avoid issues with xrGetInstanceProcAddr from runtime
* negotiation not supporting pre-instance calls. This stub is kept for API compatibility. */
#ifdef SDL_PLATFORM_ANDROID
static bool SDL_OPENXR_INTERNAL_InitializeAndroidLoader(void)
{
/* The loader should already be initialized by SDL_OpenXR_LoadLibrary().
* We just verify that xrGetInstanceProcAddr is available. */
if (xrGetInstanceProcAddr == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetInstanceProcAddr is NULL - SDL_OpenXR_LoadLibrary was not called first");
return false;
}
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Android OpenXR loader verified (was initialized by SDL_OpenXR_LoadLibrary)");
return true;
}
#endif /* SDL_PLATFORM_ANDROID */
bool SDL_OPENXR_INTERNAL_ValidationLayerAvailable()
{
#ifdef SDL_PLATFORM_ANDROID
/* On Android/Quest, the xrGetInstanceProcAddr obtained through runtime negotiation
* crashes when used for pre-instance global functions. Skip validation layer check. */
return false;
#endif
Uint32 apiLayerCount;
if (XR_FAILED(xrEnumerateApiLayerProperties(0, &apiLayerCount, NULL))) {
return false;
}
if (apiLayerCount <= 0) {
return false;
}
XrApiLayerProperties *apiLayerProperties = SDL_stack_alloc(XrApiLayerProperties, apiLayerCount);
if (XR_FAILED(xrEnumerateApiLayerProperties(apiLayerCount, &apiLayerCount, apiLayerProperties))) {
SDL_stack_free(apiLayerProperties);
return false;
}
bool found = false;
for (Uint32 i = 0; i < apiLayerCount; i++) {
XrApiLayerProperties apiLayer = apiLayerProperties[i];
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "api layer available: %s", apiLayer.layerName);
if (SDL_strcmp(apiLayer.layerName, VALIDATION_LAYER_API_NAME) == 0) {
found = true;
break;
}
}
SDL_stack_free(apiLayerProperties);
return found;
}
XrResult SDL_OPENXR_INTERNAL_GPUInitOpenXR(
bool debugMode,
XrExtensionProperties gpuExtension,
SDL_PropertiesID props,
XrInstance *instance,
XrSystemId *systemId,
XrInstancePfns **xr)
{
XrResult xrResult;
#ifdef SDL_PLATFORM_ANDROID
// Android requires loader initialization before any other XR calls
if (!SDL_OPENXR_INTERNAL_InitializeAndroidLoader()) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to initialize Android OpenXR loader");
return XR_ERROR_INITIALIZATION_FAILED;
}
#endif
bool validationLayersAvailable = SDL_OPENXR_INTERNAL_ValidationLayerAvailable();
Uint32 userApiLayerCount = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_COUNT_NUMBER, 0);
const char *const *userApiLayerNames = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_LAYER_NAMES_POINTER, NULL);
Uint32 userExtensionCount = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_COUNT_NUMBER, 0);
const char *const *userExtensionNames = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_EXTENSION_NAMES_POINTER, NULL);
// allocate enough space for the validation layer + the user's api layers
const char **apiLayerNames = SDL_stack_alloc(const char *, userApiLayerCount + 1);
SDL_memcpy(apiLayerNames, userApiLayerNames, sizeof(const char *) * (userApiLayerCount));
apiLayerNames[userApiLayerCount] = VALIDATION_LAYER_API_NAME;
// On Android, we need an extra extension for android_create_instance
#ifdef SDL_PLATFORM_ANDROID
const Uint32 platformExtensionCount = 2; // GPU extension + Android create instance
#else
const Uint32 platformExtensionCount = 1; // GPU extension only
#endif
const char **extensionNames = SDL_stack_alloc(const char *, userExtensionCount + platformExtensionCount);
SDL_memcpy(extensionNames, userExtensionNames, sizeof(const char *) * (userExtensionCount));
extensionNames[userExtensionCount] = gpuExtension.extensionName;
#ifdef SDL_PLATFORM_ANDROID
extensionNames[userExtensionCount + 1] = XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME;
#endif
XrInstanceCreateInfo xrInstanceCreateInfo = { XR_TYPE_INSTANCE_CREATE_INFO };
xrInstanceCreateInfo.applicationInfo.apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0);
xrInstanceCreateInfo.enabledApiLayerCount = userApiLayerCount + ((debugMode && validationLayersAvailable) ? 1 : 0); // in debug mode, we enable the validation layer
xrInstanceCreateInfo.enabledApiLayerNames = apiLayerNames;
xrInstanceCreateInfo.enabledExtensionCount = userExtensionCount + platformExtensionCount;
xrInstanceCreateInfo.enabledExtensionNames = extensionNames;
#ifdef SDL_PLATFORM_ANDROID
// Get JNI environment and JavaVM for Android instance creation
JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv();
JavaVM *vm = NULL;
if (env) {
(*env)->GetJavaVM(env, &vm);
}
void *activity = SDL_GetAndroidActivity();
XrInstanceCreateInfoAndroidKHR instanceCreateInfoAndroid = { XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR };
instanceCreateInfoAndroid.applicationVM = vm;
instanceCreateInfoAndroid.applicationActivity = activity;
xrInstanceCreateInfo.next = &instanceCreateInfoAndroid;
#endif
const char *applicationName = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_NAME_STRING, "SDL Application");
Uint32 applicationVersion = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_APPLICATION_VERSION_NUMBER, 0);
SDL_strlcpy(xrInstanceCreateInfo.applicationInfo.applicationName, applicationName, XR_MAX_APPLICATION_NAME_SIZE);
xrInstanceCreateInfo.applicationInfo.applicationVersion = applicationVersion;
const char *engineName = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_NAME_STRING, "SDLGPU");
uint32_t engineVersion = (uint32_t)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENGINE_VERSION_NUMBER, SDL_VERSION);
SDL_strlcpy(xrInstanceCreateInfo.applicationInfo.engineName, engineName, XR_MAX_APPLICATION_NAME_SIZE);
xrInstanceCreateInfo.applicationInfo.engineVersion = engineVersion;
if ((xrResult = xrCreateInstance(&xrInstanceCreateInfo, instance)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance");
SDL_stack_free(apiLayerNames);
SDL_stack_free(extensionNames);
return false;
}
SDL_stack_free(apiLayerNames);
SDL_stack_free(extensionNames);
*xr = SDL_OPENXR_LoadInstanceSymbols(*instance);
if (!*xr) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load required OpenXR instance symbols");
/* NOTE: we can't actually destroy the created OpenXR instance here,
as we only get that function pointer by loading the instance symbols...
let's just hope that doesn't happen. */
return false;
}
XrSystemGetInfo systemGetInfo = { XR_TYPE_SYSTEM_GET_INFO };
systemGetInfo.formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY);
if ((xrResult = (*xr)->xrGetSystem(*instance, &systemGetInfo, systemId)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system");
(*xr)->xrDestroyInstance(*instance);
SDL_free(*xr);
return false;
}
return true;
}
#endif /* HAVE_GPU_OPENXR */

View File

@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_openxrdyn.h"
XrResult SDL_OPENXR_INTERNAL_GPUInitOpenXR(
bool debugMode,
XrExtensionProperties gpuExtension,
SDL_PropertiesID props,
XrInstance *instance,
XrSystemId *systemId,
XrInstancePfns **xr);

View File

@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* This internal header provides access to the vendored OpenXR headers
* without requiring include path modifications in project files.
* Similar to SDL_vulkan_internal.h for Vulkan headers.
*/
#ifndef SDL_openxr_internal_h_
#define SDL_openxr_internal_h_
#include "SDL_internal.h"
/* Define platform-specific OpenXR macros BEFORE including openxr headers */
#ifdef SDL_PLATFORM_ANDROID
#include <jni.h>
#define XR_USE_PLATFORM_ANDROID
#endif
/* Include the vendored OpenXR headers using relative path */
#include "../../video/khronos/openxr/openxr.h"
#include "../../video/khronos/openxr/openxr_platform.h"
/* Compatibility: XR_API_VERSION_1_0 was added in OpenXR 1.1.x */
#ifndef XR_API_VERSION_1_0
#define XR_API_VERSION_1_0 XR_MAKE_VERSION(1, 0, XR_VERSION_PATCH(XR_CURRENT_API_VERSION))
#endif
#define SDL_OPENXR_CHECK_VERSION(x, y, z) \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) > x || \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) == x && XR_VERSION_MINOR(XR_CURRENT_API_VERSION) > y) || \
(XR_VERSION_MAJOR(XR_CURRENT_API_VERSION) == x && XR_VERSION_MINOR(XR_CURRENT_API_VERSION) == y && XR_VERSION_PATCH(XR_CURRENT_API_VERSION) >= z))
#endif /* SDL_openxr_internal_h_ */

414
src/gpu/xr/SDL_openxrdyn.c Normal file
View File

@@ -0,0 +1,414 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_openxrdyn.h"
#ifdef HAVE_GPU_OPENXR
#include <SDL3/SDL_dlopennote.h>
#if defined(SDL_PLATFORM_APPLE)
static const char *openxr_library_names[] = { "libopenxr_loader.dylib", NULL };
#elif defined(SDL_PLATFORM_WINDOWS)
static const char *openxr_library_names[] = { "openxr_loader.dll", NULL };
#elif defined(SDL_PLATFORM_ANDROID)
/* On Android, use the Khronos OpenXR loader (libopenxr_loader.so) which properly
* exports xrGetInstanceProcAddr. This is bundled via the Gradle dependency:
* implementation 'org.khronos.openxr:openxr_loader_for_android:X.Y.Z'
*
* The Khronos loader handles runtime discovery internally via the Android broker
* pattern and properly supports all pre-instance global functions.
*
* Note: Do NOT use Meta's forwardloader (libopenxr_forwardloader.so) - it doesn't
* export xrGetInstanceProcAddr directly and the function obtained via runtime
* negotiation crashes on pre-instance calls (e.g., xrEnumerateApiLayerProperties). */
static const char *openxr_library_names[] = { "libopenxr_loader.so", NULL };
#else
static const char *openxr_library_names[] = { "libopenxr_loader.so.1", "libopenxr_loader.so", NULL };
SDL_ELF_NOTE_DLOPEN(
"gpu-openxr",
"Support for OpenXR with SDL_GPU rendering",
SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
"libopenxr_loader.so.1", "libopenxr_loader.so"
)
#endif
#define DEBUG_DYNAMIC_OPENXR 0
typedef struct
{
SDL_SharedObject *lib;
} openxrdynlib;
static openxrdynlib openxr_loader = { NULL };
#ifndef SDL_PLATFORM_ANDROID
static void *OPENXR_GetSym(const char *fnname, bool *failed)
{
void *fn = SDL_LoadFunction(openxr_loader.lib, fnname);
#if DEBUG_DYNAMIC_OPENXR
if (fn) {
SDL_Log("OPENXR: Found '%s' in %s (%p)\n", fnname, dynlib->libname, fn);
} else {
SDL_Log("OPENXR: Symbol '%s' NOT FOUND!\n", fnname);
}
#endif
return fn;
}
#endif
// Define all the function pointers and wrappers...
#define SDL_OPENXR_SYM(name) PFN_##name OPENXR_##name = NULL;
#include "SDL_openxrsym.h"
static int openxr_load_refcount = 0;
#ifdef SDL_PLATFORM_ANDROID
#include <jni.h>
#include "../../video/khronos/openxr/openxr_platform.h"
/* On Android, we need to initialize the loader with JNI context before use */
static bool openxr_android_loader_initialized = false;
static bool OPENXR_InitializeAndroidLoader(void)
{
XrResult result;
PFN_xrInitializeLoaderKHR initializeLoader = NULL;
PFN_xrGetInstanceProcAddr loaderGetProcAddr = NULL;
JNIEnv *env = NULL;
JavaVM *vm = NULL;
jobject activity = NULL;
if (openxr_android_loader_initialized) {
return true;
}
/* The Khronos OpenXR loader (libopenxr_loader.so) properly exports xrGetInstanceProcAddr.
* Get it directly from the library - this is the standard approach. */
loaderGetProcAddr = (PFN_xrGetInstanceProcAddr)SDL_LoadFunction(openxr_loader.lib, "xrGetInstanceProcAddr");
if (loaderGetProcAddr == NULL) {
SDL_SetError("Failed to get xrGetInstanceProcAddr from OpenXR loader. "
"Make sure you're using the Khronos loader (libopenxr_loader.so), "
"not Meta's forwardloader.");
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Got xrGetInstanceProcAddr from loader: %p", (void*)loaderGetProcAddr);
#endif
/* Get xrInitializeLoaderKHR via xrGetInstanceProcAddr */
result = loaderGetProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&initializeLoader);
if (XR_FAILED(result) || initializeLoader == NULL) {
SDL_SetError("Failed to get xrInitializeLoaderKHR (result: %d)", (int)result);
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Got xrInitializeLoaderKHR: %p", (void*)initializeLoader);
#endif
/* Get Android environment info from SDL */
env = (JNIEnv *)SDL_GetAndroidJNIEnv();
if (!env) {
SDL_SetError("Failed to get Android JNI environment");
return false;
}
if ((*env)->GetJavaVM(env, &vm) != 0) {
SDL_SetError("Failed to get JavaVM from JNIEnv");
return false;
}
activity = (jobject)SDL_GetAndroidActivity();
if (!activity) {
SDL_SetError("Failed to get Android activity");
return false;
}
XrLoaderInitInfoAndroidKHR loaderInitInfo = {
.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR,
.next = NULL,
.applicationVM = vm,
.applicationContext = activity
};
result = initializeLoader((XrLoaderInitInfoBaseHeaderKHR *)&loaderInitInfo);
if (XR_FAILED(result)) {
SDL_SetError("xrInitializeLoaderKHR failed with result %d", (int)result);
return false;
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: xrInitializeLoaderKHR succeeded");
#endif
/* Store the xrGetInstanceProcAddr function - this one properly handles
* all pre-instance calls (unlike Meta's forwardloader runtime negotiation) */
OPENXR_xrGetInstanceProcAddr = loaderGetProcAddr;
xrGetInstanceProcAddr = loaderGetProcAddr;
openxr_android_loader_initialized = true;
return true;
}
#endif /* SDL_PLATFORM_ANDROID */
SDL_DECLSPEC void SDLCALL SDL_OpenXR_UnloadLibrary(void)
{
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: UnloadLibrary called, current refcount=%d", openxr_load_refcount);
#endif
// Don't actually unload if more than one module is using the libs...
if (openxr_load_refcount > 0) {
if (--openxr_load_refcount == 0) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Refcount reached 0, unloading library");
#endif
#ifdef SDL_PLATFORM_ANDROID
/* On Android/Quest, don't actually unload the library or reset the loader state.
* The Quest OpenXR runtime doesn't support being re-initialized after teardown.
* xrInitializeLoaderKHR and xrNegotiateLoaderRuntimeInterface must only be called once.
* We keep the library loaded and the loader initialized.
*
* IMPORTANT: We also keep xrGetInstanceProcAddr intact so we can reload other
* function pointers on the next LoadLibrary call. Only NULL out the other symbols. */
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Android - keeping library loaded and loader initialized");
#endif
// Only NULL out non-essential function pointers, keep xrGetInstanceProcAddr
#define SDL_OPENXR_SYM(name) \
if (SDL_strcmp(#name, "xrGetInstanceProcAddr") != 0) { \
OPENXR_##name = NULL; \
}
#include "SDL_openxrsym.h"
#else
// On non-Android, NULL everything and unload
#define SDL_OPENXR_SYM(name) OPENXR_##name = NULL;
#include "SDL_openxrsym.h"
SDL_UnloadObject(openxr_loader.lib);
openxr_loader.lib = NULL;
#endif
}
#if DEBUG_DYNAMIC_OPENXR
else {
SDL_Log("SDL/OpenXR: Refcount is now %d, not unloading", openxr_load_refcount);
}
#endif
}
}
// returns non-zero if all needed symbols were loaded.
SDL_DECLSPEC bool SDLCALL SDL_OpenXR_LoadLibrary(void)
{
bool result = true;
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: LoadLibrary called, current refcount=%d, lib=%p", openxr_load_refcount, (void*)openxr_loader.lib);
#endif
// deal with multiple modules (gpu, openxr, etc) needing these symbols...
if (openxr_load_refcount++ == 0) {
#ifdef SDL_PLATFORM_ANDROID
/* On Android, the library may already be loaded if this is a reload after
* unload (we don't actually unload on Android to preserve runtime state) */
if (openxr_loader.lib == NULL) {
#endif
const char *path_hint = SDL_GetHint(SDL_HINT_OPENXR_LIBRARY);
// If a hint was specified, try that first
if (path_hint && *path_hint) {
openxr_loader.lib = SDL_LoadObject(path_hint);
}
// If no hint or hint failed, try the default library names
if (!openxr_loader.lib) {
for (int i = 0; openxr_library_names[i] != NULL; i++) {
openxr_loader.lib = SDL_LoadObject(openxr_library_names[i]);
if (openxr_loader.lib) {
break;
}
}
}
if (!openxr_loader.lib) {
SDL_SetError("Failed loading OpenXR library");
openxr_load_refcount--;
return false;
}
#if defined(SDL_PLATFORM_ANDROID)
} else {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Library already loaded (Android reload), skipping SDL_LoadObject");
#endif
}
#endif
#ifdef SDL_PLATFORM_ANDROID
/* On Android, we need to initialize the loader before other functions work.
* OPENXR_InitializeAndroidLoader() will return early if already initialized. */
if (!OPENXR_InitializeAndroidLoader()) {
SDL_UnloadObject(openxr_loader.lib);
openxr_loader.lib = NULL;
openxr_load_refcount--;
return false;
}
#endif
bool failed = false;
#ifdef SDL_PLATFORM_ANDROID
/* On Android with Meta's forwardloader, we need special handling.
* After calling xrInitializeLoaderKHR, the global functions should be available
* either as direct exports from the forwardloader or via xrGetInstanceProcAddr(NULL, ...).
*
* Try getting functions directly from the forwardloader first since they'll go
* through the proper forwarding path. */
XrResult xrResult;
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Loading global functions...");
#endif
/* First try to get functions directly from the forwardloader library */
OPENXR_xrEnumerateApiLayerProperties = (PFN_xrEnumerateApiLayerProperties)SDL_LoadFunction(openxr_loader.lib, "xrEnumerateApiLayerProperties");
OPENXR_xrCreateInstance = (PFN_xrCreateInstance)SDL_LoadFunction(openxr_loader.lib, "xrCreateInstance");
OPENXR_xrEnumerateInstanceExtensionProperties = (PFN_xrEnumerateInstanceExtensionProperties)SDL_LoadFunction(openxr_loader.lib, "xrEnumerateInstanceExtensionProperties");
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Direct symbols - xrEnumerateApiLayerProperties=%p, xrCreateInstance=%p, xrEnumerateInstanceExtensionProperties=%p",
(void*)OPENXR_xrEnumerateApiLayerProperties,
(void*)OPENXR_xrCreateInstance,
(void*)OPENXR_xrEnumerateInstanceExtensionProperties);
#endif
/* If direct loading failed, fall back to xrGetInstanceProcAddr(NULL, ...) */
if (OPENXR_xrEnumerateApiLayerProperties == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateApiLayerProperties", (PFN_xrVoidFunction*)&OPENXR_xrEnumerateApiLayerProperties);
if (XR_FAILED(xrResult) || OPENXR_xrEnumerateApiLayerProperties == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrEnumerateApiLayerProperties via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
if (OPENXR_xrCreateInstance == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrCreateInstance", (PFN_xrVoidFunction*)&OPENXR_xrCreateInstance);
if (XR_FAILED(xrResult) || OPENXR_xrCreateInstance == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrCreateInstance via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
if (OPENXR_xrEnumerateInstanceExtensionProperties == NULL) {
xrResult = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrEnumerateInstanceExtensionProperties", (PFN_xrVoidFunction*)&OPENXR_xrEnumerateInstanceExtensionProperties);
if (XR_FAILED(xrResult) || OPENXR_xrEnumerateInstanceExtensionProperties == NULL) {
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Failed to get xrEnumerateInstanceExtensionProperties via xrGetInstanceProcAddr");
#endif
failed = true;
}
}
#if DEBUG_DYNAMIC_OPENXR
SDL_Log("SDL/OpenXR: Final symbols - xrEnumerateApiLayerProperties=%p, xrCreateInstance=%p, xrEnumerateInstanceExtensionProperties=%p",
(void*)OPENXR_xrEnumerateApiLayerProperties,
(void*)OPENXR_xrCreateInstance,
(void*)OPENXR_xrEnumerateInstanceExtensionProperties);
SDL_Log("SDL/OpenXR: Global functions loading %s", failed ? "FAILED" : "succeeded");
#endif
#else
#define SDL_OPENXR_SYM(name) OPENXR_##name = (PFN_##name)OPENXR_GetSym(#name, &failed);
#include "SDL_openxrsym.h"
#endif
if (failed) {
// in case something got loaded...
SDL_OpenXR_UnloadLibrary();
result = false;
}
}
#if DEBUG_DYNAMIC_OPENXR
else {
SDL_Log("SDL/OpenXR: Library already loaded (refcount=%d), skipping", openxr_load_refcount);
}
#endif
return result;
}
SDL_DECLSPEC PFN_xrGetInstanceProcAddr SDLCALL SDL_OpenXR_GetXrGetInstanceProcAddr(void)
{
if (xrGetInstanceProcAddr == NULL) {
SDL_SetError("The OpenXR loader has not been loaded");
}
return xrGetInstanceProcAddr;
}
XrInstancePfns *SDL_OPENXR_LoadInstanceSymbols(XrInstance instance)
{
XrResult result;
XrInstancePfns *pfns = SDL_calloc(1, sizeof(XrInstancePfns));
#define SDL_OPENXR_INSTANCE_SYM(name) \
result = xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction *)&pfns->name); \
if (result != XR_SUCCESS) { \
SDL_free(pfns); \
return NULL; \
}
#include "SDL_openxrsym.h"
return pfns;
}
#else
SDL_DECLSPEC bool SDLCALL SDL_OpenXR_LoadLibrary(void)
{
return SDL_SetError("OpenXR is not enabled in this build of SDL");
}
SDL_DECLSPEC void SDLCALL SDL_OpenXR_UnloadLibrary(void)
{
SDL_SetError("OpenXR is not enabled in this build of SDL");
}
SDL_DECLSPEC PFN_xrGetInstanceProcAddr SDLCALL SDL_OpenXR_GetXrGetInstanceProcAddr(void)
{
return (PFN_xrGetInstanceProcAddr)SDL_SetError("OpenXR is not enabled in this build of SDL");
}
#endif // HAVE_GPU_OPENXR

View File

@@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_openxrdyn_h_
#define SDL_openxrdyn_h_
/* Use the internal header for vendored OpenXR includes */
#include "SDL_openxr_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct XrInstancePfns
{
#define SDL_OPENXR_INSTANCE_SYM(name) \
PFN_##name name;
#include "SDL_openxrsym.h"
} XrInstancePfns;
extern XrInstancePfns *SDL_OPENXR_LoadInstanceSymbols(XrInstance instance);
/* Define the function pointers */
#define SDL_OPENXR_SYM(name) \
extern PFN_##name OPENXR_##name;
#include "SDL_openxrsym.h"
#define xrGetInstanceProcAddr OPENXR_xrGetInstanceProcAddr
#define xrEnumerateApiLayerProperties OPENXR_xrEnumerateApiLayerProperties
#define xrEnumerateInstanceExtensionProperties OPENXR_xrEnumerateInstanceExtensionProperties
#define xrCreateInstance OPENXR_xrCreateInstance
#ifdef __cplusplus
}
#endif
#endif // SDL_openxrdyn_h_

View File

@@ -0,0 +1,49 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* *INDENT-OFF* */ // clang-format off
#include "../../video/khronos/openxr/openxr.h"
#ifndef SDL_OPENXR_SYM
#define SDL_OPENXR_SYM(name)
#endif
#ifndef SDL_OPENXR_INSTANCE_SYM
#define SDL_OPENXR_INSTANCE_SYM(name)
#endif
SDL_OPENXR_SYM(xrGetInstanceProcAddr)
SDL_OPENXR_SYM(xrEnumerateApiLayerProperties)
SDL_OPENXR_SYM(xrCreateInstance)
SDL_OPENXR_SYM(xrEnumerateInstanceExtensionProperties)
SDL_OPENXR_INSTANCE_SYM(xrEnumerateSwapchainFormats)
SDL_OPENXR_INSTANCE_SYM(xrCreateSession)
SDL_OPENXR_INSTANCE_SYM(xrGetSystem)
SDL_OPENXR_INSTANCE_SYM(xrCreateSwapchain)
SDL_OPENXR_INSTANCE_SYM(xrEnumerateSwapchainImages)
SDL_OPENXR_INSTANCE_SYM(xrDestroyInstance)
SDL_OPENXR_INSTANCE_SYM(xrDestroySwapchain)
#undef SDL_OPENXR_SYM
#undef SDL_OPENXR_INSTANCE_SYM
/* *INDENT-ON* */ // clang-format on

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,141 @@
#ifndef OPENXR_LOADER_NEGOTIATION_H_
#define OPENXR_LOADER_NEGOTIATION_H_ 1
/*
** Copyright 2017-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
#ifdef __cplusplus
extern "C" {
#endif
// XR_LOADER_VERSION_1_0 is a preprocessor guard. Do not pass it to API calls.
#define XR_LOADER_VERSION_1_0 1
#define XR_CURRENT_LOADER_API_LAYER_VERSION 1
#define XR_CURRENT_LOADER_RUNTIME_VERSION 1
#define XR_LOADER_INFO_STRUCT_VERSION 1
#define XR_API_LAYER_INFO_STRUCT_VERSION 1
#define XR_RUNTIME_INFO_STRUCT_VERSION 1
#define XR_API_LAYER_NEXT_INFO_STRUCT_VERSION 1
#define XR_API_LAYER_CREATE_INFO_STRUCT_VERSION 1
#define XR_API_LAYER_MAX_SETTINGS_PATH_SIZE 512
typedef enum XrLoaderInterfaceStructs {
XR_LOADER_INTERFACE_STRUCT_UNINTIALIZED = 0,
XR_LOADER_INTERFACE_STRUCT_LOADER_INFO = 1,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_REQUEST = 2,
XR_LOADER_INTERFACE_STRUCT_RUNTIME_REQUEST = 3,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_CREATE_INFO = 4,
XR_LOADER_INTERFACE_STRUCT_API_LAYER_NEXT_INFO = 5,
XR_LOADER_INTERFACE_STRUCTS_MAX_ENUM = 0x7FFFFFFF
} XrLoaderInterfaceStructs;
typedef XrResult (XRAPI_PTR *PFN_xrGetInstanceProcAddr)(XrInstance instance, const char* name, PFN_xrVoidFunction* function);
typedef struct XrApiLayerCreateInfo XrApiLayerCreateInfo;
typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)(
const XrInstanceCreateInfo* info,
const XrApiLayerCreateInfo* apiLayerInfo,
XrInstance* instance);
typedef struct XrApiLayerNextInfo {
XrLoaderInterfaceStructs structType;
uint32_t structVersion;
size_t structSize;
char layerName[XR_MAX_API_LAYER_NAME_SIZE];
PFN_xrGetInstanceProcAddr nextGetInstanceProcAddr;
PFN_xrCreateApiLayerInstance nextCreateApiLayerInstance;
struct XrApiLayerNextInfo* next;
} XrApiLayerNextInfo;
typedef struct XrApiLayerCreateInfo {
XrLoaderInterfaceStructs structType;
uint32_t structVersion;
size_t structSize;
void* XR_MAY_ALIAS loaderInstance;
char settings_file_location[XR_API_LAYER_MAX_SETTINGS_PATH_SIZE];
XrApiLayerNextInfo* nextInfo;
} XrApiLayerCreateInfo;
typedef struct XrNegotiateLoaderInfo {
XrLoaderInterfaceStructs structType;
uint32_t structVersion;
size_t structSize;
uint32_t minInterfaceVersion;
uint32_t maxInterfaceVersion;
XrVersion minApiVersion;
XrVersion maxApiVersion;
} XrNegotiateLoaderInfo;
typedef struct XrNegotiateRuntimeRequest {
XrLoaderInterfaceStructs structType;
uint32_t structVersion;
size_t structSize;
uint32_t runtimeInterfaceVersion;
XrVersion runtimeApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
} XrNegotiateRuntimeRequest;
typedef struct XrNegotiateApiLayerRequest {
XrLoaderInterfaceStructs structType;
uint32_t structVersion;
size_t structSize;
uint32_t layerInterfaceVersion;
XrVersion layerApiVersion;
PFN_xrGetInstanceProcAddr getInstanceProcAddr;
PFN_xrCreateApiLayerInstance createApiLayerInstance;
} XrNegotiateApiLayerRequest;
typedef XrResult (XRAPI_PTR *PFN_xrCreateApiLayerInstance)(const XrInstanceCreateInfo* info, const XrApiLayerCreateInfo* layerInfo, XrInstance* instance);
typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderRuntimeInterface)(const XrNegotiateLoaderInfo* loaderInfo, XrNegotiateRuntimeRequest* runtimeRequest);
typedef XrResult (XRAPI_PTR *PFN_xrNegotiateLoaderApiLayerInterface)(const XrNegotiateLoaderInfo* loaderInfo, const char* layerName, XrNegotiateApiLayerRequest* apiLayerRequest);
#ifndef XR_NO_PROTOTYPES
#ifdef XR_EXTENSION_PROTOTYPES
XRAPI_ATTR XrResult XRAPI_CALL xrCreateApiLayerInstance(
const XrInstanceCreateInfo* info,
const XrApiLayerCreateInfo* layerInfo,
XrInstance* instance);
XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderRuntimeInterface(
const XrNegotiateLoaderInfo* loaderInfo,
XrNegotiateRuntimeRequest* runtimeRequest);
XRAPI_ATTR XrResult XRAPI_CALL xrNegotiateLoaderApiLayerInterface(
const XrNegotiateLoaderInfo* loaderInfo,
const char* layerName,
XrNegotiateApiLayerRequest* apiLayerRequest);
#endif /* XR_EXTENSION_PROTOTYPES */
#endif /* !XR_NO_PROTOTYPES */
#ifdef __cplusplus
}
#endif
#endif

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,330 @@
#ifndef OPENXR_REFLECTION_PARENT_STRUCTS_H_
#define OPENXR_REFLECTION_PARENT_STRUCTS_H_ 1
/*
** Copyright (c) 2017-2025 The Khronos Group Inc.
**
** SPDX-License-Identifier: Apache-2.0 OR MIT
*/
/*
** This header is generated from the Khronos OpenXR XML API Registry.
**
*/
#include "openxr.h"
/*
This file contains expansion macros (X Macros) for OpenXR structures that have a parent type.
*/
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrCompositionLayerBaseHeader
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrCompositionLayerBaseHeader_CORE(_avail, _unavail) \
_avail(XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION) \
_avail(XrCompositionLayerQuad, XR_TYPE_COMPOSITION_LAYER_QUAD) \
_avail(XrCompositionLayerCubeKHR, XR_TYPE_COMPOSITION_LAYER_CUBE_KHR) \
_avail(XrCompositionLayerCylinderKHR, XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR) \
_avail(XrCompositionLayerEquirectKHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR) \
_avail(XrCompositionLayerEquirect2KHR, XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR) \
_avail(XrCompositionLayerPassthroughFB, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB) \
_avail(XrCompositionLayerPassthroughHTC, XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_HTC) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrEventDataBaseHeader
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrEventDataBaseHeader_CORE(_avail, _unavail) \
_avail(XrEventDataEventsLost, XR_TYPE_EVENT_DATA_EVENTS_LOST) \
_avail(XrEventDataInstanceLossPending, XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING) \
_avail(XrEventDataSessionStateChanged, XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED) \
_avail(XrEventDataReferenceSpaceChangePending, XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING) \
_avail(XrEventDataInteractionProfileChanged, XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED) \
_avail(XrEventDataVisibilityMaskChangedKHR, XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR) \
_avail(XrEventDataPerfSettingsEXT, XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT) \
_avail(XrEventDataMainSessionVisibilityChangedEXTX, XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX) \
_avail(XrEventDataDisplayRefreshRateChangedFB, XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB) \
_avail(XrEventDataViveTrackerConnectedHTCX, XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX) \
_avail(XrEventDataSpatialAnchorCreateCompleteFB, XR_TYPE_EVENT_DATA_SPATIAL_ANCHOR_CREATE_COMPLETE_FB) \
_avail(XrEventDataSpaceSetStatusCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB) \
_avail(XrEventDataMarkerTrackingUpdateVARJO, XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO) \
_avail(XrEventDataLocalizationChangedML, XR_TYPE_EVENT_DATA_LOCALIZATION_CHANGED_ML) \
_avail(XrEventDataSpaceQueryResultsAvailableFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB) \
_avail(XrEventDataSpaceQueryCompleteFB, XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB) \
_avail(XrEventDataSpaceSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SAVE_COMPLETE_FB) \
_avail(XrEventDataSpaceEraseCompleteFB, XR_TYPE_EVENT_DATA_SPACE_ERASE_COMPLETE_FB) \
_avail(XrEventDataSpaceShareCompleteFB, XR_TYPE_EVENT_DATA_SPACE_SHARE_COMPLETE_FB) \
_avail(XrEventDataSpaceListSaveCompleteFB, XR_TYPE_EVENT_DATA_SPACE_LIST_SAVE_COMPLETE_FB) \
_avail(XrEventDataPassthroughLayerResumedMETA, XR_TYPE_EVENT_DATA_PASSTHROUGH_LAYER_RESUMED_META) \
_avail(XrEventDataHeadsetFitChangedML, XR_TYPE_EVENT_DATA_HEADSET_FIT_CHANGED_ML) \
_avail(XrEventDataEyeCalibrationChangedML, XR_TYPE_EVENT_DATA_EYE_CALIBRATION_CHANGED_ML) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrHapticBaseHeader
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrHapticBaseHeader_CORE(_avail, _unavail) \
_avail(XrHapticVibration, XR_TYPE_HAPTIC_VIBRATION) \
_avail(XrHapticAmplitudeEnvelopeVibrationFB, XR_TYPE_HAPTIC_AMPLITUDE_ENVELOPE_VIBRATION_FB) \
_avail(XrHapticPcmVibrationFB, XR_TYPE_HAPTIC_PCM_VIBRATION_FB) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSwapchainImageBaseHeader
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_CORE(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_CORE(_avail, _unavail) \
#if defined(XR_USE_GRAPHICS_API_D3D11)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \
_avail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D11(_avail, _unavail) \
_unavail(XrSwapchainImageD3D11KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR) \
#endif
#if defined(XR_USE_GRAPHICS_API_D3D12)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \
_avail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_D3D12(_avail, _unavail) \
_unavail(XrSwapchainImageD3D12KHR, XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR) \
#endif
#if defined(XR_USE_GRAPHICS_API_OPENGL)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \
_avail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL(_avail, _unavail) \
_unavail(XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR) \
#endif
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_avail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_unavail(XrSwapchainImageOpenGLESKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR) \
#endif
#if defined(XR_USE_GRAPHICS_API_VULKAN)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_avail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainImageBaseHeader_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_unavail(XrSwapchainImageVulkanKHR, XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR) \
#endif
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrLoaderInitInfoBaseHeaderKHR
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_CORE(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_CORE(_avail, _unavail) \
#if defined(XR_USE_PLATFORM_ANDROID)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
_avail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrLoaderInitInfoBaseHeaderKHR_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
_unavail(XrLoaderInitInfoAndroidKHR, XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR) \
#endif
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrBindingModificationBaseHeaderKHR
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrBindingModificationBaseHeaderKHR_CORE(_avail, _unavail) \
_avail(XrInteractionProfileDpadBindingEXT, XR_TYPE_INTERACTION_PROFILE_DPAD_BINDING_EXT) \
_avail(XrInteractionProfileAnalogThresholdVALVE, XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSwapchainStateBaseHeaderFB
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_CORE(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_CORE(_avail, _unavail) \
_avail(XrSwapchainStateFoveationFB, XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB) \
#if defined(XR_USE_GRAPHICS_API_OPENGL_ES)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_avail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_OPENGL_ES(_avail, _unavail) \
_unavail(XrSwapchainStateSamplerOpenGLESFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB) \
#endif
#if defined(XR_USE_GRAPHICS_API_VULKAN)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_avail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_GRAPHICS_API_VULKAN(_avail, _unavail) \
_unavail(XrSwapchainStateSamplerVulkanFB, XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB) \
#endif
#if defined(XR_USE_PLATFORM_ANDROID)
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
_avail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \
#else
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSwapchainStateBaseHeaderFB_XR_USE_PLATFORM_ANDROID(_avail, _unavail) \
_unavail(XrSwapchainStateAndroidSurfaceDimensionsFB, XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB) \
#endif
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpatialAnchorsCreateInfoBaseHeaderML
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsCreateInfoBaseHeaderML(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsCreateInfoBaseHeaderML_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsCreateInfoBaseHeaderML()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsCreateInfoBaseHeaderML_CORE(_avail, _unavail) \
_avail(XrSpatialAnchorsCreateInfoFromPoseML, XR_TYPE_SPATIAL_ANCHORS_CREATE_INFO_FROM_POSE_ML) \
_avail(XrSpatialAnchorsCreateInfoFromUuidsML, XR_TYPE_SPATIAL_ANCHORS_CREATE_INFO_FROM_UUIDS_ML) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrFutureCompletionBaseHeaderEXT
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrFutureCompletionBaseHeaderEXT(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrFutureCompletionBaseHeaderEXT_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrFutureCompletionBaseHeaderEXT()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrFutureCompletionBaseHeaderEXT_CORE(_avail, _unavail) \
_avail(XrCreateSpatialAnchorsCompletionML, XR_TYPE_CREATE_SPATIAL_ANCHORS_COMPLETION_ML) \
_avail(XrSpatialAnchorsQueryCompletionML, XR_TYPE_SPATIAL_ANCHORS_QUERY_COMPLETION_ML) \
_avail(XrSpatialAnchorsPublishCompletionML, XR_TYPE_SPATIAL_ANCHORS_PUBLISH_COMPLETION_ML) \
_avail(XrSpatialAnchorsDeleteCompletionML, XR_TYPE_SPATIAL_ANCHORS_DELETE_COMPLETION_ML) \
_avail(XrSpatialAnchorsUpdateExpirationCompletionML, XR_TYPE_SPATIAL_ANCHORS_UPDATE_EXPIRATION_COMPLETION_ML) \
_avail(XrFutureCompletionEXT, XR_TYPE_FUTURE_COMPLETION_EXT) \
_avail(XrWorldMeshStateRequestCompletionML, XR_TYPE_WORLD_MESH_STATE_REQUEST_COMPLETION_ML) \
_avail(XrWorldMeshRequestCompletionML, XR_TYPE_WORLD_MESH_REQUEST_COMPLETION_ML) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpatialAnchorsQueryInfoBaseHeaderML
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsQueryInfoBaseHeaderML(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsQueryInfoBaseHeaderML_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsQueryInfoBaseHeaderML()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpatialAnchorsQueryInfoBaseHeaderML_CORE(_avail, _unavail) \
_avail(XrSpatialAnchorsQueryInfoRadiusML, XR_TYPE_SPATIAL_ANCHORS_QUERY_INFO_RADIUS_ML) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpaceQueryInfoBaseHeaderFB
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceQueryInfoBaseHeaderFB_CORE(_avail, _unavail) \
_avail(XrSpaceQueryInfoFB, XR_TYPE_SPACE_QUERY_INFO_FB) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrSpaceFilterInfoBaseHeaderFB
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrSpaceFilterInfoBaseHeaderFB_CORE(_avail, _unavail) \
_avail(XrSpaceUuidFilterInfoFB, XR_TYPE_SPACE_UUID_FILTER_INFO_FB) \
_avail(XrSpaceComponentFilterInfoFB, XR_TYPE_SPACE_COMPONENT_FILTER_INFO_FB) \
/// Like XR_LIST_ALL_STRUCTURE_TYPES, but only includes types whose parent struct type is XrShareSpacesRecipientBaseHeaderMETA
#define XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrShareSpacesRecipientBaseHeaderMETA(_avail, _unavail) \
_impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrShareSpacesRecipientBaseHeaderMETA_CORE(_avail, _unavail) \
// Implementation detail of XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrShareSpacesRecipientBaseHeaderMETA()
#define _impl_XR_LIST_ALL_CHILD_STRUCTURE_TYPES_XrShareSpacesRecipientBaseHeaderMETA_CORE(_avail, _unavail) \
_avail(XrShareSpacesRecipientGroupsMETA, XR_TYPE_SHARE_SPACES_RECIPIENT_GROUPS_META) \
#endif

View File

@@ -66,6 +66,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetWindowsMessageHook(void);
extern SDL_DECLSPEC void SDLCALL JNI_OnLoad(void);
#include <SDL3/SDL_openxr.h>
const static struct {
const char *name;
SDL_FunctionPointer address;