From 7d6e6e99c5febc2abb359a543727a1a377481e96 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 --- doc/classes/XRInterface.xml | 2 + .../openxr/doc_classes/OpenXRAPIExtension.xml | 18 +++ .../OpenXRExtensionWrapperExtension.xml | 25 ++++ .../extensions/openxr_extension_wrapper.h | 5 + .../openxr_extension_wrapper_extension.cpp | 44 +++++++ .../openxr_extension_wrapper_extension.h | 8 ++ modules/openxr/openxr_api.cpp | 117 +++++++++++++++--- 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 + 13 files changed, 237 insertions(+), 17 deletions(-) diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml index 525525561d00..8d1fbfb963ed 100644 --- a/doc/classes/XRInterface.xml +++ b/doc/classes/XRInterface.xml @@ -263,6 +263,8 @@ 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]. + + 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 6492bb46f543..38f558db9154 100644 --- a/modules/openxr/doc_classes/OpenXRAPIExtension.xml +++ b/modules/openxr/doc_classes/OpenXRAPIExtension.xml @@ -230,6 +230,12 @@ Registers the given extension as a composition layer provider. + + + + + + @@ -237,6 +243,12 @@ Registers the given extension as a provider of additional data structures to projections views. + + + + + + @@ -295,6 +307,12 @@ Unregisters the given extension as a composition layer provider. + + + + + + diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml index cf6cd37c3084..f01807c9b61f 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml @@ -202,6 +202,18 @@ [param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties]. + + + + + + + + + + + + @@ -225,6 +237,13 @@ Adds additional data structures to the projection view of the given [param view_index]. + + + + + + + @@ -246,6 +265,12 @@ Adds additional data structures when querying OpenXR system abilities. + + + + + + diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 1033617ad80f..81f266729ded 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -63,6 +63,11 @@ class OpenXRExtensionWrapper { virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return 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) { return p_next_pointer; } virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) { return p_next_pointer; } + virtual void *set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer) { return 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) { return p_next_pointer; } // Add additional data structures when calling xrWaitFrame + virtual void *set_view_locate_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when calling xrLocateViews + virtual void *set_frame_end_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; } // Add additional data structures when calling xrEndFrame virtual PackedStringArray get_suggested_tracker_names() { return PackedStringArray(); } diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp index e6a4c2618c68..5c6e7f21cfb0 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp @@ -40,6 +40,10 @@ void OpenXRExtensionWrapperExtension::_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"); @@ -151,6 +155,46 @@ void *OpenXRExtensionWrapperExtension::set_projection_views_and_get_next_pointer return nullptr; } +void *OpenXRExtensionWrapperExtension::set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer) { + uint64_t pointer; + + 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 *OpenXRExtensionWrapperExtension::set_frame_wait_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer; + + if (GDVIRTUAL_CALL(_set_frame_wait_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + +void *OpenXRExtensionWrapperExtension::set_frame_end_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer; + + if (GDVIRTUAL_CALL(_set_frame_end_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + +void *OpenXRExtensionWrapperExtension::set_view_locate_info_and_get_next_pointer(void *p_next_pointer) { + uint64_t pointer; + + if (GDVIRTUAL_CALL(_set_view_locate_info_and_get_next_pointer, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return nullptr; +} + PackedStringArray OpenXRExtensionWrapperExtension::get_suggested_tracker_names() { PackedStringArray ret; diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h index f9b4c36fd780..58970ca8b80b 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h @@ -60,6 +60,10 @@ class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWra virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override; virtual void *set_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) override; virtual void *set_projection_views_and_get_next_pointer(int p_view_index, void *p_next_pointer) override; + virtual void *set_frame_wait_info_and_get_next_pointer(void *p_next_pointer) override; + virtual void *set_view_locate_info_and_get_next_pointer(void *p_next_pointer) override; + virtual void *set_frame_end_info_and_get_next_pointer(void *p_next_pointer) override; + virtual void *set_reference_space_create_info_and_get_next_pointer(int p_reference_space_type, void *p_next_pointer) override; virtual int get_composition_layer_count() override; virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override; @@ -72,6 +76,10 @@ class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWra 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 f432092576d7..3ebf96f7382e 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -924,7 +924,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."); @@ -982,21 +986,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. @@ -1029,9 +1046,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 }; @@ -1081,6 +1106,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), "]"); @@ -1478,12 +1514,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()); @@ -2111,7 +2156,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; @@ -2189,6 +2242,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" @@ -2202,7 +2263,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 @@ -2245,7 +2306,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; } @@ -2476,9 +2537,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 @@ -2689,6 +2758,12 @@ OpenXRAPI::~OpenXRAPI() { } composition_layer_providers.clear(); + // cleanup our frame info providers + for (OpenXRExtensionWrapper *provider : frame_info_extensions) { + memdelete(provider); + } + frame_info_extensions.clear(); + supported_extensions.clear(); layer_properties.clear(); @@ -3612,6 +3687,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 7c559f198139..1c2243cb5d4d 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -100,6 +100,9 @@ class OpenXRAPI { // projection views extensions Vector projection_views_extensions; + // frame info extensions + Vector frame_info_extensions; + // view configuration LocalVector supported_view_configuration_types; @@ -155,6 +158,7 @@ class OpenXRAPI { 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 @@ class OpenXRAPI { 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 @@ class OpenXRAPI { 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 f570dbeaae0f..32413ce542aa 100644 --- a/modules/openxr/openxr_api_extension.cpp +++ b/modules/openxr/openxr_api_extension.cpp @@ -51,6 +51,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"), &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); @@ -67,6 +68,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); @@ -180,6 +184,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(); @@ -240,6 +249,16 @@ void OpenXRAPIExtension::unregister_projection_views_extension(OpenXRExtensionWr OpenXRAPI::get_singleton()->unregister_projection_views_extension(p_extension); } +void OpenXRAPIExtension::register_frame_info_extension(OpenXRExtensionWrapperExtension *p_extension) { + ERR_FAIL_NULL(OpenXRAPI::get_singleton()); + OpenXRAPI::get_singleton()->register_frame_info_extension(p_extension); +} + +void OpenXRAPIExtension::unregister_frame_info_extension(OpenXRExtensionWrapperExtension *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 487baf38df2f..92d42c3585b0 100644 --- a/modules/openxr/openxr_api_extension.h +++ b/modules/openxr/openxr_api_extension.h @@ -71,6 +71,7 @@ class OpenXRAPIExtension : public RefCounted { 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(); @@ -87,6 +88,9 @@ class OpenXRAPIExtension : public RefCounted { void register_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension); void unregister_projection_views_extension(OpenXRExtensionWrapperExtension *p_extension); + void register_frame_info_extension(OpenXRExtensionWrapperExtension *p_extension); + void unregister_frame_info_extension(OpenXRExtensionWrapperExtension *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 7478cdc765e0..645e439d70de 100644 --- a/modules/openxr/openxr_interface.cpp +++ b/modules/openxr/openxr_interface.cpp @@ -730,6 +730,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 0f792d4f3a18..c3a4188a6c3d 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 38e442476414..d6ad0a03fbbe 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -77,6 +77,7 @@ class XRInterface : public RefCounted { 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 */ }; enum EnvironmentBlendMode {