Allow OpenXR extensions to add properties to the OpenXRCompositionLayer node

This commit is contained in:
David Snopek 2024-04-04 15:04:07 -05:00
parent f6a78f83aa
commit fddf6dc651
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.
</description>
</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">
<return type="void" />
<description>
@ -152,6 +164,14 @@
Called when the OpenXR session state is changed to visible. This means OpenXR is now ready to receive frames.
</description>
</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">
<return type="int" />
<param index="0" name="hand_index" type="int" />
@ -188,6 +208,17 @@
Adds additional data structures when interogating OpenXR system abilities.
</description>
</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">
<return type="OpenXRAPIExtension" />
<description>

View file

@ -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;
}

View file

@ -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();

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_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.
// Should return true if the event was handled, false otherwise.
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_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<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() {
return openxr_api;
}

View file

@ -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<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();
void register_extension_wrapper();

View file

@ -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<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 warnings = Node3D::get_configuration_warnings();

View file

@ -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<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_stopping();