diff options
Diffstat (limited to 'modules/openxr/openxr_api.cpp')
-rw-r--r-- | modules/openxr/openxr_api.cpp | 273 |
1 files changed, 181 insertions, 92 deletions
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 88111afede..0a25cd68b7 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -1,32 +1,32 @@ -/*************************************************************************/ -/* openxr_api.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ +/**************************************************************************/ +/* openxr_api.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ #include "openxr_api.h" #include "openxr_util.h" @@ -42,7 +42,6 @@ #ifdef ANDROID_ENABLED #define OPENXR_LOADER_NAME "libopenxr_loader.so" -#include "extensions/openxr_android_extension.h" #endif // We need to have all the graphics API defines before the Vulkan or OpenGL @@ -51,7 +50,7 @@ #define XR_USE_GRAPHICS_API_VULKAN #endif #ifdef GLES3_ENABLED -#ifdef ANDROID +#ifdef ANDROID_ENABLED #define XR_USE_GRAPHICS_API_OPENGL_ES #include <EGL/egl.h> #include <EGL/eglext.h> @@ -59,14 +58,13 @@ #include <GLES3/gl3ext.h> #else #define XR_USE_GRAPHICS_API_OPENGL -#endif // ANDROID +#endif // ANDROID_ENABLED #ifdef X11_ENABLED #include OPENGL_INCLUDE_H #define GL_GLEXT_PROTOTYPES 1 #define GL3_PROTOTYPES 1 -#include <GL/gl.h> -#include <GL/glext.h> -#include <GL/glx.h> +#include "thirdparty/glad/glad/gl.h" +#include "thirdparty/glad/glad/glx.h" #include <X11/Xlib.h> #endif // X11_ENABLED #endif // GLES_ENABLED @@ -82,13 +80,11 @@ #include "extensions/openxr_composition_layer_depth_extension.h" #include "extensions/openxr_fb_display_refresh_rate_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" OpenXRAPI *OpenXRAPI::singleton = nullptr; +Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers; bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { // @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled" @@ -105,10 +101,6 @@ bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) { } } -OpenXRAPI *OpenXRAPI::get_singleton() { - return singleton; -} - String OpenXRAPI::get_default_action_map_resource_name() { String name = GLOBAL_GET("xr/openxr/default_action_map"); @@ -209,17 +201,79 @@ 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. +bool OpenXRAPI::is_extension_enabled(const String &p_extension) const { + CharString extension = p_extension.ascii(); - for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { - if (!wrapper->is_path_supported(p_path)) { - return false; + for (int i = 0; i < enabled_extensions.size(); i++) { + if (strcmp(enabled_extensions[i].ptr(), extension.ptr()) == 0) { + return true; } } + return false; +} + +bool OpenXRAPI::is_top_level_path_supported(const String &p_toplevel_path) { + String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_top_level_extension(p_toplevel_path); + + // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error. + ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported toplevel path " + p_toplevel_path); + + if (required_extension == "") { + // no extension needed, core top level are always "supported", they just won't be used if not really supported + return true; + } + + if (!is_extension_enabled(required_extension)) { + // It is very likely we have top level paths for which the extension is not available so don't flood the logs with unnecessary spam. + print_verbose("OpenXR: Top level path " + p_toplevel_path + " requires extension " + required_extension); + return false; + } + + return true; +} + +bool OpenXRAPI::is_interaction_profile_supported(const String &p_ip_path) { + String required_extension = OpenXRInteractionProfileMetaData::get_singleton()->get_interaction_profile_extension(p_ip_path); + + // If unsupported is returned we likely have a misspelled interaction profile path in our action map. Always output that as an error. + ERR_FAIL_COND_V_MSG(required_extension == XR_PATH_UNSUPPORTED_NAME, false, "OpenXR: Unsupported interaction profile " + p_ip_path); + + if (required_extension == "") { + // no extension needed, core interaction profiles are always "supported", they just won't be used if not really supported + return true; + } + + if (!is_extension_enabled(required_extension)) { + // It is very likely we have interaction profiles for which the extension is not available so don't flood the logs with unnecessary spam. + print_verbose("OpenXR: Interaction profile " + p_ip_path + " requires extension " + required_extension); + return false; + } + + return true; +} + +bool OpenXRAPI::interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path) { + if (!is_interaction_profile_supported(p_ip_path)) { + return false; + } + + const OpenXRInteractionProfileMetaData::IOPath *io_path = OpenXRInteractionProfileMetaData::get_singleton()->get_io_path(p_ip_path, p_io_path); + + // If the io_path is not part of our meta data we've likely got a misspelled name or a bad action map, report + ERR_FAIL_NULL_V_MSG(io_path, false, "OpenXR: Unsupported io path " + String(p_ip_path) + String(p_io_path)); + + if (io_path->openxr_extension_name == "") { + // no extension needed, core io paths are always "supported", they just won't be used if not really supported + return true; + } + + if (!is_extension_enabled(io_path->openxr_extension_name)) { + // It is very likely we have io paths for which the extension is not available so don't flood the logs with unnecessary spam. + print_verbose("OpenXR: IO path " + String(p_ip_path) + String(p_io_path) + " requires extension " + io_path->openxr_extension_name); + return false; + } + return true; } @@ -242,7 +296,7 @@ bool OpenXRAPI::create_instance() { // Append the extensions requested by the registered extension wrappers. HashMap<String, bool *> requested_extensions; for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { - const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_request_extensions(); + const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_requested_extensions(); // requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end()); for (auto &requested_extension : wrapper_request_extensions) { @@ -250,14 +304,6 @@ bool OpenXRAPI::create_instance() { } } - // Add optional extensions for controllers that may be supported. - // Overkill to create extension classes for this. - requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available; - requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available; - requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available; - requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available; - requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available; - // Check which extensions are supported enabled_extensions.clear(); @@ -284,6 +330,7 @@ bool OpenXRAPI::create_instance() { Vector<const char *> extension_ptrs; for (int i = 0; i < enabled_extensions.size(); i++) { + print_verbose(String("OpenXR: Enabling extension ") + String(enabled_extensions[i])); extension_ptrs.push_back(enabled_extensions[i].get_data()); } @@ -299,9 +346,17 @@ bool OpenXRAPI::create_instance() { XR_CURRENT_API_VERSION // apiVersion }; + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_instance_create_info_and_get_next_pointer(next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + XrInstanceCreateInfo instance_create_info = { XR_TYPE_INSTANCE_CREATE_INFO, // type - nullptr, // next + next_pointer, // next 0, // createFlags application_info, // applicationInfo 0, // enabledApiLayerCount, need to find out if we need support for this? @@ -505,6 +560,12 @@ void OpenXRAPI::destroy_instance() { instance = XR_NULL_HANDLE; } enabled_extensions.clear(); + + if (graphics_extension != nullptr) { + unregister_extension_wrapper(graphics_extension); + memdelete(graphics_extension); + graphics_extension = nullptr; + } } bool OpenXRAPI::create_session() { @@ -690,7 +751,7 @@ bool OpenXRAPI::create_swapchains() { Also Godot only creates a swapchain for the main output. OpenXR will require us to create swapchains as the render target for additional viewports if we want to use the layer system - to optimise text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're + to optimize text rendering and background rendering as OpenXR may choose to re-use the results for reprojection while we're 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, @@ -733,9 +794,10 @@ bool OpenXRAPI::create_swapchains() { ERR_FAIL_NULL_V_MSG(projection_views, false, "OpenXR Couldn't allocate memory for projection views"); // We create our depth swapchain if: + // - we've enabled submitting depth buffer // - we support our depth layer extension // - we have our spacewarp extension (not yet implemented) - if (OpenXRCompositionLayerDepthExtension::get_singleton()->is_available()) { + if (submit_depth_buffer && 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; @@ -783,13 +845,13 @@ bool OpenXRAPI::create_swapchains() { 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) { + if (submit_depth_buffer && 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.imageArrayIndex = i; 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; @@ -1059,6 +1121,30 @@ bool OpenXRAPI::on_state_exiting() { return true; } +void OpenXRAPI::set_form_factor(XrFormFactor p_form_factor) { + ERR_FAIL_COND(is_initialized()); + + form_factor = p_form_factor; +} + +void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configuration) { + ERR_FAIL_COND(is_initialized()); + + view_configuration = p_view_configuration; +} + +void OpenXRAPI::set_reference_space(XrReferenceSpaceType p_reference_space) { + ERR_FAIL_COND(is_initialized()); + + reference_space = p_reference_space; +} + +void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) { + ERR_FAIL_COND(is_initialized()); + + submit_depth_buffer = p_submit_depth_buffer; +} + bool OpenXRAPI::is_initialized() { return (instance != XR_NULL_HANDLE); } @@ -1144,8 +1230,12 @@ bool OpenXRAPI::resolve_instance_openxr_symbols() { return true; } +XrResult OpenXRAPI::try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) { + return xrGetInstanceProcAddr(instance, p_name, p_addr); +} + XrResult OpenXRAPI::get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr) { - XrResult result = xrGetInstanceProcAddr(instance, p_name, p_addr); + XrResult result = try_get_instance_proc_addr(p_name, p_addr); if (result != XR_SUCCESS) { String error_message = String("Symbol ") + p_name + " not found in OpenXR instance."; @@ -1164,7 +1254,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { if (p_rendering_driver == "vulkan") { #ifdef VULKAN_ENABLED - graphics_extension = memnew(OpenXRVulkanExtension(this)); + graphics_extension = memnew(OpenXRVulkanExtension); register_extension_wrapper(graphics_extension); #else // shouldn't be possible... @@ -1172,7 +1262,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) { #endif } else if (p_rendering_driver == "opengl3") { #ifdef GLES3_ENABLED - graphics_extension = memnew(OpenXROpenGLExtension(this)); + graphics_extension = memnew(OpenXROpenGLExtension); register_extension_wrapper(graphics_extension); #else // shouldn't be possible... @@ -1263,6 +1353,23 @@ void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_w registered_extension_wrappers.push_back(p_extension_wrapper); } +void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) { + registered_extension_wrappers.erase(p_extension_wrapper); +} + +void OpenXRAPI::register_extension_metadata() { + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + extension_wrapper->on_register_metadata(); + } +} + +void OpenXRAPI::cleanup_extension_wrappers() { + for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { + memdelete(extension_wrapper); + } + registered_extension_wrappers.clear(); +} + Size2 OpenXRAPI::get_recommended_target_size() { ERR_FAIL_NULL_V(view_configuration_views, Size2()); @@ -1677,7 +1784,7 @@ RID OpenXRAPI::get_color_texture() { } RID OpenXRAPI::get_depth_texture() { - if (swapchains[OPENXR_SWAPCHAIN_DEPTH].image_acquired) { + if (submit_depth_buffer && 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(); @@ -1855,24 +1962,13 @@ OpenXRAPI::OpenXRAPI() { default: break; } + + submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer"); } // reset a few things that can't be done in our class definition frame_state.predictedDisplayTime = 0; frame_state.predictedDisplayPeriod = 0; - -#ifdef ANDROID_ENABLED - // our android wrapper will initialize our android loader at this point - register_extension_wrapper(memnew(OpenXRAndroidExtension(this))); -#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))); - register_extension_wrapper(memnew(OpenXRDisplayRefreshRateExtension(this))); } OpenXRAPI::~OpenXRAPI() { @@ -1882,12 +1978,6 @@ OpenXRAPI::~OpenXRAPI() { } composition_layer_providers.clear(); - // cleanup our extension wrappers - for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) { - memdelete(extension_wrapper); - } - registered_extension_wrappers.clear(); - if (supported_extensions != nullptr) { memfree(supported_extensions); supported_extensions = nullptr; @@ -2307,7 +2397,7 @@ 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)) { + if (!is_interaction_profile_supported(p_name)) { // The extension enabling this path must not be active, we will silently skip this interaction profile return RID(); } @@ -2348,14 +2438,13 @@ 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); + if (!interaction_profile_supports_io_path(ip->name, p_path)) { + return false; + } + XrActionSuggestedBinding binding; Action *action = action_owner.get_or_null(p_action); |