diff options
Diffstat (limited to 'modules/openxr/openxr_api.cpp')
-rw-r--r-- | modules/openxr/openxr_api.cpp | 359 |
1 files changed, 304 insertions, 55 deletions
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 94095eb61c..8a69072793 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -41,6 +41,7 @@ #endif #ifdef ANDROID_ENABLED +#define OPENXR_LOADER_NAME "libopenxr_loader.so" #include "extensions/openxr_android_extension.h" #endif @@ -48,7 +49,11 @@ #include "extensions/openxr_vulkan_extension.h" #endif +#include "extensions/openxr_composition_layer_depth_extension.h" +#include "extensions/openxr_fb_passthrough_extension_wrapper.h" +#include "extensions/openxr_hand_tracking_extension.h" #include "extensions/openxr_htc_vive_tracker_extension.h" +#include "extensions/openxr_palm_pose_extension.h" #include "modules/openxr/openxr_interface.h" @@ -184,6 +189,20 @@ bool OpenXRAPI::is_extension_supported(const String &p_extension) const { return false; } +bool OpenXRAPI::is_path_supported(const String &p_path) { + // This checks with extensions whether a path is *unsupported* and returns false if this is so. + // This allows us to filter out paths that are only available if related extensions are supported. + // WARNING: This method will return true for unknown/mistyped paths as we have no way to validate those. + + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + if (!wrapper->is_path_supported(p_path)) { + return false; + } + } + + return true; +} + void OpenXRAPI::copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len) { CharString char_string = p_string.utf8(); int len = char_string.length(); @@ -284,6 +303,9 @@ bool OpenXRAPI::create_instance() { 0, // runtimeVersion, from here will be set by our get call "" // runtimeName }; + + OPENXR_API_INIT_XR_FUNC_V(xrGetInstanceProperties); + result = xrGetInstanceProperties(instance, &instanceProps); if (XR_FAILED(result)) { // not fatal probably @@ -642,7 +664,7 @@ bool OpenXRAPI::is_swapchain_format_supported(int64_t p_swapchain_format) { return false; } -bool OpenXRAPI::create_main_swapchain() { +bool OpenXRAPI::create_swapchains() { ERR_FAIL_NULL_V(graphics_extension, false); ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); @@ -660,34 +682,36 @@ bool OpenXRAPI::create_main_swapchain() { already rendering the next frame. Finally an area we need to expand upon is that Foveated rendering is only enabled for the swap chain we create, - as we render 3D content into internal buffers that are copied into the swapchain, we don't get any of the performance gains - until such time as we implement VRS. + as we render 3D content into internal buffers that are copied into the swapchain, we do now have (basic) VRS support */ - // Build a vector with swapchain formats we want to use, from best fit to worst - Vector<int64_t> usable_swapchain_formats; - int64_t swapchain_format_to_use = 0; + Size2 recommended_size = get_recommended_target_size(); - graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); + // We start with our color swapchain... + { + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; - // now find out which one is supported - for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { - if (is_swapchain_format_supported(usable_swapchain_formats[i])) { - swapchain_format_to_use = usable_swapchain_formats[i]; - } - } + graphics_extension->get_usable_swapchain_formats(usable_swapchain_formats); - if (swapchain_format_to_use == 0) { - swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... - print_line("Couldn't find usable swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); - } else { - print_line("Using swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); - } + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } - Size2 recommended_size = get_recommended_target_size(); + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable color swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using color swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } - if (!create_swapchain(swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchain, &swapchain_graphics_data)) { - return false; + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain, &swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data)) { + return false; + } } views = (XrView *)memalloc(sizeof(XrView) * view_count); @@ -696,18 +720,73 @@ bool OpenXRAPI::create_main_swapchain() { projection_views = (XrCompositionLayerProjectionView *)memalloc(sizeof(XrCompositionLayerProjectionView) * view_count); ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); + // We create our depth swapchain if: + // - we support our depth layer extension + // - we have our spacewarp extension (not yet implemented) + if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { + // Build a vector with swapchain formats we want to use, from best fit to worst + Vector<int64_t> usable_swapchain_formats; + int64_t swapchain_format_to_use = 0; + + graphics_extension->get_usable_depth_formats(usable_swapchain_formats); + + // now find out which one is supported + for (int i = 0; i < usable_swapchain_formats.size() && swapchain_format_to_use == 0; i++) { + if (is_swapchain_format_supported(usable_swapchain_formats[i])) { + swapchain_format_to_use = usable_swapchain_formats[i]; + } + } + + if (swapchain_format_to_use == 0) { + swapchain_format_to_use = usable_swapchain_formats[0]; // just use the first one and hope for the best... + print_line("Couldn't find usable depth swap chain format, using", get_swapchain_format_name(swapchain_format_to_use), "instead."); + } else { + print_line("Using depth swap chain format:", get_swapchain_format_name(swapchain_format_to_use)); + } + + if (!create_swapchain(XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, swapchain_format_to_use, recommended_size.width, recommended_size.height, view_configuration_views[0].recommendedSwapchainSampleCount, view_count, swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain, &swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data)) { + return false; + } + + depth_views = (XrCompositionLayerDepthInfoKHR *)memalloc(sizeof(XrCompositionLayerDepthInfoKHR) * view_count); + ERR_FAIL_NULL_V_MSG(depth_views, false, "OpenXR Couldn't allocate memory for depth views"); + } + + // We create our velocity swapchain if: + // - we have our spacewarp extension (not yet implemented) + { + // TBD + } + for (uint32_t i = 0; i < view_count; i++) { views[i].type = XR_TYPE_VIEW; views[i].next = nullptr; projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW; projection_views[i].next = nullptr; - projection_views[i].subImage.swapchain = swapchain; + projection_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain; projection_views[i].subImage.imageArrayIndex = i; projection_views[i].subImage.imageRect.offset.x = 0; projection_views[i].subImage.imageRect.offset.y = 0; projection_views[i].subImage.imageRect.extent.width = recommended_size.width; projection_views[i].subImage.imageRect.extent.height = recommended_size.height; + + if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available() && depth_views) { + projection_views[i].next = &depth_views[i]; + + depth_views[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR; + depth_views[i].next = nullptr; + depth_views[i].subImage.swapchain = swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain; + depth_views[i].subImage.imageArrayIndex = 0; + depth_views[i].subImage.imageRect.offset.x = 0; + depth_views[i].subImage.imageRect.offset.y = 0; + depth_views[i].subImage.imageRect.extent.width = recommended_size.width; + depth_views[i].subImage.imageRect.extent.height = recommended_size.height; + depth_views[i].minDepth = 0.0; + depth_views[i].maxDepth = 1.0; + depth_views[i].nearZ = 0.01; // Near and far Z will be set to the correct values in fill_projection_matrix + depth_views[i].farZ = 100.0; + } }; return true; @@ -719,7 +798,7 @@ void OpenXRAPI::destroy_session() { } if (graphics_extension) { - graphics_extension->cleanup_swapchain_graphics_data(&swapchain_graphics_data); + graphics_extension->cleanup_swapchain_graphics_data(&swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data); } if (views != nullptr) { @@ -732,9 +811,16 @@ void OpenXRAPI::destroy_session() { projection_views = nullptr; } - if (swapchain != XR_NULL_HANDLE) { - xrDestroySwapchain(swapchain); - swapchain = XR_NULL_HANDLE; + if (depth_views != nullptr) { + memfree(depth_views); + depth_views = nullptr; + } + + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (swapchains[i].swapchain != XR_NULL_HANDLE) { + xrDestroySwapchain(swapchains[i].swapchain); + swapchains[i].swapchain = XR_NULL_HANDLE; + } } if (supported_swapchain_formats != nullptr) { @@ -768,7 +854,7 @@ void OpenXRAPI::destroy_session() { } } -bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { +bool OpenXRAPI::create_swapchain(XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data) { ERR_FAIL_COND_V(session == XR_NULL_HANDLE, false); ERR_FAIL_NULL_V(graphics_extension, false); @@ -786,7 +872,7 @@ bool OpenXRAPI::create_swapchain(int64_t p_swapchain_format, uint32_t p_width, u XR_TYPE_SWAPCHAIN_CREATE_INFO, // type next_pointer, // next 0, // createFlags - XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT, // usageFlags + p_usage_flags, // usageFlags p_swapchain_format, // format p_sample_count, // sampleCount p_width, // width @@ -850,7 +936,7 @@ bool OpenXRAPI::on_state_ready() { // That will be very very ugly // The other possibility is to create a separate OpenXRViewport type specifically for this goal as part of our OpenXR module - if (!create_main_swapchain()) { + if (!create_swapchains()) { return false; } @@ -992,9 +1078,94 @@ bool OpenXRAPI::is_running() { return running; } +bool OpenXRAPI::openxr_loader_init() { +#ifdef ANDROID_ENABLED + ERR_FAIL_COND_V_MSG(openxr_loader_library_handle != nullptr, false, "OpenXR Loader library is already loaded."); + + { + Error error_code = OS::get_singleton()->open_dynamic_library(OPENXR_LOADER_NAME, openxr_loader_library_handle); + ERR_FAIL_COND_V_MSG(error_code != OK, false, "OpenXR loader not found."); + } + + { + Error error_code = OS::get_singleton()->get_dynamic_library_symbol_handle(openxr_loader_library_handle, "xrGetInstanceProcAddr", (void *&)xrGetInstanceProcAddr); + ERR_FAIL_COND_V_MSG(error_code != OK, false, "Symbol xrGetInstanceProcAddr not found in OpenXR Loader library."); + } +#endif + + // Resolve the symbols that don't require an instance + OPENXR_API_INIT_XR_FUNC_V(xrCreateInstance); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateApiLayerProperties); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateInstanceExtensionProperties); + + return true; +} + +bool OpenXRAPI::resolve_instance_openxr_symbols() { + ERR_FAIL_COND_V(instance == XR_NULL_HANDLE, false); + + OPENXR_API_INIT_XR_FUNC_V(xrAcquireSwapchainImage); + OPENXR_API_INIT_XR_FUNC_V(xrApplyHapticFeedback); + OPENXR_API_INIT_XR_FUNC_V(xrAttachSessionActionSets); + OPENXR_API_INIT_XR_FUNC_V(xrBeginFrame); + OPENXR_API_INIT_XR_FUNC_V(xrBeginSession); + OPENXR_API_INIT_XR_FUNC_V(xrCreateAction); + OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSet); + OPENXR_API_INIT_XR_FUNC_V(xrCreateActionSpace); + OPENXR_API_INIT_XR_FUNC_V(xrCreateReferenceSpace); + OPENXR_API_INIT_XR_FUNC_V(xrCreateSession); + OPENXR_API_INIT_XR_FUNC_V(xrCreateSwapchain); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyAction); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyActionSet); + OPENXR_API_INIT_XR_FUNC_V(xrDestroyInstance); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySession); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySpace); + OPENXR_API_INIT_XR_FUNC_V(xrDestroySwapchain); + OPENXR_API_INIT_XR_FUNC_V(xrEndFrame); + OPENXR_API_INIT_XR_FUNC_V(xrEndSession); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateReferenceSpaces); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateSwapchainFormats); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurations); + OPENXR_API_INIT_XR_FUNC_V(xrEnumerateViewConfigurationViews); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateBoolean); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateFloat); + OPENXR_API_INIT_XR_FUNC_V(xrGetActionStateVector2f); + OPENXR_API_INIT_XR_FUNC_V(xrGetCurrentInteractionProfile); + OPENXR_API_INIT_XR_FUNC_V(xrGetSystem); + OPENXR_API_INIT_XR_FUNC_V(xrGetSystemProperties); + OPENXR_API_INIT_XR_FUNC_V(xrLocateViews); + OPENXR_API_INIT_XR_FUNC_V(xrLocateSpace); + OPENXR_API_INIT_XR_FUNC_V(xrPathToString); + OPENXR_API_INIT_XR_FUNC_V(xrPollEvent); + OPENXR_API_INIT_XR_FUNC_V(xrReleaseSwapchainImage); + OPENXR_API_INIT_XR_FUNC_V(xrResultToString); + OPENXR_API_INIT_XR_FUNC_V(xrStringToPath); + OPENXR_API_INIT_XR_FUNC_V(xrSuggestInteractionProfileBindings); + OPENXR_API_INIT_XR_FUNC_V(xrSyncActions); + OPENXR_API_INIT_XR_FUNC_V(xrWaitFrame); + OPENXR_API_INIT_XR_FUNC_V(xrWaitSwapchainImage); + + return true; +} + +XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) { + XrResult result = xrGetInstanceProcAddr(instance, p_name, p_addr); + + if (result != XR_SUCCESS) { + String error_message = String("Symbol ") + p_name + " not found in OpenXR instance."; + ERR_FAIL_COND_V_MSG(true, result, error_message.utf8().get_data()); + } + + return result; +} + bool OpenXRAPI::initialize(const String &p_rendering_driver) { ERR_FAIL_COND_V_MSG(instance != XR_NULL_HANDLE, false, "OpenXR instance was already created"); + if (!openxr_loader_init()) { + return false; + } + if (p_rendering_driver == "vulkan") { #ifdef VULKAN_ENABLED graphics_extension = memnew(OpenXRVulkanExtension(this)); @@ -1017,6 +1188,10 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { } // initialize + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_before_instance_created(); + } + if (!load_layer_properties()) { destroy_instance(); return false; @@ -1032,6 +1207,11 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { return false; } + if (!resolve_instance_openxr_symbols()) { + destroy_instance(); + return false; + } + if (!get_system_info()) { destroy_instance(); return false; @@ -1189,6 +1369,15 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z return false; } + // if we're using depth views, make sure we update our near and far there... + if (depth_views != nullptr) { + for (uint32_t i = 0; i < view_count; i++) { + depth_views[i].nearZ = p_z_near; + depth_views[i].farZ = p_z_far; + } + } + + // now update our projection return graphics_extension->create_projection_fov(views[p_view].fov, p_z_near, p_z_far, p_camera_matrix); } @@ -1327,15 +1516,15 @@ bool OpenXRAPI::process() { return true; } -bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) { - ERR_FAIL_COND_V(image_acquired, true); // this was not released when it should be, error out and re-use... +bool OpenXRAPI::acquire_image(OpenXRSwapChainInfo &p_swapchain) { + ERR_FAIL_COND_V(p_swapchain.image_acquired, true); // this was not released when it should be, error out and re-use... XrResult result; XrSwapchainImageAcquireInfo swapchain_image_acquire_info = { XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO, // type nullptr // next }; - result = xrAcquireSwapchainImage(p_swapchain, &swapchain_image_acquire_info, &r_image_index); + result = xrAcquireSwapchainImage(p_swapchain.swapchain, &swapchain_image_acquire_info, &p_swapchain.image_index); if (XR_FAILED(result)) { print_line("OpenXR: failed to acquire swapchain image [", get_error_string(result), "]"); return false; @@ -1347,7 +1536,7 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) 17000000 // timeout in nanoseconds }; - result = xrWaitSwapchainImage(p_swapchain, &swapchain_image_wait_info); + result = xrWaitSwapchainImage(p_swapchain.swapchain, &swapchain_image_wait_info); if (XR_FAILED(result)) { print_line("OpenXR: failed to wait for swapchain image [", get_error_string(result), "]"); return false; @@ -1356,12 +1545,12 @@ bool OpenXRAPI::acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index) return true; } -bool OpenXRAPI::release_image(XrSwapchain p_swapchain) { +bool OpenXRAPI::release_image(OpenXRSwapChainInfo &p_swapchain) { XrSwapchainImageReleaseInfo swapchain_image_release_info = { XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO, // type nullptr // next }; - XrResult result = xrReleaseSwapchainImage(swapchain, &swapchain_image_release_info); + XrResult result = xrReleaseSwapchainImage(p_swapchain.swapchain, &swapchain_image_release_info); if (XR_FAILED(result)) { print_line("OpenXR: failed to release swapchain image! [", get_error_string(result), "]"); return false; @@ -1382,6 +1571,10 @@ void OpenXRAPI::pre_render() { // 2) It will use the previous timing to pause our thread so that rendering starts as close to displaying as possible // This must thus be called as close to when we start rendering as possible XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; + frame_state.predictedDisplayTime = 0; + frame_state.predictedDisplayPeriod = 0; + frame_state.shouldRender = false; + XrResult result = xrWaitFrame(session, &frame_wait_info, &frame_state); if (XR_FAILED(result)) { print_line("OpenXR: xrWaitFrame() was not successful [", get_error_string(result), "]"); @@ -1471,28 +1664,41 @@ bool OpenXRAPI::pre_draw_viewport(RID p_render_target) { // TODO: at some point in time we may support multiple viewports in which case we need to handle that... + // Acquire our images + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (!swapchains[i].image_acquired && swapchains[i].swapchain != XR_NULL_HANDLE) { + if (!acquire_image(swapchains[i])) { + return false; + } + swapchains[i].image_acquired = true; + } + } + return true; } +RID OpenXRAPI::get_color_texture() { + if (swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) { + return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_COLOR].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_COLOR].image_index); + } else { + return RID(); + } +} + +RID OpenXRAPI::get_depth_texture() { + if (swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) { + return graphics_extension->get_texture(swapchains[OPENXR_SWAPCHAIN_DEPTH].swapchain_graphics_data, swapchains[OPENXR_SWAPCHAIN_DEPTH].image_index); + } else { + return RID(); + } +} + void OpenXRAPI::post_draw_viewport(RID p_render_target) { if (!can_render()) { return; } - // TODO: at some point in time we may support multiple viewports in which case we need to handle that... - - // TODO: if we can get PR 51179 to work properly we can change away from this approach and move this into get_external_texture or something - if (!image_acquired) { - if (!acquire_image(swapchain, image_index)) { - return; - } - image_acquired = true; - - // print_line("OpenXR: acquired image " + itos(image_index) + ", copying..."); - - // Copy our buffer into our swap chain (remove once PR 51179 is done) - graphics_extension->copy_render_target_to_image(p_render_target, swapchain_graphics_data, image_index); - } + // Nothing to do here at this point in time... }; void OpenXRAPI::end_frame() { @@ -1504,7 +1710,7 @@ void OpenXRAPI::end_frame() { return; } - if (frame_state.shouldRender && view_pose_valid && !image_acquired) { + if (frame_state.shouldRender && view_pose_valid && !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) { print_line("OpenXR: No viewport was marked with use_xr, there is no rendered output!"); } @@ -1512,7 +1718,7 @@ void OpenXRAPI::end_frame() { // - shouldRender set to true // - a valid view pose for projection_views[eye].pose to submit layer // - an image to render - if (!frame_state.shouldRender || !view_pose_valid || !image_acquired) { + if (!frame_state.shouldRender || !view_pose_valid || !swapchains[OPENXR_SWAPCHAIN_COLOR].image_acquired) { // submit 0 layers when we shouldn't render XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type @@ -1533,10 +1739,12 @@ void OpenXRAPI::end_frame() { } // release our swapchain image if we acquired it - if (image_acquired) { - image_acquired = false; // whether we succeed or not, consider this released. + for (int i = 0; i < OPENXR_SWAPCHAIN_MAX; i++) { + if (swapchains[i].image_acquired) { + swapchains[i].image_acquired = false; // whether we succeed or not, consider this released. - release_image(swapchain); + release_image(swapchains[i]); + } } for (uint32_t eye = 0; eye < view_count; eye++) { @@ -1643,7 +1851,11 @@ OpenXRAPI::OpenXRAPI() { #endif // register our other extensions + register_extension_wrapper(memnew(OpenXRPalmPoseExtension(this))); + register_extension_wrapper(memnew(OpenXRCompositionLayerDepthExtension(this))); register_extension_wrapper(memnew(OpenXRHTCViveTrackerExtension(this))); + register_extension_wrapper(memnew(OpenXRHandTrackingExtension(this))); + register_extension_wrapper(memnew(OpenXRFbPassthroughExtensionWrapper(this))); } OpenXRAPI::~OpenXRAPI() { @@ -1669,6 +1881,13 @@ OpenXRAPI::~OpenXRAPI() { layer_properties = nullptr; } +#ifdef ANDROID_ENABLED + if (openxr_loader_library_handle) { + OS::get_singleton()->close_dynamic_library(openxr_loader_library_handle); + openxr_loader_library_handle = nullptr; + } +#endif + singleton = nullptr; } @@ -1745,6 +1964,18 @@ void OpenXRAPI::parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_l } } +bool OpenXRAPI::xr_result(XrResult result, const char *format, Array args) const { + if (XR_SUCCEEDED(result)) + return true; + + char resultString[XR_MAX_RESULT_STRING_SIZE]; + xrResultToString(instance, result, resultString); + + print_error(String("OpenXR ") + String(format).format(args) + String(" [") + String(resultString) + String("]")); + + return false; +} + RID OpenXRAPI::get_tracker_rid(XrPath p_path) { List<RID> current; tracker_owner.get_owned_list(¤t); @@ -2063,6 +2294,11 @@ XrPath OpenXRAPI::get_interaction_profile_path(RID p_interaction_profile) { } RID OpenXRAPI::interaction_profile_create(const String p_name) { + if (!is_path_supported(p_name)) { + // The extension enabling this path must not be active, we will silently skip this interaction profile + return RID(); + } + InteractionProfile new_interaction_profile; XrResult result = xrStringToPath(instance, p_name.utf8().get_data(), &new_interaction_profile.path); @@ -2099,6 +2335,11 @@ void OpenXRAPI::interaction_profile_clear_bindings(RID p_interaction_profile) { } bool OpenXRAPI::interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path) { + if (!is_path_supported(p_path)) { + // The extension enabling this path must not be active, we will silently skip this binding + return false; + } + InteractionProfile *ip = interaction_profile_owner.get_or_null(p_interaction_profile); ERR_FAIL_NULL_V(ip, false); @@ -2426,3 +2667,11 @@ bool OpenXRAPI::trigger_haptic_pulse(RID p_action, RID p_tracker, float p_freque return true; } + +void OpenXRAPI::register_composition_layer_provider(OpenXRCompositionLayerProvider *provider) { + composition_layer_providers.append(provider); +} + +void OpenXRAPI::unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider) { + composition_layer_providers.erase(provider); +} |