summaryrefslogtreecommitdiffstats
path: root/modules/openxr/scene/openxr_composition_layer.cpp
diff options
context:
space:
mode:
authorDavid Snopek <dsnopek@gmail.com>2024-08-26 17:02:28 -0500
committerDavid Snopek <dsnopek@gmail.com>2024-09-11 21:15:22 -0500
commit3afa26834a072ca1a9bcc53e0e1b9d6467b74ed2 (patch)
tree7ca5be09765b5ec07cb379ad211286ede0dc7b45 /modules/openxr/scene/openxr_composition_layer.cpp
parent97ef3c837263099faf02d8ebafd6c77c94d2aaba (diff)
downloadredot-engine-3afa26834a072ca1a9bcc53e0e1b9d6467b74ed2.tar.gz
OpenXR: Support composition layers based on Android surfaces
Diffstat (limited to 'modules/openxr/scene/openxr_composition_layer.cpp')
-rw-r--r--modules/openxr/scene/openxr_composition_layer.cpp179
1 files changed, 125 insertions, 54 deletions
diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp
index f69a907be9..697369d516 100644
--- a/modules/openxr/scene/openxr_composition_layer.cpp
+++ b/modules/openxr/scene/openxr_composition_layer.cpp
@@ -38,6 +38,8 @@
#include "scene/3d/xr_nodes.h"
#include "scene/main/viewport.h"
+#include "platform/android/api/java_class_wrapper.h"
+
Vector<OpenXRCompositionLayer *> OpenXRCompositionLayer::composition_layer_nodes;
static const char *HOLE_PUNCH_SHADER_CODE =
@@ -47,7 +49,10 @@ static const char *HOLE_PUNCH_SHADER_CODE =
"\tALBEDO = vec3(0.0, 0.0, 0.0);\n"
"}\n";
-OpenXRCompositionLayer::OpenXRCompositionLayer() {
+OpenXRCompositionLayer::OpenXRCompositionLayer(XrCompositionLayerBaseHeader *p_composition_layer) {
+ composition_layer_base_header = p_composition_layer;
+ openxr_layer_provider = memnew(OpenXRViewportCompositionLayerProvider(composition_layer_base_header));
+
openxr_api = OpenXRAPI::get_singleton();
composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();
@@ -85,6 +90,12 @@ void OpenXRCompositionLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_viewport", "viewport"), &OpenXRCompositionLayer::set_layer_viewport);
ClassDB::bind_method(D_METHOD("get_layer_viewport"), &OpenXRCompositionLayer::get_layer_viewport);
+ ClassDB::bind_method(D_METHOD("set_use_android_surface", "enable"), &OpenXRCompositionLayer::set_use_android_surface);
+ ClassDB::bind_method(D_METHOD("get_use_android_surface"), &OpenXRCompositionLayer::get_use_android_surface);
+
+ ClassDB::bind_method(D_METHOD("set_android_surface_size", "size"), &OpenXRCompositionLayer::set_android_surface_size);
+ ClassDB::bind_method(D_METHOD("get_android_surface_size"), &OpenXRCompositionLayer::get_android_surface_size);
+
ClassDB::bind_method(D_METHOD("set_enable_hole_punch", "enable"), &OpenXRCompositionLayer::set_enable_hole_punch);
ClassDB::bind_method(D_METHOD("get_enable_hole_punch"), &OpenXRCompositionLayer::get_enable_hole_punch);
@@ -94,11 +105,14 @@ void OpenXRCompositionLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alpha_blend", "enabled"), &OpenXRCompositionLayer::set_alpha_blend);
ClassDB::bind_method(D_METHOD("get_alpha_blend"), &OpenXRCompositionLayer::get_alpha_blend);
+ ClassDB::bind_method(D_METHOD("get_android_surface"), &OpenXRCompositionLayer::get_android_surface);
ClassDB::bind_method(D_METHOD("is_natively_supported"), &OpenXRCompositionLayer::is_natively_supported);
ClassDB::bind_method(D_METHOD("intersects_ray", "origin", "direction"), &OpenXRCompositionLayer::intersects_ray);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_android_surface", PROPERTY_HINT_NONE, ""), "set_use_android_surface", "get_use_android_surface");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "android_surface_size", PROPERTY_HINT_NONE, ""), "set_android_surface_size", "get_android_surface_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_hole_punch", PROPERTY_HINT_NONE, ""), "set_enable_hole_punch", "get_enable_hole_punch");
@@ -108,7 +122,7 @@ bool OpenXRCompositionLayer::_should_use_fallback_node() {
if (Engine::get_singleton()->is_editor_hint()) {
return true;
} else if (openxr_session_running) {
- return enable_hole_punch || !is_natively_supported();
+ return enable_hole_punch || (!is_natively_supported() && !use_android_surface);
}
return false;
}
@@ -128,10 +142,36 @@ void OpenXRCompositionLayer::_remove_fallback_node() {
fallback = nullptr;
}
+void OpenXRCompositionLayer::_setup_composition_layer_provider() {
+ if (use_android_surface || layer_viewport) {
+ if (composition_layer_extension) {
+ composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider);
+ }
+
+ // NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly.
+ if (layer_viewport) {
+ // Set our properties on the layer provider, which will create all the necessary resources (ex swap chains).
+ openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
+ }
+ }
+}
+
+void OpenXRCompositionLayer::_clear_composition_layer_provider() {
+ if (composition_layer_extension) {
+ composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider);
+ }
+
+ // NOTE: We don't setup/clear when using Android surfaces, so we don't destroy the surface unexpectedly.
+ if (!use_android_surface) {
+ // This will reset the viewport and free all the resources (ex swap chains) used by the layer.
+ openxr_layer_provider->set_viewport(RID(), Size2i());
+ }
+}
+
void OpenXRCompositionLayer::_on_openxr_session_begun() {
openxr_session_running = true;
- if (layer_viewport && is_natively_supported() && is_visible() && is_inside_tree()) {
- openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
+ if (is_natively_supported() && is_visible() && is_inside_tree()) {
+ _setup_composition_layer_provider();
}
if (!fallback && _should_use_fallback_node()) {
_create_fallback_node();
@@ -142,9 +182,8 @@ void OpenXRCompositionLayer::_on_openxr_session_stopping() {
openxr_session_running = false;
if (fallback && !_should_use_fallback_node()) {
_remove_fallback_node();
- } else {
- openxr_layer_provider->set_viewport(RID(), Size2i());
}
+ _clear_composition_layer_provider();
}
void OpenXRCompositionLayer::update_fallback_mesh() {
@@ -162,6 +201,7 @@ XrPosef OpenXRCompositionLayer::get_openxr_pose() {
}
bool OpenXRCompositionLayer::is_viewport_in_use(SubViewport *p_viewport) {
+ ERR_FAIL_NULL_V(p_viewport, false);
for (const OpenXRCompositionLayer *other_composition_layer : composition_layer_nodes) {
if (other_composition_layer != this && other_composition_layer->is_inside_tree() && other_composition_layer->get_layer_viewport() == p_viewport) {
return true;
@@ -178,6 +218,9 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
if (p_viewport != nullptr) {
ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first."));
}
+ if (use_android_surface) {
+ ERR_FAIL_COND_MSG(p_viewport != nullptr, RTR("Cannot set SubViewport on an OpenXR composition layer when using an Android surface."));
+ }
layer_viewport = p_viewport;
@@ -200,6 +243,41 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
}
}
+void OpenXRCompositionLayer::set_use_android_surface(bool p_use_android_surface) {
+ if (use_android_surface == p_use_android_surface) {
+ return;
+ }
+
+ use_android_surface = p_use_android_surface;
+ if (use_android_surface) {
+ set_layer_viewport(nullptr);
+ openxr_layer_provider->set_use_android_surface(true, android_surface_size);
+ } else {
+ openxr_layer_provider->set_use_android_surface(false, Size2i());
+ }
+
+ notify_property_list_changed();
+}
+
+bool OpenXRCompositionLayer::get_use_android_surface() const {
+ return use_android_surface;
+}
+
+void OpenXRCompositionLayer::set_android_surface_size(Size2i p_size) {
+ if (android_surface_size == p_size) {
+ return;
+ }
+
+ android_surface_size = p_size;
+ if (use_android_surface) {
+ openxr_layer_provider->set_use_android_surface(true, android_surface_size);
+ }
+}
+
+Size2i OpenXRCompositionLayer::get_android_surface_size() const {
+ return android_surface_size;
+}
+
SubViewport *OpenXRCompositionLayer::get_layer_viewport() const {
return layer_viewport;
}
@@ -228,33 +306,23 @@ bool OpenXRCompositionLayer::get_enable_hole_punch() const {
}
void OpenXRCompositionLayer::set_sort_order(int p_order) {
- if (openxr_layer_provider) {
- openxr_layer_provider->set_sort_order(p_order);
- update_configuration_warnings();
- }
+ openxr_layer_provider->set_sort_order(p_order);
+ update_configuration_warnings();
}
int OpenXRCompositionLayer::get_sort_order() const {
- if (openxr_layer_provider) {
- return openxr_layer_provider->get_sort_order();
- }
- return 1;
+ return openxr_layer_provider->get_sort_order();
}
void OpenXRCompositionLayer::set_alpha_blend(bool p_alpha_blend) {
- if (openxr_layer_provider) {
- openxr_layer_provider->set_alpha_blend(p_alpha_blend);
- if (fallback) {
- _reset_fallback_material();
- }
+ openxr_layer_provider->set_alpha_blend(p_alpha_blend);
+ if (fallback) {
+ _reset_fallback_material();
}
}
bool OpenXRCompositionLayer::get_alpha_blend() const {
- if (openxr_layer_provider) {
- return openxr_layer_provider->get_alpha_blend();
- }
- return false;
+ return openxr_layer_provider->get_alpha_blend();
}
bool OpenXRCompositionLayer::is_natively_supported() const {
@@ -264,6 +332,10 @@ bool OpenXRCompositionLayer::is_natively_supported() const {
return false;
}
+Ref<JavaObject> OpenXRCompositionLayer::get_android_surface() {
+ return openxr_layer_provider->get_android_surface();
+}
+
Vector2 OpenXRCompositionLayer::intersects_ray(const Vector3 &p_origin, const Vector3 &p_direction) const {
return Vector2(-1.0, -1.0);
}
@@ -301,10 +373,7 @@ void OpenXRCompositionLayer::_reset_fallback_material() {
Ref<ViewportTexture> texture = material->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
if (texture.is_null()) {
- texture.instantiate();
- // ViewportTexture can't be configured without a local scene, so use this hack to set it.
- HashMap<Ref<Resource>, Ref<Resource>> remap_cache;
- texture->configure_for_local_scene(this, remap_cache);
+ texture = layer_viewport->get_texture();
}
Node *loc_scene = texture->get_local_scene();
@@ -321,12 +390,10 @@ void OpenXRCompositionLayer::_notification(int p_what) {
case NOTIFICATION_POSTINITIALIZE: {
composition_layer_nodes.push_back(this);
- 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);
+ 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) {
@@ -339,10 +406,10 @@ void OpenXRCompositionLayer::_notification(int p_what) {
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
if (!fallback && openxr_session_running && is_inside_tree()) {
- if (layer_viewport && is_visible()) {
- openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
+ if (is_visible()) {
+ _setup_composition_layer_provider();
} else {
- openxr_layer_provider->set_viewport(RID(), Size2i());
+ _clear_composition_layer_provider();
}
}
update_configuration_warnings();
@@ -351,25 +418,15 @@ void OpenXRCompositionLayer::_notification(int p_what) {
update_configuration_warnings();
} break;
case NOTIFICATION_ENTER_TREE: {
- if (composition_layer_extension) {
- composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider);
- }
-
- if (is_viewport_in_use(layer_viewport)) {
- set_layer_viewport(nullptr);
- } else if (!fallback && layer_viewport && openxr_session_running && is_visible()) {
- openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
+ if (layer_viewport && is_viewport_in_use(layer_viewport)) {
+ _clear_composition_layer_provider();
+ } else if (openxr_session_running && is_visible()) {
+ _setup_composition_layer_provider();
}
} break;
case NOTIFICATION_EXIT_TREE: {
- if (composition_layer_extension) {
- composition_layer_extension->unregister_viewport_composition_layer_provider(openxr_layer_provider);
- }
-
- if (!fallback) {
- // This will clean up existing resources.
- openxr_layer_provider->set_viewport(RID(), Size2i());
- }
+ // This will clean up existing resources.
+ _clear_composition_layer_provider();
} break;
}
}
@@ -401,13 +458,27 @@ bool OpenXRCompositionLayer::_get(const StringName &p_property, Variant &r_value
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);
- }
+ openxr_layer_provider->set_extension_property_values(extension_property_values);
return true;
}
+void OpenXRCompositionLayer::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "layer_viewport") {
+ if (use_android_surface) {
+ p_property.usage &= ~PROPERTY_USAGE_EDITOR;
+ } else {
+ p_property.usage |= PROPERTY_USAGE_EDITOR;
+ }
+ } else if (p_property.name == "android_surface_size") {
+ if (use_android_surface) {
+ p_property.usage |= PROPERTY_USAGE_EDITOR;
+ } else {
+ p_property.usage &= ~PROPERTY_USAGE_EDITOR;
+ }
+ }
+}
+
PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const {
PackedStringArray warnings = Node3D::get_configuration_warnings();