From fddf6dc65157fe08bdda20809a105950f885a095 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 4 Apr 2024 15:04:07 -0500 Subject: [PATCH] Allow OpenXR extensions to add properties to the OpenXRCompositionLayer node --- .../OpenXRExtensionWrapperExtension.xml | 31 +++++++++++++ .../openxr_composition_layer_extension.cpp | 26 ++++++++++- .../openxr_composition_layer_extension.h | 8 +++- .../extensions/openxr_extension_wrapper.h | 5 ++ .../openxr_extension_wrapper_extension.cpp | 34 ++++++++++++++ .../openxr_extension_wrapper_extension.h | 12 +++++ .../openxr/scene/openxr_composition_layer.cpp | 46 ++++++++++++++++++- .../openxr/scene/openxr_composition_layer.h | 5 ++ 8 files changed, 161 insertions(+), 6 deletions(-) diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml index 9d6b197ee13..79aa547c526 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml @@ -46,6 +46,18 @@ Returns a [PackedStringArray] of positional tracker names that are used within the extension wrapper. + + + + Gets an array of [Dictionary]s that represent properties, just like [method Object._get_property_list], that will be added to [OpenXRCompositionLayer] nodes. + + + + + + Gets a [Dictionary] containing the default values for the properties returned by [method _get_viewport_composition_layer_extension_properties]. + + @@ -152,6 +164,14 @@ Called when the OpenXR session state is changed to visible. This means OpenXR is now ready to receive frames. + + + + + Called when a composition layer created via [OpenXRCompositionLayer] is destroyed. + [param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct. + + @@ -188,6 +208,17 @@ Adds additional data structures when interogating OpenXR system abilities. + + + + + + + Adds additional data structures to composition layers created by [OpenXRCompositionLayer]. + [param property_values] contains the values of the properties returned by [method _get_viewport_composition_layer_extension_properties]. + [param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct. + + diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp index 7c0c69d747d..cb117d7bb7a 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp @@ -86,11 +86,11 @@ int OpenXRCompositionLayerExtension::get_composition_layer_order(int p_index) { return composition_layers[p_index]->get_sort_order(); } -void OpenXRCompositionLayerExtension::register_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) { +void OpenXRCompositionLayerExtension::register_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) { composition_layers.push_back(p_composition_layer); } -void OpenXRCompositionLayerExtension::unregister_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) { +void OpenXRCompositionLayerExtension::unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer) { composition_layers.erase(p_composition_layer); } @@ -123,6 +123,10 @@ OpenXRViewportCompositionLayerProvider::OpenXRViewportCompositionLayerProvider(X } OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider() { + for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { + extension->on_viewport_composition_layer_destroyed(composition_layer); + } + // This will reset the viewport and free the swapchain too. set_viewport(RID(), Size2i()); } @@ -159,6 +163,11 @@ void OpenXRViewportCompositionLayerProvider::set_viewport(RID p_viewport, Size2i } } +void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const Dictionary &p_extension_property_values) { + extension_property_values = p_extension_property_values; + extension_property_values_changed = true; +} + void OpenXRViewportCompositionLayerProvider::on_pre_render() { RenderingServer *rs = RenderingServer::get_singleton(); ERR_FAIL_NULL(rs); @@ -233,6 +242,19 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos } break; } + if (extension_property_values_changed) { + extension_property_values_changed = false; + + void *next_pointer = nullptr; + for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { + void *np = extension->set_viewport_composition_layer_and_get_next_pointer(composition_layer, extension_property_values, next_pointer); + if (np) { + next_pointer = np; + } + } + composition_layer->next = next_pointer; + } + return composition_layer; } diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.h b/modules/openxr/extensions/openxr_composition_layer_extension.h index 7cc35005f84..4fefc416e61 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.h +++ b/modules/openxr/extensions/openxr_composition_layer_extension.h @@ -57,8 +57,8 @@ public: virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override; virtual int get_composition_layer_order(int p_index) override; - void register_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); - void unregister_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); + void register_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); + void unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); bool is_available(XrStructureType p_which); @@ -75,6 +75,8 @@ class OpenXRViewportCompositionLayerProvider { XrCompositionLayerBaseHeader *composition_layer = nullptr; int sort_order = 1; bool alpha_blend = false; + Dictionary extension_property_values; + bool extension_property_values_changed = true; RID viewport; Size2i viewport_size; @@ -102,6 +104,8 @@ public: void set_viewport(RID p_viewport, Size2i p_size); RID get_viewport() const { return viewport; } + void set_extension_property_values(const Dictionary &p_property_values); + void on_pre_render(); XrCompositionLayerBaseHeader *get_composition_layer(); diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index ad326472ab1..ce03df0b30d 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -96,6 +96,11 @@ public: virtual void on_state_loss_pending() {} // `on_state_loss_pending` is called when the OpenXR session state is changed to loss pending. virtual void on_state_exiting() {} // `on_state_exiting` is called when the OpenXR session state is changed to exiting. + virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) { return p_next_pointer; } // Add additional data structures to composition layers created via OpenXRCompositionLayer. + virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) {} // `on_viewport_composition_layer_destroyed` is called when a composition layer created via OpenXRCompositionLayer is destroyed. + virtual void get_viewport_composition_layer_extension_properties(List *p_property_list) {} // Get additional property definitions for OpenXRCompositionLayer. + virtual Dictionary get_viewport_composition_layer_extension_property_defaults() { return Dictionary(); } // Get the default values for the additional property definitions for OpenXRCompositionLayer. + // `on_event_polled` is called when there is an OpenXR event to process. // Should return true if the event was handled, false otherwise. virtual bool on_event_polled(const XrEventDataBuffer &event) { diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp index 60a934e3a81..0cb039bec42 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp @@ -60,6 +60,10 @@ void OpenXRExtensionWrapperExtension::_bind_methods() { GDVIRTUAL_BIND(_on_state_loss_pending); GDVIRTUAL_BIND(_on_state_exiting); GDVIRTUAL_BIND(_on_event_polled, "event"); + GDVIRTUAL_BIND(_set_viewport_composition_layer_and_get_next_pointer, "layer", "property_values", "next_pointer"); + GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_properties, "layer"); + GDVIRTUAL_BIND(_get_viewport_composition_layer_extension_property_defaults, "layer"); + GDVIRTUAL_BIND(_on_viewport_composition_layer_destroyed, "layer"); ClassDB::bind_method(D_METHOD("get_openxr_api"), &OpenXRExtensionWrapperExtension::get_openxr_api); ClassDB::bind_method(D_METHOD("register_extension_wrapper"), &OpenXRExtensionWrapperExtension::register_extension_wrapper); @@ -240,6 +244,36 @@ bool OpenXRExtensionWrapperExtension::on_event_polled(const XrEventDataBuffer &p return false; } +void *OpenXRExtensionWrapperExtension::set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) { + uint64_t pointer = 0; + + if (GDVIRTUAL_CALL(_set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr(p_layer), p_property_values, GDExtensionPtr(p_next_pointer), pointer)) { + return reinterpret_cast(pointer); + } + + return p_next_pointer; +} + +void OpenXRExtensionWrapperExtension::on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) { + GDVIRTUAL_CALL(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr(p_layer)); +} + +void OpenXRExtensionWrapperExtension::get_viewport_composition_layer_extension_properties(List *p_property_list) { + TypedArray properties; + + if (GDVIRTUAL_CALL(_get_viewport_composition_layer_extension_properties, properties)) { + for (int i = 0; i < properties.size(); i++) { + p_property_list->push_back(PropertyInfo::from_dict(properties[i])); + } + } +} + +Dictionary OpenXRExtensionWrapperExtension::get_viewport_composition_layer_extension_property_defaults() { + Dictionary property_defaults; + GDVIRTUAL_CALL(_get_viewport_composition_layer_extension_property_defaults, property_defaults); + return property_defaults; +} + Ref OpenXRExtensionWrapperExtension::get_openxr_api() { return openxr_api; } diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h index d3b78bf6170..71d2a57ff89 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h @@ -38,6 +38,7 @@ #include "core/os/os.h" #include "core/os/thread_safe.h" #include "core/variant/native_ptr.h" +#include "core/variant/typed_array.h" class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider { GDCLASS(OpenXRExtensionWrapperExtension, Object); @@ -59,6 +60,7 @@ public: virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override; 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 int get_composition_layer_count() override; virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override; virtual int get_composition_layer_order(int p_index) override; @@ -117,6 +119,16 @@ public: GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr); + virtual void *set_viewport_composition_layer_and_get_next_pointer(const XrCompositionLayerBaseHeader *p_layer, Dictionary p_property_values, void *p_next_pointer) override; + virtual void on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) override; + virtual void get_viewport_composition_layer_extension_properties(List *p_property_list) override; + virtual Dictionary get_viewport_composition_layer_extension_property_defaults() override; + + GDVIRTUAL3R(uint64_t, _set_viewport_composition_layer_and_get_next_pointer, GDExtensionConstPtr, Dictionary, GDExtensionPtr); + GDVIRTUAL1(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr); + GDVIRTUAL0R(TypedArray, _get_viewport_composition_layer_extension_properties); + GDVIRTUAL0R(Dictionary, _get_viewport_composition_layer_extension_property_defaults); + Ref get_openxr_api(); void register_extension_wrapper(); diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp index 120914485f2..e0d0ddc77fb 100644 --- a/modules/openxr/scene/openxr_composition_layer.cpp +++ b/modules/openxr/scene/openxr_composition_layer.cpp @@ -236,6 +236,14 @@ void OpenXRCompositionLayer::_reset_fallback_material() { void OpenXRCompositionLayer::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + if (openxr_layer_provider) { + for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { + extension_property_values.merge(extension->get_viewport_composition_layer_extension_property_defaults()); + } + openxr_layer_provider->set_extension_property_values(extension_property_values); + } + } break; case NOTIFICATION_INTERNAL_PROCESS: { if (fallback) { if (should_update_fallback_mesh) { @@ -260,7 +268,7 @@ void OpenXRCompositionLayer::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { if (composition_layer_extension) { - composition_layer_extension->register_composition_layer_provider(openxr_layer_provider); + composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider); } if (!fallback && layer_viewport && openxr_api && openxr_api->is_running() && is_visible()) { @@ -269,7 +277,7 @@ void OpenXRCompositionLayer::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (composition_layer_extension) { - composition_layer_extension->unregister_composition_layer_provider(openxr_layer_provider); + composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider); } // When a node is removed in the editor, we need to clear the layer viewport, because otherwise @@ -285,6 +293,40 @@ void OpenXRCompositionLayer::_notification(int p_what) { } } +void OpenXRCompositionLayer::_get_property_list(List *p_property_list) const { + List extension_properties; + for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) { + extension->get_viewport_composition_layer_extension_properties(&extension_properties); + } + + for (const PropertyInfo &pinfo : extension_properties) { + StringName prop_name = pinfo.name; + if (!String(prop_name).contains("/")) { + WARN_PRINT_ONCE(vformat("Discarding OpenXRCompositionLayer property name '%s' from extension because it doesn't contain a '/'.")); + continue; + } + p_property_list->push_back(pinfo); + } +} + +bool OpenXRCompositionLayer::_get(const StringName &p_property, Variant &r_value) const { + if (extension_property_values.has(p_property)) { + r_value = extension_property_values[p_property]; + } + + return true; +} + +bool OpenXRCompositionLayer::_set(const StringName &p_property, const Variant &p_value) { + extension_property_values[p_property] = p_value; + + if (openxr_layer_provider) { + openxr_layer_provider->set_extension_property_values(extension_property_values); + } + + return true; +} + PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const { PackedStringArray warnings = Node3D::get_configuration_warnings(); diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h index f683aea647d..dbc09d19b10 100644 --- a/modules/openxr/scene/openxr_composition_layer.h +++ b/modules/openxr/scene/openxr_composition_layer.h @@ -49,6 +49,8 @@ class OpenXRCompositionLayer : public Node3D { MeshInstance3D *fallback = nullptr; bool should_update_fallback_mesh = false; + Dictionary extension_property_values; + void _create_fallback_node(); void _reset_fallback_material(); @@ -60,6 +62,9 @@ protected: static void _bind_methods(); void _notification(int p_what); + void _get_property_list(List *p_property_list) const; + bool _get(const StringName &p_property, Variant &r_value) const; + bool _set(const StringName &p_property, const Variant &p_value); virtual void _on_openxr_session_begun(); virtual void _on_openxr_session_stopping();