summaryrefslogtreecommitdiffstats
path: root/modules/openxr/extensions/openxr_composition_layer_extension.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/openxr/extensions/openxr_composition_layer_extension.cpp')
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_extension.cpp257
1 files changed, 209 insertions, 48 deletions
diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp
index 8a448afc08..83e45ffe7f 100644
--- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp
+++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp
@@ -30,6 +30,12 @@
#include "openxr_composition_layer_extension.h"
+#ifdef ANDROID_ENABLED
+#include <openxr/openxr.h>
+#include <openxr/openxr_platform.h>
+#endif
+
+#include "platform/android/api/java_class_wrapper.h"
#include "servers/rendering/rendering_server_globals.h"
////////////////////////////////////////////////////////////////////////////
@@ -55,18 +61,37 @@ HashMap<String, bool *> OpenXRCompositionLayerExtension::get_requested_extension
request_extensions[XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME] = &cylinder_ext_available;
request_extensions[XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME] = &equirect_ext_available;
+#ifdef ANDROID_ENABLED
+ request_extensions[XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME] = &android_surface_ext_available;
+#endif
+
return request_extensions;
}
+void OpenXRCompositionLayerExtension::on_instance_created(const XrInstance p_instance) {
+#ifdef ANDROID_ENABLED
+ EXT_INIT_XR_FUNC(xrDestroySwapchain);
+ EXT_INIT_XR_FUNC(xrCreateSwapchainAndroidSurfaceKHR);
+#endif
+}
+
void OpenXRCompositionLayerExtension::on_session_created(const XrSession p_session) {
OpenXRAPI::get_singleton()->register_composition_layer_provider(this);
}
void OpenXRCompositionLayerExtension::on_session_destroyed() {
OpenXRAPI::get_singleton()->unregister_composition_layer_provider(this);
+
+#ifdef ANDROID_ENABLED
+ free_queued_android_surface_swapchains();
+#endif
}
void OpenXRCompositionLayerExtension::on_pre_render() {
+#ifdef ANDROID_ENABLED
+ free_queued_android_surface_swapchains();
+#endif
+
for (OpenXRViewportCompositionLayerProvider *composition_layer : composition_layers) {
composition_layer->on_pre_render();
}
@@ -113,6 +138,37 @@ bool OpenXRCompositionLayerExtension::is_available(XrStructureType p_which) {
}
}
+#ifdef ANDROID_ENABLED
+bool OpenXRCompositionLayerExtension::create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface) {
+ if (android_surface_ext_available) {
+ OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
+ ERR_FAIL_NULL_V(openxr_api, false);
+
+ // @todo We need a way to add to the next pointer chain.
+ XrResult result = xrCreateSwapchainAndroidSurfaceKHR(openxr_api->get_session(), p_info, r_swapchain, r_surface);
+ if (XR_FAILED(result)) {
+ print_line("OpenXR: Failed to create Android surface swapchain [", openxr_api->get_error_string(result), "]");
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void OpenXRCompositionLayerExtension::free_android_surface_swapchain(XrSwapchain p_swapchain) {
+ android_surface_swapchain_free_queue.push_back(p_swapchain);
+}
+
+void OpenXRCompositionLayerExtension::free_queued_android_surface_swapchains() {
+ for (XrSwapchain swapchain : android_surface_swapchain_free_queue) {
+ xrDestroySwapchain(swapchain);
+ }
+ android_surface_swapchain_free_queue.clear();
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////
// OpenXRViewportCompositionLayerProvider
@@ -127,8 +183,12 @@ OpenXRViewportCompositionLayerProvider::~OpenXRViewportCompositionLayerProvider(
extension->on_viewport_composition_layer_destroyed(composition_layer);
}
- // This will reset the viewport and free the swapchain too.
- set_viewport(RID(), Size2i());
+ if (use_android_surface) {
+ free_swapchain();
+ } else {
+ // This will reset the viewport and free the swapchain too.
+ set_viewport(RID(), Size2i());
+ }
}
void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend) {
@@ -143,24 +203,92 @@ void OpenXRViewportCompositionLayerProvider::set_alpha_blend(bool p_alpha_blend)
}
void OpenXRViewportCompositionLayerProvider::set_viewport(RID p_viewport, Size2i p_size) {
+ ERR_FAIL_COND(use_android_surface);
+
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
- if (viewport != p_viewport) {
- if (viewport.is_valid()) {
- RID rt = rs->viewport_get_render_target(viewport);
+ if (subviewport.viewport != p_viewport) {
+ if (subviewport.viewport.is_valid()) {
+ RID rt = rs->viewport_get_render_target(subviewport.viewport);
RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID());
}
- viewport = p_viewport;
+ subviewport.viewport = p_viewport;
- if (viewport.is_valid()) {
- viewport_size = p_size;
+ if (subviewport.viewport.is_valid()) {
+ subviewport.viewport_size = p_size;
} else {
free_swapchain();
- viewport_size = Size2i();
+ subviewport.viewport_size = Size2i();
+ }
+ }
+}
+
+void OpenXRViewportCompositionLayerProvider::set_use_android_surface(bool p_use_android_surface, Size2i p_size) {
+#ifdef ANDROID_ENABLED
+ if (p_use_android_surface == use_android_surface) {
+ return;
+ }
+
+ use_android_surface = p_use_android_surface;
+
+ if (use_android_surface) {
+ if (!composition_layer_extension->is_android_surface_swapchain_available()) {
+ ERR_PRINT_ONCE("OpenXR: Cannot use Android surface for composition layer because the extension isn't available");
}
+
+ if (subviewport.viewport.is_valid()) {
+ set_viewport(RID(), Size2i());
+ }
+
+ swapchain_size = p_size;
+ } else {
+ free_swapchain();
+ }
+#endif
+}
+
+#ifdef ANDROID_ENABLED
+void OpenXRViewportCompositionLayerProvider::create_android_surface() {
+ ERR_FAIL_COND(android_surface.swapchain != XR_NULL_HANDLE || android_surface.surface.is_valid());
+ ERR_FAIL_COND(!openxr_api || !openxr_api->is_running());
+
+ // The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount,
+ // faceCount, arraySize, and mipCount must be zero.
+ XrSwapchainCreateInfo info = {
+ XR_TYPE_SWAPCHAIN_CREATE_INFO, // type
+ nullptr, // next
+ 0, // createFlags
+ XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags
+ 0, // format
+ 0, // sampleCount
+ (uint32_t)swapchain_size.x, // width
+ (uint32_t)swapchain_size.y, // height
+ 0, // faceCount
+ 0, // arraySize
+ 0, // mipCount
+ };
+
+ jobject surface;
+ composition_layer_extension->create_android_surface_swapchain(&info, &android_surface.swapchain, &surface);
+
+ if (surface) {
+ android_surface.surface = Ref<JavaObject>(memnew(JavaObject(JavaClassWrapper::get_singleton()->wrap("android.view.Surface"), surface)));
+ }
+}
+#endif
+
+Ref<JavaObject> OpenXRViewportCompositionLayerProvider::get_android_surface() {
+#ifdef ANDROID_ENABLED
+ if (use_android_surface) {
+ if (android_surface.surface.is_null()) {
+ create_android_surface();
+ }
+ return android_surface.surface;
}
+#endif
+ return Ref<JavaObject>();
}
void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const Dictionary &p_extension_property_values) {
@@ -169,16 +297,25 @@ void OpenXRViewportCompositionLayerProvider::set_extension_property_values(const
}
void OpenXRViewportCompositionLayerProvider::on_pre_render() {
+#ifdef ANDROID_ENABLED
+ if (use_android_surface) {
+ if (android_surface.surface.is_null()) {
+ create_android_surface();
+ }
+ return;
+ }
+#endif
+
RenderingServer *rs = RenderingServer::get_singleton();
ERR_FAIL_NULL(rs);
- if (viewport.is_valid() && openxr_api && openxr_api->is_running()) {
- RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(viewport);
+ if (subviewport.viewport.is_valid() && openxr_api && openxr_api->is_running()) {
+ RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(subviewport.viewport);
if (update_mode == RS::VIEWPORT_UPDATE_ONCE || update_mode == RS::VIEWPORT_UPDATE_ALWAYS) {
// Update our XR swapchain
if (update_and_acquire_swapchain(update_mode == RS::VIEWPORT_UPDATE_ONCE)) {
// Render to our XR swapchain image.
- RID rt = rs->viewport_get_render_target(viewport);
+ RID rt = rs->viewport_get_render_target(subviewport.viewport);
RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID());
}
}
@@ -196,48 +333,36 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
return nullptr;
}
- if (swapchain_info.get_swapchain() == XR_NULL_HANDLE) {
+ XrSwapchainSubImage subimage = {
+ 0, // swapchain
+ { { 0, 0 }, { 0, 0 } }, // imageRect
+ 0, // imageArrayIndex
+ };
+ update_swapchain_sub_image(subimage);
+
+ if (subimage.swapchain == XR_NULL_HANDLE) {
// Don't have a swapchain to display? Ignore our layer.
return nullptr;
}
- if (swapchain_info.is_image_acquired()) {
- swapchain_info.release();
- }
-
// Update the layer struct for the swapchain.
switch (composition_layer->type) {
case XR_TYPE_COMPOSITION_LAYER_QUAD: {
XrCompositionLayerQuad *quad_layer = (XrCompositionLayerQuad *)composition_layer;
quad_layer->space = openxr_api->get_play_space();
- quad_layer->subImage.swapchain = swapchain_info.get_swapchain();
- quad_layer->subImage.imageArrayIndex = 0;
- quad_layer->subImage.imageRect.offset.x = 0;
- quad_layer->subImage.imageRect.offset.y = 0;
- quad_layer->subImage.imageRect.extent.width = swapchain_size.width;
- quad_layer->subImage.imageRect.extent.height = swapchain_size.height;
+ quad_layer->subImage = subimage;
} break;
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {
XrCompositionLayerCylinderKHR *cylinder_layer = (XrCompositionLayerCylinderKHR *)composition_layer;
cylinder_layer->space = openxr_api->get_play_space();
- cylinder_layer->subImage.swapchain = swapchain_info.get_swapchain();
- cylinder_layer->subImage.imageArrayIndex = 0;
- cylinder_layer->subImage.imageRect.offset.x = 0;
- cylinder_layer->subImage.imageRect.offset.y = 0;
- cylinder_layer->subImage.imageRect.extent.width = swapchain_size.width;
- cylinder_layer->subImage.imageRect.extent.height = swapchain_size.height;
+ cylinder_layer->subImage = subimage;
} break;
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {
XrCompositionLayerEquirect2KHR *equirect_layer = (XrCompositionLayerEquirect2KHR *)composition_layer;
equirect_layer->space = openxr_api->get_play_space();
- equirect_layer->subImage.swapchain = swapchain_info.get_swapchain();
- equirect_layer->subImage.imageArrayIndex = 0;
- equirect_layer->subImage.imageRect.offset.x = 0;
- equirect_layer->subImage.imageRect.offset.y = 0;
- equirect_layer->subImage.imageRect.extent.width = swapchain_size.width;
- equirect_layer->subImage.imageRect.extent.height = swapchain_size.height;
+ equirect_layer->subImage = subimage;
} break;
default: {
@@ -261,27 +386,49 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
return composition_layer;
}
+void OpenXRViewportCompositionLayerProvider::update_swapchain_sub_image(XrSwapchainSubImage &r_subimage) {
+#ifdef ANDROID_ENABLED
+ if (use_android_surface) {
+ r_subimage.swapchain = android_surface.swapchain;
+ } else
+#endif
+ {
+ XrSwapchain swapchain = subviewport.swapchain_info.get_swapchain();
+
+ if (swapchain && subviewport.swapchain_info.is_image_acquired()) {
+ subviewport.swapchain_info.release();
+ }
+
+ r_subimage.swapchain = swapchain;
+ }
+
+ r_subimage.imageRect.extent.width = swapchain_size.width;
+ r_subimage.imageRect.extent.height = swapchain_size.height;
+}
+
bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p_static_image) {
+ ERR_FAIL_COND_V(use_android_surface, false);
+
if (openxr_api == nullptr || composition_layer_extension == nullptr) {
// OpenXR not initialized or we're in the editor?
return false;
}
- if (!composition_layer_extension->is_available(composition_layer->type)) {
+ if (!composition_layer_extension->is_available(get_openxr_type())) {
// Selected type is not supported?
return false;
}
// See if our current swapchain is outdated.
- if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
+ if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
// If this swap chain, or the previous one, were static, then we can't reuse it.
- if (swapchain_size == viewport_size && !p_static_image && !static_image) {
+ if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image) {
// We're all good! Just acquire it.
// We can ignore should_render here, return will be false.
bool should_render = true;
- return swapchain_info.acquire(should_render);
+ return subviewport.swapchain_info.acquire(should_render);
}
- swapchain_info.queue_free();
+ subviewport.swapchain_info.queue_free();
}
// Create our new swap chain
@@ -292,7 +439,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p
if (p_static_image) {
create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;
}
- if (!swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, viewport_size.width, viewport_size.height, sample_count, array_size)) {
+ if (!subviewport.swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, subviewport.viewport_size.width, subviewport.viewport_size.height, sample_count, array_size)) {
swapchain_size = Size2i();
return false;
}
@@ -300,26 +447,40 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p
// Acquire our image so we can start rendering into it,
// we can ignore should_render here, ret will be false.
bool should_render = true;
- bool ret = swapchain_info.acquire(should_render);
+ bool ret = subviewport.swapchain_info.acquire(should_render);
- swapchain_size = viewport_size;
- static_image = p_static_image;
+ swapchain_size = subviewport.viewport_size;
+ subviewport.static_image = p_static_image;
return ret;
}
void OpenXRViewportCompositionLayerProvider::free_swapchain() {
- if (swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
- swapchain_info.queue_free();
+#ifdef ANDROID_ENABLED
+ if (use_android_surface) {
+ if (android_surface.swapchain != XR_NULL_HANDLE) {
+ composition_layer_extension->free_android_surface_swapchain(android_surface.swapchain);
+
+ android_surface.swapchain = XR_NULL_HANDLE;
+ android_surface.surface.unref();
+ }
+ } else
+#endif
+ {
+ if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {
+ subviewport.swapchain_info.queue_free();
+ }
+ subviewport.static_image = false;
}
swapchain_size = Size2i();
- static_image = false;
}
RID OpenXRViewportCompositionLayerProvider::get_current_swapchain_texture() {
+ ERR_FAIL_COND_V(use_android_surface, RID());
+
if (openxr_api == nullptr) {
return RID();
}
- return swapchain_info.get_image();
+ return subviewport.swapchain_info.get_image();
}