Merge pull request #90237 from dsnopek/openxr-composition-layers-extension-properties

Allow OpenXR extensions to add properties to the OpenXRCompositionLayer node
This commit is contained in:
Rémi Verschelde 2024-04-08 11:21:05 +02:00
commit 59cfa0ef75
No known key found for this signature in database
GPG key ID: C3336907360768E1
8 changed files with 161 additions and 6 deletions

View file

@ -46,6 +46,18 @@
Returns a [PackedStringArray] of positional tracker names that are used within the extension wrapper. Returns a [PackedStringArray] of positional tracker names that are used within the extension wrapper.
</description> </description>
</method> </method>
<method name="_get_viewport_composition_layer_extension_properties" qualifiers="virtual">
<return type="Dictionary[]" />
<description>
Gets an array of [Dictionary]s that represent properties, just like [method Object._get_property_list], that will be added to [OpenXRCompositionLayer] nodes.
</description>
</method>
<method name="_get_viewport_composition_layer_extension_property_defaults" qualifiers="virtual">
<return type="Dictionary" />
<description>
Gets a [Dictionary] containing the default values for the properties returned by [method _get_viewport_composition_layer_extension_properties].
</description>
</method>
<method name="_on_before_instance_created" qualifiers="virtual"> <method name="_on_before_instance_created" qualifiers="virtual">
<return type="void" /> <return type="void" />
<description> <description>
@ -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 the OpenXR session state is changed to visible. This means OpenXR is now ready to receive frames.
</description> </description>
</method> </method>
<method name="_on_viewport_composition_layer_destroyed" qualifiers="virtual">
<return type="void" />
<param index="0" name="layer" type="const void*" />
<description>
Called when a composition layer created via [OpenXRCompositionLayer] is destroyed.
[param layer] is a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct.
</description>
</method>
<method name="_set_hand_joint_locations_and_get_next_pointer" qualifiers="virtual"> <method name="_set_hand_joint_locations_and_get_next_pointer" qualifiers="virtual">
<return type="int" /> <return type="int" />
<param index="0" name="hand_index" type="int" /> <param index="0" name="hand_index" type="int" />
@ -188,6 +208,17 @@
Adds additional data structures when interogating OpenXR system abilities. Adds additional data structures when interogating OpenXR system abilities.
</description> </description>
</method> </method>
<method name="_set_viewport_composition_layer_and_get_next_pointer" qualifiers="virtual">
<return type="int" />
<param index="0" name="layer" type="const void*" />
<param index="1" name="property_values" type="Dictionary" />
<param index="2" name="next_pointer" type="void*" />
<description>
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.
</description>
</method>
<method name="get_openxr_api"> <method name="get_openxr_api">
<return type="OpenXRAPIExtension" /> <return type="OpenXRAPIExtension" />
<description> <description>

View file

@ -86,11 +86,11 @@ int OpenXRCompositionLayerExtension::get_composition_layer_order(int p_index) {
return composition_layers[p_index]->get_sort_order(); 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); 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); composition_layers.erase(p_composition_layer);
} }
@ -123,6 +123,10 @@ OpenXRViewportCompositionLayerProvider::OpenXRViewportCompositionLayerProvider(X
} }
OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider() { 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. // This will reset the viewport and free the swapchain too.
set_viewport(RID(), Size2i()); 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() { void OpenXRViewportCompositionLayerProvider::on_pre_render() {
RenderingServer *rs = RenderingServer::get_singleton(); RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs); ERR_FAIL_NULL(rs);
@ -233,6 +242,19 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
} break; } 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; return composition_layer;
} }

View file

@ -57,8 +57,8 @@ public:
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override; virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
virtual int get_composition_layer_order(int p_index) override; virtual int get_composition_layer_order(int p_index) override;
void register_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); void register_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer);
void unregister_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer); void unregister_viewport_composition_layer_provider(OpenXRViewportCompositionLayerProvider *p_composition_layer);
bool is_available(XrStructureType p_which); bool is_available(XrStructureType p_which);
@ -75,6 +75,8 @@ class OpenXRViewportCompositionLayerProvider {
XrCompositionLayerBaseHeader *composition_layer = nullptr; XrCompositionLayerBaseHeader *composition_layer = nullptr;
int sort_order = 1; int sort_order = 1;
bool alpha_blend = false; bool alpha_blend = false;
Dictionary extension_property_values;
bool extension_property_values_changed = true;
RID viewport; RID viewport;
Size2i viewport_size; Size2i viewport_size;
@ -102,6 +104,8 @@ public:
void set_viewport(RID p_viewport, Size2i p_size); void set_viewport(RID p_viewport, Size2i p_size);
RID get_viewport() const { return viewport; } RID get_viewport() const { return viewport; }
void set_extension_property_values(const Dictionary &p_property_values);
void on_pre_render(); void on_pre_render();
XrCompositionLayerBaseHeader *get_composition_layer(); XrCompositionLayerBaseHeader *get_composition_layer();

View file

@ -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_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 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<PropertyInfo> *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. // `on_event_polled` is called when there is an OpenXR event to process.
// Should return true if the event was handled, false otherwise. // Should return true if the event was handled, false otherwise.
virtual bool on_event_polled(const XrEventDataBuffer &event) { virtual bool on_event_polled(const XrEventDataBuffer &event) {

View file

@ -60,6 +60,10 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
GDVIRTUAL_BIND(_on_state_loss_pending); GDVIRTUAL_BIND(_on_state_loss_pending);
GDVIRTUAL_BIND(_on_state_exiting); GDVIRTUAL_BIND(_on_state_exiting);
GDVIRTUAL_BIND(_on_event_polled, "event"); 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("get_openxr_api"), &OpenXRExtensionWrapperExtension::get_openxr_api);
ClassDB::bind_method(D_METHOD("register_extension_wrapper"), &OpenXRExtensionWrapperExtension::register_extension_wrapper); 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; 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<void>(p_layer), p_property_values, GDExtensionPtr<void>(p_next_pointer), pointer)) {
return reinterpret_cast<void *>(pointer);
}
return p_next_pointer;
}
void OpenXRExtensionWrapperExtension::on_viewport_composition_layer_destroyed(const XrCompositionLayerBaseHeader *p_layer) {
GDVIRTUAL_CALL(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr<void>(p_layer));
}
void OpenXRExtensionWrapperExtension::get_viewport_composition_layer_extension_properties(List<PropertyInfo> *p_property_list) {
TypedArray<Dictionary> 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<OpenXRAPIExtension> OpenXRExtensionWrapperExtension::get_openxr_api() { Ref<OpenXRAPIExtension> OpenXRExtensionWrapperExtension::get_openxr_api() {
return openxr_api; return openxr_api;
} }

View file

@ -38,6 +38,7 @@
#include "core/os/os.h" #include "core/os/os.h"
#include "core/os/thread_safe.h" #include "core/os/thread_safe.h"
#include "core/variant/native_ptr.h" #include "core/variant/native_ptr.h"
#include "core/variant/typed_array.h"
class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider { class OpenXRExtensionWrapperExtension : public Object, public OpenXRExtensionWrapper, public OpenXRCompositionLayerProvider {
GDCLASS(OpenXRExtensionWrapperExtension, Object); 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_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_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_hand_joint_locations_and_get_next_pointer(int p_hand_index, void *p_next_pointer) override;
virtual int get_composition_layer_count() override; virtual int get_composition_layer_count() override;
virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override; virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) override;
virtual int get_composition_layer_order(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<void>); GDVIRTUAL1R(bool, _on_event_polled, GDExtensionConstPtr<void>);
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<PropertyInfo> *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<void>, Dictionary, GDExtensionPtr<void>);
GDVIRTUAL1(_on_viewport_composition_layer_destroyed, GDExtensionConstPtr<void>);
GDVIRTUAL0R(TypedArray<Dictionary>, _get_viewport_composition_layer_extension_properties);
GDVIRTUAL0R(Dictionary, _get_viewport_composition_layer_extension_property_defaults);
Ref<OpenXRAPIExtension> get_openxr_api(); Ref<OpenXRAPIExtension> get_openxr_api();
void register_extension_wrapper(); void register_extension_wrapper();

View file

@ -236,6 +236,14 @@ void OpenXRCompositionLayer::_reset_fallback_material() {
void OpenXRCompositionLayer::_notification(int p_what) { void OpenXRCompositionLayer::_notification(int p_what) {
switch (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: { case NOTIFICATION_INTERNAL_PROCESS: {
if (fallback) { if (fallback) {
if (should_update_fallback_mesh) { if (should_update_fallback_mesh) {
@ -260,7 +268,7 @@ void OpenXRCompositionLayer::_notification(int p_what) {
} break; } break;
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_ENTER_TREE: {
if (composition_layer_extension) { 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()) { if (!fallback && layer_viewport && openxr_api && openxr_api->is_running() && is_visible()) {
@ -269,7 +277,7 @@ void OpenXRCompositionLayer::_notification(int p_what) {
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
if (composition_layer_extension) { 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 // 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<PropertyInfo> *p_property_list) const {
List<PropertyInfo> 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 OpenXRCompositionLayer::get_configuration_warnings() const {
PackedStringArray warnings = Node3D::get_configuration_warnings(); PackedStringArray warnings = Node3D::get_configuration_warnings();

View file

@ -49,6 +49,8 @@ class OpenXRCompositionLayer : public Node3D {
MeshInstance3D *fallback = nullptr; MeshInstance3D *fallback = nullptr;
bool should_update_fallback_mesh = false; bool should_update_fallback_mesh = false;
Dictionary extension_property_values;
void _create_fallback_node(); void _create_fallback_node();
void _reset_fallback_material(); void _reset_fallback_material();
@ -60,6 +62,9 @@ protected:
static void _bind_methods(); static void _bind_methods();
void _notification(int p_what); void _notification(int p_what);
void _get_property_list(List<PropertyInfo> *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_begun();
virtual void _on_openxr_session_stopping(); virtual void _on_openxr_session_stopping();