From 308a6a4734f38f79ac505e41e6f61c51df111748 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Tue, 9 May 2023 23:29:13 +1000 Subject: [PATCH] OpenXR: Allow GDExtensions to provide multiple, ordered composition layers Co-authored-by: Bastiaan Olij --- .../OpenXRExtensionWrapperExtension.xml | 19 ++++++++++- ...enxr_composition_layer_depth_extension.cpp | 11 +++++-- ...openxr_composition_layer_depth_extension.h | 4 ++- .../openxr_composition_layer_provider.h | 4 ++- .../openxr_extension_wrapper_extension.cpp | 20 ++++++++++-- .../openxr_extension_wrapper_extension.h | 8 +++-- modules/openxr/openxr_api.cpp | 32 +++++++++++++++---- modules/openxr/openxr_api.h | 9 ++++++ 8 files changed, 91 insertions(+), 16 deletions(-) diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml index 20ce1c42bf0..9d6b197ee13 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml @@ -11,8 +11,25 @@ + - Returns a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct to provide a composition layer. This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider]. + Returns a pointer to an [code]XrCompositionLayerBaseHeader[/code] struct to provide the given composition layer. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider]. + + + + + + Returns the number of composition layers this extension wrapper provides via [method _get_composition_layer]. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider]. + + + + + + + Returns an integer that will be used to sort the given composition layer provided via [method _get_composition_layer]. Lower numbers will move the layer to the front of the list, and higher numbers to the end. The default projection layer has an order of [code]0[/code], so layers provided by this method should probably be above or below (but not exactly) [code]0[/code]. + This will only be called if the extension previously registered itself with [method OpenXRAPIExtension.register_composition_layer_provider]. diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp index 7a16da144ef..b3c94d44f07 100644 --- a/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.cpp @@ -56,8 +56,15 @@ bool OpenXRCompositionLayerDepthExtension::is_available() { return available; } -XrCompositionLayerBaseHeader *OpenXRCompositionLayerDepthExtension::get_composition_layer() { - // Seems this is all done in our base layer... Just in case this changes... +int OpenXRCompositionLayerDepthExtension::get_composition_layer_count() { + return 0; +} +XrCompositionLayerBaseHeader *OpenXRCompositionLayerDepthExtension::get_composition_layer(int p_index) { + // Seems this is all done in our base layer... Just in case this changes... return nullptr; } + +int OpenXRCompositionLayerDepthExtension::get_composition_layer_order(int p_index) { + return 0; +} diff --git a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h index 50bbef4db48..1fda8844aff 100644 --- a/modules/openxr/extensions/openxr_composition_layer_depth_extension.h +++ b/modules/openxr/extensions/openxr_composition_layer_depth_extension.h @@ -43,7 +43,9 @@ public: virtual HashMap get_requested_extensions() override; bool is_available(); - virtual XrCompositionLayerBaseHeader *get_composition_layer() 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; private: static OpenXRCompositionLayerDepthExtension *singleton; diff --git a/modules/openxr/extensions/openxr_composition_layer_provider.h b/modules/openxr/extensions/openxr_composition_layer_provider.h index d77ae061742..44f90a0e0ec 100644 --- a/modules/openxr/extensions/openxr_composition_layer_provider.h +++ b/modules/openxr/extensions/openxr_composition_layer_provider.h @@ -38,7 +38,9 @@ // Interface for OpenXR extensions that provide a composition layer. class OpenXRCompositionLayerProvider { public: - virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0; + virtual int get_composition_layer_count() = 0; + virtual XrCompositionLayerBaseHeader *get_composition_layer(int p_index) = 0; + virtual int get_composition_layer_order(int p_index) = 0; virtual ~OpenXRCompositionLayerProvider() {} }; diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp index a9b62819b78..60a934e3a81 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp @@ -39,7 +39,9 @@ void OpenXRExtensionWrapperExtension::_bind_methods() { GDVIRTUAL_BIND(_set_session_create_and_get_next_pointer, "next_pointer"); 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(_get_composition_layer); + GDVIRTUAL_BIND(_get_composition_layer_count); + GDVIRTUAL_BIND(_get_composition_layer, "index"); + GDVIRTUAL_BIND(_get_composition_layer_order, "index"); GDVIRTUAL_BIND(_get_suggested_tracker_names); GDVIRTUAL_BIND(_on_register_metadata); GDVIRTUAL_BIND(_on_before_instance_created); @@ -140,16 +142,28 @@ PackedStringArray OpenXRExtensionWrapperExtension::get_suggested_tracker_names() return PackedStringArray(); } -XrCompositionLayerBaseHeader *OpenXRExtensionWrapperExtension::get_composition_layer() { +int OpenXRExtensionWrapperExtension::get_composition_layer_count() { + int count = 0; + GDVIRTUAL_CALL(_get_composition_layer_count, count); + return count; +} + +XrCompositionLayerBaseHeader *OpenXRExtensionWrapperExtension::get_composition_layer(int p_index) { uint64_t pointer; - if (GDVIRTUAL_CALL(_get_composition_layer, pointer)) { + if (GDVIRTUAL_CALL(_get_composition_layer, p_index, pointer)) { return reinterpret_cast(pointer); } return nullptr; } +int OpenXRExtensionWrapperExtension::get_composition_layer_order(int p_index) { + int order = 0; + GDVIRTUAL_CALL(_get_composition_layer_order, p_index, order); + return order; +} + void OpenXRExtensionWrapperExtension::on_register_metadata() { GDVIRTUAL_CALL(_on_register_metadata); } diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h index edcbc0139b5..d3b78bf6170 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h @@ -59,7 +59,9 @@ 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 XrCompositionLayerBaseHeader *get_composition_layer() 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; //TODO workaround as GDExtensionPtr return type results in build error in godot-cpp GDVIRTUAL1R(uint64_t, _set_system_properties_and_get_next_pointer, GDExtensionPtr); @@ -67,7 +69,9 @@ public: GDVIRTUAL1R(uint64_t, _set_session_create_and_get_next_pointer, GDExtensionPtr); 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); - GDVIRTUAL0R(uint64_t, _get_composition_layer); + GDVIRTUAL0R(int, _get_composition_layer_count); + GDVIRTUAL1R(uint64_t, _get_composition_layer, int); + GDVIRTUAL1R(int, _get_composition_layer_order, int); virtual PackedStringArray get_suggested_tracker_names() override; diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index e978c012b53..8dd017c2137 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -2080,18 +2080,29 @@ void OpenXRAPI::end_frame() { projection_views[eye].pose = views[eye].pose; } - Vector layers_list; + Vector ordered_layers_list; + bool projection_layer_is_first = true; // Add composition layers from providers for (OpenXRCompositionLayerProvider *provider : composition_layer_providers) { - XrCompositionLayerBaseHeader *layer = provider->get_composition_layer(); - if (layer) { - layers_list.push_back(layer); + for (int i = 0; i < provider->get_composition_layer_count(); i++) { + OrderedCompositionLayer layer = { + provider->get_composition_layer(i), + provider->get_composition_layer_order(i), + }; + if (layer.composition_layer) { + ordered_layers_list.push_back(layer); + if (layer.sort_order == 0) { + WARN_PRINT_ONCE_ED("Composition layer returned sort order 0, it may be overwritten by projection layer."); + } else if (layer.sort_order < 0) { + projection_layer_is_first = false; + } + } } } XrCompositionLayerFlags layer_flags = XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; - if (layers_list.size() > 0 || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) { + if (!projection_layer_is_first || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) { layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; } @@ -2103,7 +2114,16 @@ void OpenXRAPI::end_frame() { view_count, // viewCount projection_views, // views }; - layers_list.push_back((const XrCompositionLayerBaseHeader *)&projection_layer); + ordered_layers_list.push_back({ (const XrCompositionLayerBaseHeader *)&projection_layer, 0 }); + + // Sort our layers. + ordered_layers_list.sort_custom(); + + // Now make a list we can pass on to OpenXR. + Vector layers_list; + for (OrderedCompositionLayer &ordered_layer : ordered_layers_list) { + layers_list.push_back(ordered_layer.composition_layer); + } XrFrameEndInfo frame_end_info = { XR_TYPE_FRAME_END_INFO, // type diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index e1a04a07966..7ec622364b0 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -287,6 +287,15 @@ private: RID get_interaction_profile_rid(XrPath p_path); XrPath get_interaction_profile_path(RID p_interaction_profile); + struct OrderedCompositionLayer { + const XrCompositionLayerBaseHeader *composition_layer; + int sort_order; + + _FORCE_INLINE_ bool operator()(const OrderedCompositionLayer &a, const OrderedCompositionLayer &b) const { + return a.sort_order < b.sort_order || (a.sort_order == b.sort_order && uint64_t(a.composition_layer) < uint64_t(b.composition_layer)); + } + }; + // state changes bool poll_events(); bool on_state_idle();