From 3f27351f2b832e0760202e4c227585ea2bed9de8 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 27 Feb 2025 10:42:05 -0600 Subject: [PATCH] OpenXR: Support alternative reference spaces from extensions Co-authored-by: Fredia Huya-Kouadio --- doc/classes/XRInterface.xml | 3 + .../openxr/doc_classes/OpenXRAPIExtension.xml | 21 ++++ .../doc_classes/OpenXRExtensionWrapper.xml | 32 +++++ .../extensions/openxr_extension_wrapper.cpp | 44 +++++++ .../extensions/openxr_extension_wrapper.h | 9 ++ modules/openxr/openxr_api.cpp | 112 +++++++++++++++--- modules/openxr/openxr_api.h | 8 ++ modules/openxr/openxr_api_extension.cpp | 19 +++ modules/openxr/openxr_api_extension.h | 4 + modules/openxr/openxr_interface.cpp | 2 + servers/xr/xr_interface.cpp | 1 + servers/xr/xr_interface.h | 1 + 12 files changed, 239 insertions(+), 17 deletions(-) diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml index 525525561d0..13eb3c67e06 100644 --- a/doc/classes/XRInterface.xml +++ b/doc/classes/XRInterface.xml @@ -263,6 +263,9 @@ Same as [constant XR_PLAY_AREA_ROOMSCALE] but origin point is fixed to the center of the physical space. In this mode, system-level recentering may be disabled, requiring the use of [method XRServer.center_on_hmd]. + + Custom play area set by a GDExtension. + Opaque blend mode. This is typically used for VR devices. diff --git a/modules/openxr/doc_classes/OpenXRAPIExtension.xml b/modules/openxr/doc_classes/OpenXRAPIExtension.xml index a7820719d98..0980a3ca846 100644 --- a/modules/openxr/doc_classes/OpenXRAPIExtension.xml +++ b/modules/openxr/doc_classes/OpenXRAPIExtension.xml @@ -230,6 +230,13 @@ Registers the given extension as a composition layer provider. + + + + + Registers the given extension as modifying frame info via the [method OpenXRExtensionWrapper._set_frame_wait_info_and_get_next_pointer], [method OpenXRExtensionWrapper._set_view_locate_info_and_get_next_pointer], or [method OpenXRExtensionWrapper._set_frame_end_info_and_get_next_pointer] virtual methods. + + @@ -237,6 +244,13 @@ Registers the given extension as a provider of additional data structures to projections views. + + + + + Sets the reference space used by OpenXR to the given [url=https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrSpace.html]XrSpace[/url] (cast to a [code]void *[/code]). + + @@ -295,6 +309,13 @@ Unregisters the given extension as a composition layer provider. + + + + + Unregisters the given extension as modifying frame info. + + diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapper.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapper.xml index d0928a75b5c..b3106c1003e 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapper.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapper.xml @@ -202,6 +202,22 @@ [param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties]. + + + + + Adds additional data structures to [code]XrFrameEndInfo[/code]. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension]. + + + + + + + Adds additional data structures to [code]XrFrameWaitInfo[/code]. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension]. + + @@ -225,6 +241,14 @@ Adds additional data structures to the projection view of the given [param view_index]. + + + + + + Adds additional data structures to [code]XrReferenceSpaceCreateInfo[/code]. + + @@ -246,6 +270,14 @@ Adds additional data structures when querying OpenXR system abilities. + + + + + Adds additional data structures to [code]XrViewLocateInfo[/code]. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_frame_info_extension]. + + diff --git a/modules/openxr/extensions/openxr_extension_wrapper.cpp b/modules/openxr/extensions/openxr_extension_wrapper.cpp index fb1c795d4d6..72d3964de98 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper.cpp @@ -41,6 +41,10 @@ void OpenXRExtensionWrapper::_bind_methods() { GDVIRTUAL_BIND(_set_swapchain_create_info_and_get_next_pointer, "next_pointer"); GDVIRTUAL_BIND(_set_hand_joint_locations_and_get_next_pointer, "hand_index", "next_pointer"); GDVIRTUAL_BIND(_set_projection_views_and_get_next_pointer, "view_index", "next_pointer"); + GDVIRTUAL_BIND(_set_frame_wait_info_and_get_next_pointer, "next_pointer"); + GDVIRTUAL_BIND(_set_frame_end_info_and_get_next_pointer, "next_pointer"); + GDVIRTUAL_BIND(_set_view_locate_info_and_get_next_pointer, "next_pointer"); + GDVIRTUAL_BIND(_set_reference_space_create_info_and_get_next_pointer, "reference_space_type", "next_pointer"); GDVIRTUAL_BIND(_get_composition_layer_count); GDVIRTUAL_BIND(_get_composition_layer, "index"); GDVIRTUAL_BIND(_get_composition_layer_order, "index"); @@ -152,6 +156,46 @@ void *OpenXRExtensionWrapper::set_projection_views_and_get_next_pointer(int p_vi return nullptr; } +void *OpenXRExtensionWrapper::set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_reference_space_create_info_and_get_next_pointer, p_reference_space_type, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + +void *OpenXRExtensionWrapper::set_frame_wait_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_frame_wait_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + +void *OpenXRExtensionWrapper::set_frame_end_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_frame_end_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + +void *OpenXRExtensionWrapper::set_view_locate_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_view_locate_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + PackedStringArray OpenXRExtensionWrapper::get_suggested_tracker_names() { PackedStringArray ret; diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 216ed7bca90..0119c89c430 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -77,6 +77,11 @@ public: virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when creating OpenXR swap chains. virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer); virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer); + virtual void *set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer); + // These will only be called for extensions registered via OpenXRApi::register_frame_info_extension(). + virtual void *set_frame_wait_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrWaitFrame + virtual void *set_view_locate_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrLocateViews + virtual void *set_frame_end_info_and_get_next_pointer(void *p_next_pointer); // Add additional data structures when calling xrEndFrame //TODO workaround as GDExtensionPtr return type results in build error in godot-cpp GDVIRTUAL1R(uint64_t, _set_system_properties_and_get_next_pointer, GDExtensionPtr); @@ -85,6 +90,10 @@ public: GDVIRTUAL1R(uint64_t, _set_swapchain_create_info_and_get_next_pointer, GDExtensionPtr); GDVIRTUAL2R(uint64_t, _set_hand_joint_locations_and_get_next_pointer, int, GDExtensionPtr); GDVIRTUAL2R(uint64_t, _set_projection_views_and_get_next_pointer, int, GDExtensionPtr); + GDVIRTUAL1R(uint64_t, _set_frame_wait_info_and_get_next_pointer, GDExtensionPtr); + GDVIRTUAL1R(uint64_t, _set_frame_end_info_and_get_next_pointer, GDExtensionPtr); + GDVIRTUAL1R(uint64_t, _set_view_locate_info_and_get_next_pointer, GDExtensionPtr); + GDVIRTUAL2R(uint64_t, _set_reference_space_create_info_and_get_next_pointer, int, GDExtensionPtr); GDVIRTUAL0R(int, _get_composition_layer_count); GDVIRTUAL1R(uint64_t, _get_composition_layer, int); GDVIRTUAL1R(int, _get_composition_layer_order, int); diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 78059537d6b..c7314864641 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -927,7 +927,11 @@ bool OpenXRAPI::setup_play_space() { XrSpace new_play_space = XR_NULL_HANDLE; bool will_emulate_local_floor = false; - if (is_reference_space_supported(requested_reference_space)) { + if (custom_play_space != XR_NULL_HANDLE) { + new_play_space = custom_play_space; + // We use this to mark custom reference spaces. + new_reference_space = XR_REFERENCE_SPACE_TYPE_MAX_ENUM; + } else if (is_reference_space_supported(requested_reference_space)) { new_reference_space = requested_reference_space; } else if (requested_reference_space == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT && is_reference_space_supported(XR_REFERENCE_SPACE_TYPE_STAGE)) { print_verbose("OpenXR: LOCAL_FLOOR space isn't supported, emulating using STAGE and LOCAL spaces."); @@ -985,21 +989,34 @@ bool OpenXRAPI::setup_play_space() { new_reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL; } - XrReferenceSpaceCreateInfo play_space_create_info = { - XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type - nullptr, // next - new_reference_space, // referenceSpaceType - identityPose, // poseInReferenceSpace - }; + if (new_play_space == XR_NULL_HANDLE) { + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_reference_space_create_info_and_get_next_pointer( + new_reference_space, next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } - XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space); - if (XR_FAILED(result)) { - print_line("OpenXR: Failed to create play space [", get_error_string(result), "]"); - return false; + XrReferenceSpaceCreateInfo play_space_create_info = { + XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type + next_pointer, // next + new_reference_space, // referenceSpaceType + identityPose, // poseInReferenceSpace + }; + + XrResult result = xrCreateReferenceSpace(session, &play_space_create_info, &new_play_space); + if (XR_FAILED(result)) { + print_line("OpenXR: Failed to create play space [", get_error_string(result), "]"); + return false; + } } // If we've previously created a play space, clean it up first. - if (play_space != XR_NULL_HANDLE) { + // But if it was a custom reference space, we don't touch it - it's the job of the extension that + // created it to clean it up. + if (play_space != XR_NULL_HANDLE && reference_space != XR_REFERENCE_SPACE_TYPE_MAX_ENUM) { // TODO Investigate if destroying our play space here is safe, // it may still be used in the rendering thread. @@ -1032,9 +1049,17 @@ bool OpenXRAPI::setup_view_space() { { 0.0, 0.0, 0.0 } }; + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_reference_space_create_info_and_get_next_pointer(XR_REFERENCE_SPACE_TYPE_VIEW, next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + XrReferenceSpaceCreateInfo view_space_create_info = { XR_TYPE_REFERENCE_SPACE_CREATE_INFO, // type - nullptr, // next + next_pointer, // next XR_REFERENCE_SPACE_TYPE_VIEW, // referenceSpaceType identityPose // poseInReferenceSpace }; @@ -1084,6 +1109,17 @@ bool OpenXRAPI::reset_emulated_floor_height() { }; XrSpace new_play_space; + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + void *np = wrapper->set_reference_space_create_info_and_get_next_pointer( + create_info.referenceSpaceType, next_pointer); + if (np != nullptr) { + next_pointer = np; + } + } + create_info.next = next_pointer; + result = xrCreateReferenceSpace(session, &create_info, &new_play_space); if (XR_FAILED(result)) { print_line("OpenXR: Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate [", get_error_string(result), "]"); @@ -1481,12 +1517,21 @@ void OpenXRAPI::set_view_configuration(XrViewConfigurationType p_view_configurat } bool OpenXRAPI::set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space) { + if (custom_play_space != XR_NULL_HANDLE) { + return false; + } + requested_reference_space = p_requested_reference_space; play_space_is_dirty = true; return true; } +void OpenXRAPI::set_custom_play_space(XrSpace p_custom_space) { + custom_play_space = p_custom_space; + play_space_is_dirty = true; +} + void OpenXRAPI::set_submit_depth_buffer(bool p_submit_depth_buffer) { ERR_FAIL_COND(is_initialized()); @@ -2117,7 +2162,15 @@ bool OpenXRAPI::process() { // As the name suggests, OpenXR can pause the thread to minimize the time between // retrieving tracking data and using that tracking data to render. // OpenXR thus works best if rendering is performed on a separate thread. - XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, nullptr }; + void *frame_wait_info_next_pointer = nullptr; + for (OpenXRExtensionWrapper *extension : frame_info_extensions) { + void *np = extension->set_frame_wait_info_and_get_next_pointer(frame_wait_info_next_pointer); + if (np != nullptr) { + frame_wait_info_next_pointer = np; + } + } + + XrFrameWaitInfo frame_wait_info = { XR_TYPE_FRAME_WAIT_INFO, frame_wait_info_next_pointer }; frame_state.predictedDisplayTime = 0; frame_state.predictedDisplayPeriod = 0; frame_state.shouldRender = false; @@ -2195,6 +2248,14 @@ void OpenXRAPI::pre_render() { wrapper->on_pre_render(); } + void *view_locate_info_next_pointer = nullptr; + for (OpenXRExtensionWrapper *extension : frame_info_extensions) { + void *np = extension->set_view_locate_info_and_get_next_pointer(view_locate_info_next_pointer); + if (np != nullptr) { + view_locate_info_next_pointer = np; + } + } + // Get our view info for the frame we're about to render, note from the OpenXR manual: // "Repeatedly calling xrLocateViews with the same time may not necessarily return the same result. Instead the prediction gets increasingly accurate as the function is called closer to the given time for which a prediction is made" @@ -2208,7 +2269,7 @@ void OpenXRAPI::pre_render() { XrViewLocateInfo view_locate_info = { XR_TYPE_VIEW_LOCATE_INFO, // type - nullptr, // next + view_locate_info_next_pointer, // next view_configuration, // viewConfigurationType render_state.predicted_display_time, // displayTime render_state.play_space // space @@ -2251,7 +2312,7 @@ void OpenXRAPI::pre_render() { }; result = xrBeginFrame(session, &frame_begin_info); if (XR_FAILED(result)) { - print_line("OpenXR: failed to being frame [", get_error_string(result), "]"); + print_line("OpenXR: failed to begin frame [", get_error_string(result), "]"); return; } @@ -2482,9 +2543,17 @@ void OpenXRAPI::end_frame() { layers_list.push_back(ordered_layer.composition_layer); } + void *frame_end_info_next_pointer = nullptr; + for (OpenXRExtensionWrapper *extension : frame_info_extensions) { + void *np = extension->set_frame_end_info_and_get_next_pointer(frame_end_info_next_pointer); + if (np != nullptr) { + frame_end_info_next_pointer = np; + } + } + XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type - nullptr, // next + frame_end_info_next_pointer, // next render_state.predicted_display_time, // displayTime environment_blend_mode, // environmentBlendMode static_cast(layers_list.size()), // layerCount @@ -2690,6 +2759,7 @@ OpenXRAPI::OpenXRAPI() { OpenXRAPI::~OpenXRAPI() { composition_layer_providers.clear(); + frame_info_extensions.clear(); supported_extensions.clear(); layer_properties.clear(); @@ -3611,6 +3681,14 @@ void OpenXRAPI::unregister_projection_views_extension(OpenXRExtensionWrapper *p_ projection_views_extensions.erase(p_extension); } +void OpenXRAPI::register_frame_info_extension(OpenXRExtensionWrapper *p_extension) { + frame_info_extensions.append(p_extension); +} + +void OpenXRAPI::unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension) { + frame_info_extensions.erase(p_extension); +} + const Vector OpenXRAPI::get_supported_environment_blend_modes() { return supported_environment_blend_modes; } diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 675a6356f79..05ac215153a 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -98,6 +98,9 @@ private: // projection views extensions Vector projection_views_extensions; + // frame info extensions + Vector frame_info_extensions; + // view configuration LocalVector supported_view_configuration_types; @@ -153,6 +156,7 @@ private: bool play_space_is_dirty = true; XrSpace play_space = XR_NULL_HANDLE; + XrSpace custom_play_space = XR_NULL_HANDLE; XrSpace view_space = XR_NULL_HANDLE; XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE; @@ -465,6 +469,7 @@ public: bool set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space); XrReferenceSpaceType get_requested_reference_space() const { return requested_reference_space; } XrReferenceSpaceType get_reference_space() const { return reference_space; } + void set_custom_play_space(XrSpace p_custom_space); void set_submit_depth_buffer(bool p_submit_depth_buffer); bool get_submit_depth_buffer() const { return submit_depth_buffer; } @@ -582,6 +587,9 @@ public: void register_projection_views_extension(OpenXRExtensionWrapper *p_extension); void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension); + void register_frame_info_extension(OpenXRExtensionWrapper *p_extension); + void unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension); + const Vector get_supported_environment_blend_modes(); bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const; bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode); diff --git a/modules/openxr/openxr_api_extension.cpp b/modules/openxr/openxr_api_extension.cpp index 44c36fefb82..1824aef6d7b 100644 --- a/modules/openxr/openxr_api_extension.cpp +++ b/modules/openxr/openxr_api_extension.cpp @@ -52,6 +52,7 @@ void OpenXRAPIExtension::_bind_methods() { ClassDB::bind_method(D_METHOD("is_initialized"), &OpenXRAPIExtension::is_initialized); ClassDB::bind_method(D_METHOD("is_running"), &OpenXRAPIExtension::is_running); + ClassDB::bind_method(D_METHOD("set_custom_play_space", "space"), &OpenXRAPIExtension::set_custom_play_space); ClassDB::bind_method(D_METHOD("get_play_space"), &OpenXRAPIExtension::get_play_space); ClassDB::bind_method(D_METHOD("get_predicted_display_time"), &OpenXRAPIExtension::get_predicted_display_time); ClassDB::bind_method(D_METHOD("get_next_frame_time"), &OpenXRAPIExtension::get_next_frame_time); @@ -68,6 +69,9 @@ void OpenXRAPIExtension::_bind_methods() { ClassDB::bind_method(D_METHOD("register_projection_views_extension", "extension"), &OpenXRAPIExtension::register_projection_views_extension); ClassDB::bind_method(D_METHOD("unregister_projection_views_extension", "extension"), &OpenXRAPIExtension::unregister_projection_views_extension); + ClassDB::bind_method(D_METHOD("register_frame_info_extension", "extension"), &OpenXRAPIExtension::register_frame_info_extension); + ClassDB::bind_method(D_METHOD("unregister_frame_info_extension", "extension"), &OpenXRAPIExtension::unregister_frame_info_extension); + ClassDB::bind_method(D_METHOD("get_render_state_z_near"), &OpenXRAPIExtension::get_render_state_z_near); ClassDB::bind_method(D_METHOD("get_render_state_z_far"), &OpenXRAPIExtension::get_render_state_z_far); @@ -181,6 +185,11 @@ bool OpenXRAPIExtension::is_running() { return OpenXRAPI::get_singleton()->is_running(); } +void OpenXRAPIExtension::set_custom_play_space(GDExtensionConstPtr p_custom_space) { + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + OpenXRAPI::get_singleton()->set_custom_play_space(*(XrSpace *)p_custom_space.data); +} + uint64_t OpenXRAPIExtension::get_play_space() { ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0); return (uint64_t)OpenXRAPI::get_singleton()->get_play_space(); @@ -241,6 +250,16 @@ void OpenXRAPIExtension::unregister_projection_views_extension(OpenXRExtensionWr OpenXRAPI::get_singleton()->unregister_projection_views_extension(p_extension); } +void OpenXRAPIExtension::register_frame_info_extension(OpenXRExtensionWrapper *p_extension) { + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + OpenXRAPI::get_singleton()->register_frame_info_extension(p_extension); +} + +void OpenXRAPIExtension::unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension) { + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + OpenXRAPI::get_singleton()->unregister_frame_info_extension(p_extension); +} + double OpenXRAPIExtension::get_render_state_z_near() { ERR_NOT_ON_RENDER_THREAD_V(0.0); ERR_FAIL_NULL_V(OpenXRAPI::get_singleton(), 0.0); diff --git a/modules/openxr/openxr_api_extension.h b/modules/openxr/openxr_api_extension.h index 61eaf559592..85d03447ba4 100644 --- a/modules/openxr/openxr_api_extension.h +++ b/modules/openxr/openxr_api_extension.h @@ -79,6 +79,7 @@ public: bool is_initialized(); bool is_running(); + void set_custom_play_space(GDExtensionConstPtr p_custom_space); uint64_t get_play_space(); int64_t get_predicted_display_time(); int64_t get_next_frame_time(); @@ -95,6 +96,9 @@ public: void register_projection_views_extension(OpenXRExtensionWrapper *p_extension); void unregister_projection_views_extension(OpenXRExtensionWrapper *p_extension); + void register_frame_info_extension(OpenXRExtensionWrapper *p_extension); + void unregister_frame_info_extension(OpenXRExtensionWrapper *p_extension); + double get_render_state_z_near(); double get_render_state_z_far(); diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp index 9f92cb858ae..0e9e4f41fc6 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -753,6 +753,8 @@ XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const { return XRInterface::XR_PLAY_AREA_ROOMSCALE; } else if (reference_space == XR_REFERENCE_SPACE_TYPE_STAGE) { return XRInterface::XR_PLAY_AREA_STAGE; + } else if (reference_space == XR_REFERENCE_SPACE_TYPE_MAX_ENUM) { + return XRInterface::XR_PLAY_AREA_CUSTOM; } return XRInterface::XR_PLAY_AREA_UNKNOWN; diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 0f792d4f3a1..c3a4188a6c3 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -103,6 +103,7 @@ void XRInterface::_bind_methods() { BIND_ENUM_CONSTANT(XR_PLAY_AREA_SITTING); BIND_ENUM_CONSTANT(XR_PLAY_AREA_ROOMSCALE); BIND_ENUM_CONSTANT(XR_PLAY_AREA_STAGE); + BIND_ENUM_CONSTANT(XR_PLAY_AREA_CUSTOM); BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_OPAQUE); BIND_ENUM_CONSTANT(XR_ENV_BLEND_MODE_ADDITIVE); diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 398d0cb69f4..b669f6ebcfd 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -76,6 +76,7 @@ public: XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */ XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */ XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space */ + XR_PLAY_AREA_CUSTOM = 0x7FFFFFFF, /* Used to denote that a custom, possibly non-standard, play area is being used */ }; enum EnvironmentBlendMode {