#pragma once #include "../platforms/platform_utils.h" #if defined(SK_XR_OPENXR) #include "openxr.h" #include "../stereokit.h" #include "../libraries/array.h" #if defined(XR_USE_GRAPHICS_API_D3D11) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #define XR_GFX_EXTENSION XR_KHR_D3D11_ENABLE_EXTENSION_NAME #define XrSwapchainImage XrSwapchainImageD3D11KHR #define XR_TYPE_SWAPCHAIN_IMAGE XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR #define XrGraphicsRequirements XrGraphicsRequirementsD3D11KHR #define XR_TYPE_GRAPHICS_REQUIREMENTS XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR #define xrGetGraphicsRequirementsKHR xrGetD3D11GraphicsRequirementsKHR #define PFN_xrGetGraphicsRequirementsKHR PFN_xrGetD3D11GraphicsRequirementsKHR #define NAME_xrGetGraphicsRequirementsKHR "xrGetD3D11GraphicsRequirementsKHR" #define XrGraphicsBinding XrGraphicsBindingD3D11KHR #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_D3D11_KHR #elif defined(XR_USE_PLATFORM_WIN32) && defined(XR_USE_GRAPHICS_API_OPENGL) #include #include #define XR_GFX_EXTENSION XR_KHR_OPENGL_ENABLE_EXTENSION_NAME #define XrSwapchainImage XrSwapchainImageOpenGLKHR #define XR_TYPE_SWAPCHAIN_IMAGE XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR #define XrGraphicsRequirements XrGraphicsRequirementsOpenGLKHR #define XR_TYPE_GRAPHICS_REQUIREMENTS XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR #define xrGetGraphicsRequirementsKHR xrGetOpenGLGraphicsRequirementsKHR #define PFN_xrGetGraphicsRequirementsKHR PFN_xrGetOpenGLGraphicsRequirementsKHR #define NAME_xrGetGraphicsRequirementsKHR "xrGetOpenGLGraphicsRequirementsKHR" #define XrGraphicsBinding XrGraphicsBindingOpenGLWin32KHR #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR #elif defined(XR_USE_PLATFORM_XLIB) && defined(XR_USE_GRAPHICS_API_OPENGL) #include #include #include #define XR_GFX_EXTENSION XR_KHR_OPENGL_ENABLE_EXTENSION_NAME #define XrSwapchainImage XrSwapchainImageOpenGLKHR #define XR_TYPE_SWAPCHAIN_IMAGE XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR #define XrGraphicsRequirements XrGraphicsRequirementsOpenGLKHR #define XR_TYPE_GRAPHICS_REQUIREMENTS XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR #define xrGetGraphicsRequirementsKHR xrGetOpenGLGraphicsRequirementsKHR #define PFN_xrGetGraphicsRequirementsKHR PFN_xrGetOpenGLGraphicsRequirementsKHR #define NAME_xrGetGraphicsRequirementsKHR "xrGetOpenGLGraphicsRequirementsKHR" #define XrGraphicsBinding XrGraphicsBindingOpenGLXlibKHR #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR #elif defined(XR_USE_GRAPHICS_API_VULKAN) #define XR_GFX_EXTENSION XR_KHR_VULKAN_ENABLE_EXTENSION_NAME #define XrSwapchainImage XrSwapchainImageVulkanKHR #define XR_TYPE_SWAPCHAIN_IMAGE XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR #define XrGraphicsRequirements XrGraphicsRequirementsVulkanKHR #define XR_TYPE_GRAPHICS_REQUIREMENTS XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR #define PFN_xrGetGraphicsRequirementsKHR PFN_xrGetVulkanGraphicsRequirementsKHR #define NAME_xrGetGraphicsRequirementsKHR "xrGetVulkanGraphicsRequirementsKHR" #define XrGraphicsBinding XrGraphicsBindingVulkanKHR #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR #elif defined(XR_USE_GRAPHICS_API_OPENGL_ES) #include #define XR_GFX_EXTENSION XR_KHR_OPENGL_ES_ENABLE_EXTENSION_NAME #define XrSwapchainImage XrSwapchainImageOpenGLESKHR #define XR_TYPE_SWAPCHAIN_IMAGE XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR #define XrGraphicsRequirements XrGraphicsRequirementsOpenGLESKHR #define XR_TYPE_GRAPHICS_REQUIREMENTS XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR #define xrGetGraphicsRequirementsKHR xrGetOpenGLESGraphicsRequirementsKHR #define PFN_xrGetGraphicsRequirementsKHR PFN_xrGetOpenGLESGraphicsRequirementsKHR #define NAME_xrGetGraphicsRequirementsKHR "xrGetOpenGLESGraphicsRequirementsKHR" #if defined(SK_OS_ANDROID) #include #define XrGraphicsBinding XrGraphicsBindingOpenGLESAndroidKHR #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR #elif defined(SK_OS_LINUX) #define XrGraphicsBinding XrGraphicsBindingEGLMNDX #define XR_TYPE_GRAPHICS_BINDING XR_TYPE_GRAPHICS_BINDING_EGL_MNDX #endif #endif #include namespace sk { #pragma warning( push ) #pragma warning( disable: 4127 ) // conditional expression is constant /////////////////////////////////////////// #if defined(SK_OS_WINDOWS_UWP) #define EXT_AVAILABLE_UWP true #else #define EXT_AVAILABLE_UWP false #endif #if defined(SK__DEBUG) #define EXT_AVAILABLE_DEBUG true #else #define EXT_AVAILABLE_DEBUG false #endif #if defined(SK_OS_ANDROID) #define EXT_AVAILABLE_ANDROID true #else #define EXT_AVAILABLE_ANDROID false #endif #if defined(SK_OS_LINUX) #define EXT_AVAILABLE_LINUX true #else #define EXT_AVAILABLE_LINUX false #endif /////////////////////////////////////////// // Extension availability /////////////////////////////////////////// // Extensions that are available for all supported platforms #define FOR_EACH_EXT_ALL(_) \ _(KHR_composition_layer_depth, true) \ _(EXT_hand_tracking, true) \ _(EXT_hand_tracking_data_source, true) \ _(EXT_hand_interaction, true) \ _(EXT_palm_pose, true) \ _(EXT_eye_gaze_interaction, true) \ _(EXT_local_floor, true) \ _(FB_color_space, true) \ _(OCULUS_audio_device_guid, true) \ _(MSFT_unbounded_reference_space, true) \ _(MSFT_hand_tracking_mesh, true) \ _(MSFT_spatial_anchor, true) \ _(MSFT_spatial_graph_bridge, true) \ _(MSFT_secondary_view_configuration, true) \ _(MSFT_first_person_observer, true) \ _(MSFT_scene_understanding, true) \ _(BD_controller_interaction, true) \ _(EXT_hp_mixed_reality_controller, true) \ _(EXTX_overlay, true) // UWP platform only #define FOR_EACH_EXT_UWP(_) \ _(MSFT_perception_anchor_interop, EXT_AVAILABLE_UWP) // Android platform only #define FOR_EACH_EXT_ANDROID(_) \ _(KHR_android_create_instance, EXT_AVAILABLE_ANDROID) #if defined(SKG_LINUX_EGL) // Linux platform only #define FOR_EACH_EXT_LINUX(_) \ _(MNDX_egl_enable, EXT_AVAILABLE_LINUX) #else #define FOR_EACH_EXT_LINUX(_) #endif // Debug builds only #define FOR_EACH_EXT_DEBUG(_) \ _(EXT_debug_utils, EXT_AVAILABLE_DEBUG) /////////////////////////////////////////// // Extension functions /////////////////////////////////////////// #define FOR_EACH_EXTENSION_FUNCTION(_) \ _(xrCreateSpatialAnchorMSFT) \ _(xrCreateSpatialAnchorSpaceMSFT) \ _(xrDestroySpatialAnchorMSFT) \ _(xrCreateSceneObserverMSFT) \ _(xrDestroySceneObserverMSFT) \ _(xrCreateSceneMSFT) \ _(xrDestroySceneMSFT) \ _(xrComputeNewSceneMSFT) \ _(xrGetSceneComputeStateMSFT) \ _(xrGetSceneComponentsMSFT) \ _(xrLocateSceneComponentsMSFT) \ _(xrEnumerateSceneComputeFeaturesMSFT) \ _(xrGetSceneMeshBuffersMSFT) \ _(xrGetVisibilityMaskKHR) \ _(xrCreateHandTrackerEXT) \ _(xrDestroyHandTrackerEXT) \ _(xrLocateHandJointsEXT) \ _(xrCreateHandMeshSpaceMSFT) \ _(xrUpdateHandMeshMSFT) \ _(xrEnumerateColorSpacesFB) \ _(xrSetColorSpaceFB) \ _(xrCreateSpatialGraphNodeSpaceMSFT) \ _(xrCreateDebugUtilsMessengerEXT) \ _(xrDestroyDebugUtilsMessengerEXT) #if defined(_WIN32) #define FOR_EACH_PLATFORM_FUNCTION(_) \ _(xrConvertWin32PerformanceCounterToTimeKHR) \ _(xrConvertTimeToWin32PerformanceCounterKHR) \ _(xrCreateSpatialAnchorFromPerceptionAnchorMSFT) \ _(xrGetAudioOutputDeviceGuidOculus) \ _(xrGetAudioInputDeviceGuidOculus) #else #define FOR_EACH_PLATFORM_FUNCTION(_) \ _(xrConvertTimespecTimeToTimeKHR ) \ _(xrConvertTimeToTimespecTimeKHR ) #endif /////////////////////////////////////////// #define DEFINE_PROC_MEMBER(name) PFN_##name name; struct XrExtTable { FOR_EACH_EXTENSION_FUNCTION(DEFINE_PROC_MEMBER); FOR_EACH_PLATFORM_FUNCTION(DEFINE_PROC_MEMBER); PFN_xrGetGraphicsRequirementsKHR xrGetGraphicsRequirementsKHR; }; extern XrExtTable xr_extensions; #define GET_INSTANCE_PROC_ADDRESS(name) (void)xrGetInstanceProcAddr(instance, #name, (PFN_xrVoidFunction*)((PFN_##name*)(&result.name))); inline XrExtTable xrCreateExtensionTable(XrInstance instance) { XrExtTable result = {}; FOR_EACH_EXTENSION_FUNCTION(GET_INSTANCE_PROC_ADDRESS); FOR_EACH_PLATFORM_FUNCTION(GET_INSTANCE_PROC_ADDRESS); (void)xrGetInstanceProcAddr(instance, NAME_xrGetGraphicsRequirementsKHR, (PFN_xrVoidFunction*)((PFN_xrGetGraphicsRequirementsKHR)(&result.xrGetGraphicsRequirementsKHR))); return result; } #undef DEFINE_PROC_MEMBER #undef GET_INSTANCE_PROC_ADDRESS #undef FOR_EACH_EXTENSION_FUNCTION #undef FOR_EACH_PLATFORM_FUNCTION #undef FOR_EACH_GRAPHICS_FUNCTION /////////////////////////////////////////// #define DEFINE_EXT_INFO(name, available) bool name; typedef struct XrExtInfo { bool gfx_extension; bool time_extension; FOR_EACH_EXT_ALL (DEFINE_EXT_INFO); FOR_EACH_EXT_UWP (DEFINE_EXT_INFO); FOR_EACH_EXT_ANDROID(DEFINE_EXT_INFO); FOR_EACH_EXT_LINUX (DEFINE_EXT_INFO); FOR_EACH_EXT_DEBUG (DEFINE_EXT_INFO); } XrExtInfo; extern XrExtInfo xr_ext_available; inline array_t openxr_list_extensions(array_t extra_exts, array_t exclude_exts, bool minimum_exts, void (*on_available)(const char *name)) { array_t result = {}; // Enumerate the list of extensions available on the system uint32_t ext_count = 0; if (XR_FAILED(xrEnumerateInstanceExtensionProperties(nullptr, 0, &ext_count, nullptr))) return result; XrExtensionProperties* exts = sk_malloc_t(XrExtensionProperties, ext_count); for (uint32_t i = 0; i < ext_count; i++) exts[i] = { XR_TYPE_EXTENSION_PROPERTIES }; xrEnumerateInstanceExtensionProperties(nullptr, ext_count, &ext_count, exts); qsort(exts, ext_count, sizeof(XrExtensionProperties), [](const void* a, const void* b) { return strcmp(((XrExtensionProperties*)a)->extensionName, ((XrExtensionProperties*)b)->extensionName); }); // See which of the available extensions we want to use for (uint32_t i = 0; i < ext_count; i++) { // These extensions are required for StereoKit to function if (strcmp(exts[i].extensionName, XR_GFX_EXTENSION) == 0) { result.add(XR_GFX_EXTENSION); continue; } if (strcmp(exts[i].extensionName, XR_TIME_EXTENSION) == 0) { result.add(XR_TIME_EXTENSION); continue; } #if defined(SK_OS_ANDROID) if (strcmp(exts[i].extensionName, "XR_KHR_android_create_instance") == 0) { result.add("XR_KHR_android_create_instance"); continue; } #endif // Skip this extension if it's a specifically excluded one bool skip = false; for (int32_t e = 0; e < exclude_exts.count; e++) { if (strcmp(exts[i].extensionName, exclude_exts[e]) == 0) { skip = true; break; } } if (skip) { if (on_available != nullptr) { on_available(exts[i].extensionName); } continue; } // Check if the current extension is a user requested extra, and if // so, add it bool found = false; for (int32_t e = 0; e < extra_exts.count; e++) { if (strcmp(exts[i].extensionName, extra_exts[e]) == 0) { result.add(extra_exts[e]); found = true; break; } } if (found) continue; // We're only interested required extensions if we're using minimum // extension mode if (minimum_exts) { if (on_available != nullptr) { on_available(exts[i].extensionName); } continue; } // Check if this extension matches any extensions that StereoKit wants #define ADD_NAME(name, available) else if (available && strcmp("XR_"#name, exts[i].extensionName) == 0) {result.add("XR_"#name);} if (false) {} FOR_EACH_EXT_ALL (ADD_NAME) FOR_EACH_EXT_UWP (ADD_NAME) FOR_EACH_EXT_ANDROID(ADD_NAME) FOR_EACH_EXT_LINUX (ADD_NAME) FOR_EACH_EXT_DEBUG (ADD_NAME) else { // We got to the end, and no-one loves this extension. We'll let // 'em know it's at least available! if (on_available != nullptr) { on_available(exts[i].extensionName); } } #undef ADD_NAME } // Mark each extension that made it to this point as available in the // xr_ext_available struct for (int32_t i = 0; i < result.count; i++) { #define CHECK_EXT(name, available) else if (strcmp("XR_"#name, result[i]) == 0) {xr_ext_available.name = true;} if (false) {} FOR_EACH_EXT_ALL (CHECK_EXT) FOR_EACH_EXT_UWP (CHECK_EXT) FOR_EACH_EXT_ANDROID(CHECK_EXT) FOR_EACH_EXT_LINUX (CHECK_EXT) FOR_EACH_EXT_DEBUG (CHECK_EXT) #undef CHECK_EXT } sk_free(exts); return result; } #undef DEFINE_EXT_INFO #undef EXT_AVAILABLE_UWP #undef EXT_AVAILABLE_ANDROID #undef EXT_AVAILABLE_DEBUG #undef FOR_EACH_EXT_ALL #undef FOR_EACH_EXT_UWP #undef FOR_EACH_EXT_ANDROID #undef FOR_EACH_EXT_LINUX #undef FOR_EACH_EXT_DEBUG #pragma warning( pop ) } #endif