Skip to content

Commit

Permalink
Load OpenXR dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
Beyley committed Dec 7, 2024
1 parent 7fcf996 commit 9a34662
Show file tree
Hide file tree
Showing 5 changed files with 266 additions and 18 deletions.
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ set_option(SDL_ASAN "Use AddressSanitizer to detect memory errors
set_option(SDL_CCACHE "Use Ccache to speed up build" OFF)
set_option(SDL_CLANG_TIDY "Run clang-tidy static analysis" OFF)
set_option(SDL_GPU_DXVK "Build SDL_GPU with DXVK support" OFF)
set_option(SDL_OPENXR "Build SDL_GPU with OpenXR support" ON)
set_option(SDL_GPU_OPENXR "Build SDL_GPU with OpenXR support" ON)

set(SDL_VENDOR_INFO "" CACHE STRING "Vendor name and/or version to add to SDL_REVISION")

Expand Down Expand Up @@ -1733,8 +1733,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
endif()

# if(SDL_GPU AND SDL_GPU_OPENXR)
# TODO: make this not silly
sdl_link_dependency(openxr_loader LIBS openxr_loader)
# TODO: actually do this correctly :)
set(HAVE_OPENXR_H TRUE)
# if(PKG_CONFIG_FOUND)
# # pkg_search_module(OPENXR_LOADER openxr_loader)
Expand Down Expand Up @@ -2989,7 +2988,8 @@ if(SDL_GPU)
set(SDL_VIDEO_RENDER_GPU 1)
set(HAVE_RENDER_GPU TRUE)
endif()
if(HAVE_OPENXR_H)
if(SDL_GPU_OPENXR)
sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/xr/*.c")
set(SDL_GPU_OPENXR 1)
endif()
endif()
Expand Down
50 changes: 36 additions & 14 deletions src/gpu/vulkan/SDL_gpu_vulkan.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
/* Enable the OpenXR vulkan extensions */
#define XR_USE_GRAPHICS_API_VULKAN 1
#include <openxr/openxr_platform.h>
#include "../xr/SDL_openxrdyn.h"

#endif

Expand Down Expand Up @@ -1134,6 +1135,7 @@ struct VulkanRenderer
// openxr
XrInstance xrInstance;
XrSystemId xrSystem;
XrInstancePfns *xr;

bool debugMode;
bool preferLowPower;
Expand Down Expand Up @@ -4836,6 +4838,9 @@ static void VULKAN_DestroyDevice(

VULKAN_Wait(device->driverData);

SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);

for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) {
VULKAN_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window);
}
Expand Down Expand Up @@ -6773,7 +6778,7 @@ static XrResult VULKAN_CreateXRSession(
sessionCreateInfo.systemId = renderer->xrSystem;
sessionCreateInfo.next = &graphicsBinding;

return xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session);
return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session);
}

static XrResult VULKAN_DestroyXRSwapchain(
Expand All @@ -6786,7 +6791,7 @@ static XrResult VULKAN_DestroyXRSwapchain(
VulkanRenderer *renderer = (VulkanRenderer *)driverData;

Uint32 swapchainCount;
result = xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL);
result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL);
if (result != XR_SUCCESS) {
return result;
}
Expand All @@ -6807,7 +6812,7 @@ static XrResult VULKAN_DestroyXRSwapchain(

SDL_free(swapchainImages);

return xrDestroySwapchain(swapchain);
return renderer->xr->xrDestroySwapchain(swapchain);
}

static XrResult VULKAN_CreateXRSwapchain(
Expand All @@ -6825,10 +6830,10 @@ static XrResult VULKAN_CreateXRSwapchain(
int64_t *supported_formats;
VulkanRenderer *renderer = (VulkanRenderer *)driverData;

result = xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL);
result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL);
if(result != XR_SUCCESS) return result;
supported_formats = SDL_stack_alloc(int64_t, num_supported_formats);
result = xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats);
result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats);
if(result != XR_SUCCESS)
{
SDL_stack_free(num_supported_formats);
Expand Down Expand Up @@ -6866,18 +6871,18 @@ static XrResult VULKAN_CreateXRSwapchain(

/* TODO: validate createInfo.usageFlags */

result = xrCreateSwapchain(session, &createInfo, swapchain);
result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain);
if(result != XR_SUCCESS) return result;

Uint32 swapchainImageCount;
result = xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL);
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL);
if(result != XR_SUCCESS) return result;

/* TODO: dont hardcode KHR_vulkan_enable2 */
XrSwapchainImageVulkan2KHR *swapchainImages = (XrSwapchainImageVulkan2KHR*)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageVulkan2KHR));
for(i = 0; i < swapchainImageCount; i++) swapchainImages[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR;

result = xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages);
result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages);
if(result != XR_SUCCESS) {
SDL_free(swapchainImages);
return result;
Expand Down Expand Up @@ -11137,7 +11142,7 @@ static Uint8 VULKAN_INTERNAL_CreateXRInstance(VulkanRenderer *renderer, XrVersio
return 0;
}

appInfo.apiVersion = VK_MAKE_VERSION(XR_VERSION_MAJOR(minimumVersion), XR_VERSION_MINOR(minimumVersion), XR_VERSION_PATCH(minimumVersion));
appInfo.apiVersion = VK_MAKE_VERSION(VK_VERSION_MAJOR(minimumVersion), VK_VERSION_MINOR(minimumVersion), VK_VERSION_PATCH(minimumVersion));

createFlags = 0;

Expand Down Expand Up @@ -12070,25 +12075,30 @@ static bool VULKAN_CreateXRDevice(SDL_GPUDevice **gpu_device, XrInstance *xrInst
return false;
}

renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer));
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
if (!SDL_OPENXR_LoadLoaderSymbols()) {
SDL_SetError("Failed to load OpenXR loader or a required symbol");
return false;
}

renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(VulkanRenderer));
renderer->debugMode = debugMode;
renderer->preferLowPower = preferLowPower;

if(!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension))
{
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR vulkan extension");
SDL_OPENXR_UnloadLoaderSymbols();
return false;
}

static const char *apiLayerNames[] = {"XR_APILAYER_LUNARG_core_validation"};
const char *extensionLayerNames[] = {gpuExtension.extensionName};

XrInstanceCreateInfo xrInstanceCreateInfo = {XR_TYPE_INSTANCE_CREATE_INFO};
xrInstanceCreateInfo.applicationInfo.apiVersion = XR_API_VERSION_1_1;
xrInstanceCreateInfo.applicationInfo.apiVersion = XR_API_VERSION_1_0;
xrInstanceCreateInfo.enabledApiLayerCount = 1;
xrInstanceCreateInfo.enabledApiLayerNames = apiLayerNames;
xrInstanceCreateInfo.enabledExtensionCount = 1;
xrInstanceCreateInfo.enabledExtensionCount = debugMode ? 1 : 0;
xrInstanceCreateInfo.enabledExtensionNames = extensionLayerNames;

SDL_strlcpy(xrInstanceCreateInfo.applicationInfo.applicationName, "SDL Application", XR_MAX_APPLICATION_NAME_SIZE); // TODO: let the user specify this
Expand All @@ -12099,15 +12109,19 @@ static bool VULKAN_CreateXRDevice(SDL_GPUDevice **gpu_device, XrInstance *xrInst

if((xrResult = xrCreateInstance(&xrInstanceCreateInfo, xrInstance)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance");
SDL_OPENXR_UnloadLoaderSymbols();
return false;
}

renderer->xrInstance = *xrInstance;
renderer->xr = SDL_OPENXR_LoadInstanceSymbols(*xrInstance);

XrSystemGetInfo systemGetInfo = {XR_TYPE_SYSTEM_GET_INFO};
systemGetInfo.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; /* TODO: let the caller specify this */
if((xrResult = xrGetSystem(*xrInstance, &systemGetInfo, xrSystem)) != XR_SUCCESS) {
if((xrResult = renderer->xr->xrGetSystem(*xrInstance, &systemGetInfo, xrSystem)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system");
SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);
return false;
}

Expand All @@ -12116,18 +12130,24 @@ static bool VULKAN_CreateXRDevice(SDL_GPUDevice **gpu_device, XrInstance *xrInst
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR;
if((xrResult = xrGetInstanceProcAddr(*xrInstance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction*)&xrGetVulkanGraphicsRequirements2KHR)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsRequirements2KHR");
SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);
return false;
}

XrGraphicsRequirementsVulkanKHR graphicsRequirementsVulkan = {XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR};
if((xrResult = xrGetVulkanGraphicsRequirements2KHR(*xrInstance, *xrSystem, &graphicsRequirementsVulkan)) != XR_SUCCESS) {
SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get vulkan graphics requirements, xr error %d", xrResult);
SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);
return false;
}

if (!VULKAN_INTERNAL_PrepareXRVulkan(renderer, graphicsRequirementsVulkan.minApiVersionSupported)) {
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);
SET_STRING_ERROR_AND_RETURN("Failed to initialize Vulkan!", false)
}

Expand Down Expand Up @@ -12156,6 +12176,8 @@ static bool VULKAN_CreateXRDevice(SDL_GPUDevice **gpu_device, XrInstance *xrInst
renderer)) {
SDL_free(renderer);
SDL_Vulkan_UnloadLibrary();
SDL_OPENXR_UnloadLoaderSymbols();
SDL_free(renderer->xr);
SET_STRING_ERROR_AND_RETURN("Failed to create logical device!", false)
}

Expand Down
116 changes: 116 additions & 0 deletions src/gpu/xr/SDL_openxrdyn.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <[email protected]>
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 SDL_GPU_OPENXR

#define DEBUG_DYNAMIC_OPENXR 0

#include "SDL_openxrdyn.h"

typedef struct
{
SDL_SharedObject *lib;
const char *libname;
} openxrdynlib;

static openxrdynlib openxr_loader = { NULL, "libopenxr_loader.so.1" };

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;
}

// 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;

void SDL_OPENXR_UnloadLoaderSymbols(void)
{
// Don't actually unload if more than one module is using the libs...
if (openxr_load_refcount > 0) {
if (--openxr_load_refcount == 0) {
// set all the function pointers to NULL.
#define SDL_OPENXR_SYM(name) OPENXR_##name = NULL;
#include "SDL_openxrsym.h"

SDL_UnloadObject(openxr_loader.lib);
}
}
}

// returns non-zero if all needed symbols were loaded.
bool SDL_OPENXR_LoadLoaderSymbols(void)
{
bool result = true; // always succeed if not using Dynamic OPENXR stuff.

// deal with multiple modules (dga, openxr, etc) needing these symbols...
if (openxr_load_refcount++ == 0) {
openxr_loader.lib = SDL_LoadObject(openxr_loader.libname);

if(!openxr_loader.lib)
return false;

bool failed = false;

#define SDL_OPENXR_SYM(name) OPENXR_##name = (PFN_##name)OPENXR_GetSym(#name, &failed);
#include "SDL_openxrsym.h"

if (failed) {
// in case something got loaded...
SDL_OPENXR_UnloadLoaderSymbols();
result = false;
}
}

return result;
}

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;
}

#endif // SDL_GPU_OPENXR
62 changes: 62 additions & 0 deletions src/gpu/xr/SDL_openxrdyn.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2024 Sam Lantinga <[email protected]>
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_

#include "SDL_internal.h"

#include "openxr/openxr.h"
#include "openxr/openxr_platform.h"

#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))

#ifdef __cplusplus
extern "C" {
#endif

typedef struct XrInstancePfns {
#define SDL_OPENXR_INSTANCE_SYM(name) \
PFN_##name name;
#include "SDL_openxrsym.h"
} XrInstancePfns;

extern bool SDL_OPENXR_LoadLoaderSymbols(void);
extern void SDL_OPENXR_UnloadLoaderSymbols(void);

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 xrEnumerateInstanceExtensionProperties OPENXR_xrEnumerateInstanceExtensionProperties
#define xrCreateInstance OPENXR_xrCreateInstance

#ifdef __cplusplus
}
#endif

#endif // SDL_openxrdyn_h_
Loading

0 comments on commit 9a34662

Please sign in to comment.