Path: blob/master/modules/openxr/extensions/openxr_composition_layer_extension.cpp
20969 views
/**************************************************************************/1/* openxr_composition_layer_extension.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "openxr_composition_layer_extension.h"3132#ifdef ANDROID_ENABLED33#include <openxr/openxr.h>34#include <openxr/openxr_platform.h>35#endif3637#include "openxr_fb_update_swapchain_extension.h"38#include "platform/android/api/java_class_wrapper.h"39#include "servers/rendering/rendering_server_globals.h"4041////////////////////////////////////////////////////////////////////////////42// OpenXRCompositionLayerExtension4344OpenXRCompositionLayerExtension *OpenXRCompositionLayerExtension::singleton = nullptr;4546OpenXRCompositionLayerExtension *OpenXRCompositionLayerExtension::get_singleton() {47return singleton;48}4950OpenXRCompositionLayerExtension::OpenXRCompositionLayerExtension() {51singleton = this;52}5354OpenXRCompositionLayerExtension::~OpenXRCompositionLayerExtension() {55singleton = nullptr;56}5758HashMap<String, bool *> OpenXRCompositionLayerExtension::get_requested_extensions(XrVersion p_version) {59HashMap<String, bool *> request_extensions;6061request_extensions[XR_KHR_COMPOSITION_LAYER_CYLINDER_EXTENSION_NAME] = &cylinder_ext_available;62request_extensions[XR_KHR_COMPOSITION_LAYER_EQUIRECT2_EXTENSION_NAME] = &equirect_ext_available;6364#ifdef ANDROID_ENABLED65request_extensions[XR_KHR_ANDROID_SURFACE_SWAPCHAIN_EXTENSION_NAME] = &android_surface_ext_available;66#endif6768return request_extensions;69}7071void OpenXRCompositionLayerExtension::on_instance_created(const XrInstance p_instance) {72#ifdef ANDROID_ENABLED73EXT_INIT_XR_FUNC(xrDestroySwapchain);74if (android_surface_ext_available) {75EXT_INIT_XR_FUNC(xrCreateSwapchainAndroidSurfaceKHR);76}77#endif78}7980void OpenXRCompositionLayerExtension::on_session_created(const XrSession p_session) {81OpenXRAPI::get_singleton()->register_composition_layer_provider(this);82}8384void OpenXRCompositionLayerExtension::on_session_destroyed() {85OpenXRAPI::get_singleton()->unregister_composition_layer_provider(this);86}8788void OpenXRCompositionLayerExtension::on_pre_render() {89for (CompositionLayer *composition_layer : registered_composition_layers) {90composition_layer->on_pre_render();91}92}9394int OpenXRCompositionLayerExtension::get_composition_layer_count() {95return registered_composition_layers.size();96}9798XrCompositionLayerBaseHeader *OpenXRCompositionLayerExtension::get_composition_layer(int p_index) {99ERR_FAIL_UNSIGNED_INDEX_V((unsigned int)p_index, registered_composition_layers.size(), nullptr);100return registered_composition_layers[p_index]->get_composition_layer();101}102103int OpenXRCompositionLayerExtension::get_composition_layer_order(int p_index) {104ERR_FAIL_UNSIGNED_INDEX_V((unsigned int)p_index, registered_composition_layers.size(), 1);105return registered_composition_layers[p_index]->sort_order;106}107108RID OpenXRCompositionLayerExtension::composition_layer_create(XrCompositionLayerBaseHeader *p_openxr_layer) {109RID rid = composition_layer_owner.make_rid();110CompositionLayer *layer = composition_layer_owner.get_or_null(rid);111112switch (p_openxr_layer->type) {113case XR_TYPE_COMPOSITION_LAYER_QUAD: {114layer->composition_layer_quad = *(XrCompositionLayerQuad *)p_openxr_layer;115} break;116case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {117layer->composition_layer_cylinder = *(XrCompositionLayerCylinderKHR *)p_openxr_layer;118} break;119case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {120layer->composition_layer_equirect = *(XrCompositionLayerEquirect2KHR *)p_openxr_layer;121} break;122default: {123ERR_PRINT(vformat("Invalid OpenXR composition layer type: %s", p_openxr_layer->type));124composition_layer_owner.free(rid);125return RID();126}127}128129return rid;130}131132void OpenXRCompositionLayerExtension::composition_layer_free(RID p_layer) {133RenderingServer::get_singleton()->call_on_render_thread(callable_mp(this, &OpenXRCompositionLayerExtension::_composition_layer_free_rt).bind(p_layer));134}135136void OpenXRCompositionLayerExtension::composition_layer_register(RID p_layer) {137RenderingServer::get_singleton()->call_on_render_thread(callable_mp(this, &OpenXRCompositionLayerExtension::_composition_layer_register_rt).bind(p_layer));138}139140void OpenXRCompositionLayerExtension::composition_layer_unregister(RID p_layer) {141RenderingServer::get_singleton()->call_on_render_thread(callable_mp(this, &OpenXRCompositionLayerExtension::_composition_layer_unregister_rt).bind(p_layer));142}143144Ref<JavaObject> OpenXRCompositionLayerExtension::composition_layer_get_android_surface(RID p_layer) {145MutexLock lock(composition_layer_mutex);146CompositionLayer *layer = composition_layer_owner.get_or_null(p_layer);147ERR_FAIL_NULL_V(layer, Ref<JavaObject>());148return layer->get_android_surface();149}150151void OpenXRCompositionLayerExtension::_composition_layer_free_rt(RID p_layer) {152_composition_layer_unregister_rt(p_layer);153154MutexLock lock(composition_layer_mutex);155CompositionLayer *layer = composition_layer_owner.get_or_null(p_layer);156if (layer) {157for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {158extension->on_viewport_composition_layer_destroyed(&layer->composition_layer);159}160layer->free();161}162163composition_layer_owner.free(p_layer);164}165166void OpenXRCompositionLayerExtension::_composition_layer_register_rt(RID p_layer) {167CompositionLayer *layer = composition_layer_owner.get_or_null(p_layer);168ERR_FAIL_NULL(layer);169registered_composition_layers.push_back(layer);170}171172void OpenXRCompositionLayerExtension::_composition_layer_unregister_rt(RID p_layer) {173CompositionLayer *layer = composition_layer_owner.get_or_null(p_layer);174ERR_FAIL_NULL(layer);175registered_composition_layers.erase(layer);176}177178bool OpenXRCompositionLayerExtension::is_available(XrStructureType p_which) {179switch (p_which) {180case XR_TYPE_COMPOSITION_LAYER_QUAD: {181// Doesn't require an extension.182return true;183} break;184case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {185return cylinder_ext_available;186} break;187case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {188return equirect_ext_available;189} break;190default: {191ERR_PRINT(vformat("Unsupported composition layer type: %s", p_which));192return false;193}194}195}196197#ifdef ANDROID_ENABLED198bool OpenXRCompositionLayerExtension::create_android_surface_swapchain(XrSwapchainCreateInfo *p_info, XrSwapchain *r_swapchain, jobject *r_surface) {199if (android_surface_ext_available) {200OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();201ERR_FAIL_NULL_V(openxr_api, false);202203XrResult result = xrCreateSwapchainAndroidSurfaceKHR(openxr_api->get_session(), p_info, r_swapchain, r_surface);204if (XR_FAILED(result)) {205print_line("OpenXR: Failed to create Android surface swapchain [", openxr_api->get_error_string(result), "]");206return false;207}208209return true;210}211212return false;213}214#endif215216////////////////////////////////////////////////////////////////////////////217// OpenXRCompositionLayerExtension::CompositionLayer218219void OpenXRCompositionLayerExtension::CompositionLayer::set_viewport(RID p_viewport, const Size2i &p_size) {220ERR_FAIL_COND(use_android_surface);221222if (subviewport.viewport != p_viewport) {223if (subviewport.viewport.is_valid()) {224RID rt = RenderingServer::get_singleton()->viewport_get_render_target(subviewport.viewport);225RSG::texture_storage->render_target_set_override(rt, RID(), RID(), RID(), RID());226}227228subviewport.viewport = p_viewport;229230if (subviewport.viewport.is_valid()) {231subviewport.viewport_size = p_size;232} else {233free_swapchain();234subviewport.viewport_size = Size2i();235}236} else if (subviewport.viewport_size != p_size) {237subviewport.viewport_size = p_size;238}239}240241void OpenXRCompositionLayerExtension::CompositionLayer::set_use_android_surface(bool p_use_android_surface, const Size2i &p_size) {242#ifdef ANDROID_ENABLED243if (p_use_android_surface == use_android_surface) {244if (use_android_surface && swapchain_size != p_size) {245OpenXRFBUpdateSwapchainExtension *fb_update_swapchain_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();246if (fb_update_swapchain_ext && fb_update_swapchain_ext->is_android_ext_enabled()) {247swapchain_size = p_size;248fb_update_swapchain_ext->update_swapchain_surface_size(android_surface.swapchain, swapchain_size);249}250}251return;252}253254use_android_surface = p_use_android_surface;255256if (use_android_surface) {257if (!OpenXRCompositionLayerExtension::get_singleton()->is_android_surface_swapchain_available()) {258ERR_PRINT_ONCE("OpenXR: Cannot use Android surface for composition layer because the extension isn't available");259}260261if (subviewport.viewport.is_valid()) {262set_viewport(RID(), Size2i());263}264265swapchain_size = p_size;266} else {267free_swapchain();268}269#endif270}271272void OpenXRCompositionLayerExtension::CompositionLayer::set_alpha_blend(bool p_alpha_blend) {273if (alpha_blend != p_alpha_blend) {274alpha_blend = p_alpha_blend;275if (alpha_blend) {276composition_layer.layerFlags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;277} else {278composition_layer.layerFlags &= ~XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;279}280}281}282283void OpenXRCompositionLayerExtension::CompositionLayer::set_transform(const Transform3D &p_transform) {284Transform3D xf;285286if (pose_space == POSE_HEAD_LOCKED) {287// Local transform relative to the head/camera.288xf = p_transform;289} else {290// Relative to the XROrigin3D, so we need to apply the reference frame.291Transform3D reference_frame = XRServer::get_singleton()->get_reference_frame();292xf = reference_frame.inverse() * p_transform;293}294295Quaternion quat(xf.basis.orthonormalized());296297// Prevent invalid quaternion298if (Math::is_zero_approx(quat.length())) {299quat = Quaternion(); // identity quaternion300}301302XrPosef pose = {303{ (float)quat.x, (float)quat.y, (float)quat.z, (float)quat.w },304{ (float)xf.origin.x, (float)xf.origin.y, (float)xf.origin.z }305};306307switch (composition_layer.type) {308case XR_TYPE_COMPOSITION_LAYER_QUAD: {309composition_layer_quad.pose = pose;310} break;311312case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {313composition_layer_cylinder.pose = pose;314} break;315316case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {317composition_layer_equirect.pose = pose;318} break;319320default: {321ERR_PRINT(vformat("Cannot set transform on unsupported composition layer type: %s", composition_layer.type));322}323}324}325326void OpenXRCompositionLayerExtension::CompositionLayer::set_extension_property_values(const Dictionary &p_property_values) {327extension_property_values = p_property_values;328extension_property_values_changed = true;329}330331void OpenXRCompositionLayerExtension::CompositionLayer::set_min_filter(Filter p_mode) {332swapchain_state.min_filter = p_mode;333swapchain_state_is_dirty = true;334}335336void OpenXRCompositionLayerExtension::CompositionLayer::set_mag_filter(Filter p_mode) {337swapchain_state.mag_filter = p_mode;338swapchain_state_is_dirty = true;339}340341void OpenXRCompositionLayerExtension::CompositionLayer::set_mipmap_mode(MipmapMode p_mode) {342swapchain_state.mipmap_mode = p_mode;343swapchain_state_is_dirty = true;344}345346void OpenXRCompositionLayerExtension::CompositionLayer::set_horizontal_wrap(Wrap p_mode) {347swapchain_state.horizontal_wrap = p_mode;348swapchain_state_is_dirty = true;349}350351void OpenXRCompositionLayerExtension::CompositionLayer::set_vertical_wrap(Wrap p_mode) {352swapchain_state.vertical_wrap = p_mode;353swapchain_state_is_dirty = true;354}355356void OpenXRCompositionLayerExtension::CompositionLayer::set_red_swizzle(Swizzle p_mode) {357swapchain_state.red_swizzle = p_mode;358swapchain_state_is_dirty = true;359}360361void OpenXRCompositionLayerExtension::CompositionLayer::set_green_swizzle(Swizzle p_mode) {362swapchain_state.green_swizzle = p_mode;363swapchain_state_is_dirty = true;364}365366void OpenXRCompositionLayerExtension::CompositionLayer::set_blue_swizzle(Swizzle p_mode) {367swapchain_state.blue_swizzle = p_mode;368swapchain_state_is_dirty = true;369}370371void OpenXRCompositionLayerExtension::CompositionLayer::set_alpha_swizzle(Swizzle p_mode) {372swapchain_state.alpha_swizzle = p_mode;373swapchain_state_is_dirty = true;374}375376void OpenXRCompositionLayerExtension::CompositionLayer::set_max_anisotropy(float p_value) {377swapchain_state.max_anisotropy = p_value;378swapchain_state_is_dirty = true;379}380381void OpenXRCompositionLayerExtension::CompositionLayer::set_border_color(const Color &p_color) {382swapchain_state.border_color = p_color;383swapchain_state_is_dirty = true;384}385386void OpenXRCompositionLayerExtension::CompositionLayer::set_pose_space(PoseSpace p_pose_space) {387pose_space = p_pose_space;388}389390void OpenXRCompositionLayerExtension::CompositionLayer::set_eye_visibility(EyeVisibility p_eye_visibility) {391XrEyeVisibility eye_visibility;392393switch (p_eye_visibility) {394case EYE_VISIBILITY_BOTH: {395eye_visibility = XR_EYE_VISIBILITY_BOTH;396} break;397398case EYE_VISIBILITY_LEFT: {399eye_visibility = XR_EYE_VISIBILITY_LEFT;400} break;401402case EYE_VISIBILITY_RIGHT: {403eye_visibility = XR_EYE_VISIBILITY_RIGHT;404} break;405406default: {407eye_visibility = XR_EYE_VISIBILITY_BOTH;408}409}410411switch (composition_layer.type) {412case XR_TYPE_COMPOSITION_LAYER_QUAD: {413composition_layer_quad.eyeVisibility = eye_visibility;414} break;415416case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {417composition_layer_cylinder.eyeVisibility = eye_visibility;418} break;419420case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {421composition_layer_equirect.eyeVisibility = eye_visibility;422} break;423424default: {425ERR_PRINT(vformat("%s does not support setting eye visibility.", composition_layer.type));426}427}428}429430void OpenXRCompositionLayerExtension::CompositionLayer::set_quad_size(const Size2 &p_size) {431ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_QUAD);432composition_layer_quad.size = { (float)p_size.x, (float)p_size.y };433}434435void OpenXRCompositionLayerExtension::CompositionLayer::set_cylinder_radius(float p_radius) {436ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR);437composition_layer_cylinder.radius = p_radius;438}439440void OpenXRCompositionLayerExtension::CompositionLayer::set_cylinder_aspect_ratio(float p_aspect_ratio) {441ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR);442composition_layer_cylinder.aspectRatio = p_aspect_ratio;443}444445void OpenXRCompositionLayerExtension::CompositionLayer::set_cylinder_central_angle(float p_central_angle) {446ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR);447composition_layer_cylinder.centralAngle = p_central_angle;448}449450void OpenXRCompositionLayerExtension::CompositionLayer::set_equirect_radius(float p_radius) {451ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR);452composition_layer_equirect.radius = p_radius;453}454455void OpenXRCompositionLayerExtension::CompositionLayer::set_equirect_central_horizontal_angle(float p_angle) {456ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR);457composition_layer_equirect.centralHorizontalAngle = p_angle;458}459460void OpenXRCompositionLayerExtension::CompositionLayer::set_equirect_upper_vertical_angle(float p_angle) {461ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR);462composition_layer_equirect.upperVerticalAngle = p_angle;463}464465void OpenXRCompositionLayerExtension::CompositionLayer::set_equirect_lower_vertical_angle(float p_angle) {466ERR_FAIL_COND(composition_layer.type != XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR);467composition_layer_equirect.lowerVerticalAngle = p_angle;468}469470Ref<JavaObject> OpenXRCompositionLayerExtension::CompositionLayer::get_android_surface() {471#ifdef ANDROID_ENABLED472if (use_android_surface) {473MutexLock lock(OpenXRCompositionLayerExtension::get_singleton()->composition_layer_mutex);474if (android_surface.surface.is_null()) {475create_android_surface();476}477return android_surface.surface;478}479#endif480return Ref<JavaObject>();481}482483void OpenXRCompositionLayerExtension::CompositionLayer::on_pre_render() {484#ifdef ANDROID_ENABLED485if (use_android_surface) {486MutexLock lock(OpenXRCompositionLayerExtension::get_singleton()->composition_layer_mutex);487if (android_surface.surface.is_null()) {488create_android_surface();489}490return;491}492#endif493494RenderingServer *rs = RenderingServer::get_singleton();495OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();496497if (subviewport.viewport.is_valid() && openxr_api && openxr_api->is_running()) {498RS::ViewportUpdateMode update_mode = rs->viewport_get_update_mode(subviewport.viewport);499if (update_mode == RS::VIEWPORT_UPDATE_ONCE || update_mode == RS::VIEWPORT_UPDATE_ALWAYS) {500// Update our XR swapchain501if (update_and_acquire_swapchain(update_mode == RS::VIEWPORT_UPDATE_ONCE)) {502// Render to our XR swapchain image.503RID rt = rs->viewport_get_render_target(subviewport.viewport);504RSG::texture_storage->render_target_set_override(rt, get_current_swapchain_texture(), RID(), RID(), RID());505}506}507}508509if (swapchain_state_is_dirty) {510update_swapchain_state();511swapchain_state_is_dirty = false;512}513}514515XrCompositionLayerBaseHeader *OpenXRCompositionLayerExtension::CompositionLayer::get_composition_layer() {516OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();517OpenXRCompositionLayerExtension *composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();518519if (openxr_api == nullptr || composition_layer_extension == nullptr) {520// OpenXR not initialized or we're in the editor?521return nullptr;522}523524if (!composition_layer_extension->is_available(composition_layer.type)) {525// Selected type is not supported, ignore our layer.526return nullptr;527}528529XrSwapchainSubImage subimage = {5300, // swapchain // NOLINT(modernize-use-nullptr) - 32-bit uses non-pointer uint64531{ { 0, 0 }, { 0, 0 } }, // imageRect5320, // imageArrayIndex533};534update_swapchain_sub_image(subimage);535536if (subimage.swapchain == XR_NULL_HANDLE) {537// Don't have a swapchain to display? Ignore our layer.538return nullptr;539}540541// Update the layer's reference space542switch (pose_space) {543case POSE_WORLD_LOCKED: {544layer_reference_space = openxr_api->get_play_space();545break;546}547548case POSE_HEAD_LOCKED: {549layer_reference_space = openxr_api->get_view_space();550break;551}552default: {553return nullptr;554}555}556557// Update the layer struct for the swapchain.558switch (composition_layer.type) {559case XR_TYPE_COMPOSITION_LAYER_QUAD: {560composition_layer_quad.space = layer_reference_space;561composition_layer_quad.subImage = subimage;562} break;563564case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {565composition_layer_cylinder.space = layer_reference_space;566composition_layer_cylinder.subImage = subimage;567} break;568569case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {570composition_layer_equirect.space = layer_reference_space;571composition_layer_equirect.subImage = subimage;572} break;573574default: {575return nullptr;576}577}578579if (extension_property_values_changed) {580extension_property_values_changed = false;581582void *next_pointer = nullptr;583for (OpenXRExtensionWrapper *extension : OpenXRAPI::get_registered_extension_wrappers()) {584void *np = extension->set_viewport_composition_layer_and_get_next_pointer(&composition_layer, extension_property_values, next_pointer);585if (np) {586next_pointer = np;587}588}589composition_layer.next = next_pointer;590}591592return &composition_layer;593}594595void OpenXRCompositionLayerExtension::CompositionLayer::free() {596if (use_android_surface) {597free_swapchain();598} else {599// This will reset the viewport and free the swapchain too.600set_viewport(RID(), Size2i());601}602}603604void OpenXRCompositionLayerExtension::CompositionLayer::update_swapchain_state() {605OpenXRFBUpdateSwapchainExtension *fb_update_swapchain_ext = OpenXRFBUpdateSwapchainExtension::get_singleton();606if (!fb_update_swapchain_ext) {607return;608}609610#ifdef ANDROID_ENABLED611if (use_android_surface) {612if (android_surface.swapchain == XR_NULL_HANDLE) {613return;614}615616fb_update_swapchain_ext->update_swapchain_state(android_surface.swapchain, &swapchain_state);617} else618#endif619{620if (subviewport.swapchain_info.get_swapchain() == XR_NULL_HANDLE) {621return;622}623624fb_update_swapchain_ext->update_swapchain_state(subviewport.swapchain_info.get_swapchain(), &swapchain_state);625}626}627628void OpenXRCompositionLayerExtension::CompositionLayer::update_swapchain_sub_image(XrSwapchainSubImage &r_subimage) {629#ifdef ANDROID_ENABLED630if (use_android_surface) {631r_subimage.swapchain = android_surface.swapchain;632} else633#endif634{635XrSwapchain swapchain = subviewport.swapchain_info.get_swapchain();636637if (swapchain && subviewport.swapchain_info.is_image_acquired()) {638subviewport.swapchain_info.release();639}640641r_subimage.swapchain = swapchain;642}643644r_subimage.imageRect.extent.width = swapchain_size.width;645r_subimage.imageRect.extent.height = swapchain_size.height;646}647648bool OpenXRCompositionLayerExtension::CompositionLayer::update_and_acquire_swapchain(bool p_static_image) {649ERR_FAIL_COND_V(use_android_surface, false);650651OpenXRCompositionLayerExtension *composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();652OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();653654if (openxr_api == nullptr || composition_layer_extension == nullptr) {655// OpenXR not initialized or we're in the editor?656return false;657}658if (!composition_layer_extension->is_available(composition_layer.type)) {659// Selected type is not supported?660return false;661}662663// See if our current swapchain is outdated.664if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {665// If this swap chain, or the previous one, were static, then we can't reuse it.666if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image && protected_content == subviewport.swapchain_protected_content) {667// We're all good! Just acquire it.668// We can ignore should_render here, return will be false.669bool should_render = true;670return subviewport.swapchain_info.acquire(should_render);671}672673subviewport.swapchain_info.queue_free();674}675676// Create our new swap chain677int64_t swapchain_format = openxr_api->get_color_swapchain_format();678const uint32_t sample_count = 1;679const uint32_t array_size = 1;680XrSwapchainCreateFlags create_flags = 0;681if (p_static_image) {682create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT;683}684if (protected_content) {685create_flags |= XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT;686}687if (!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)) {688swapchain_size = Size2i();689return false;690}691692swapchain_state_is_dirty = true;693694// Acquire our image so we can start rendering into it,695// we can ignore should_render here, ret will be false.696bool should_render = true;697bool ret = subviewport.swapchain_info.acquire(should_render);698699swapchain_size = subviewport.viewport_size;700subviewport.static_image = p_static_image;701subviewport.swapchain_protected_content = protected_content;702return ret;703}704705RID OpenXRCompositionLayerExtension::CompositionLayer::get_current_swapchain_texture() {706ERR_FAIL_COND_V(use_android_surface, RID());707708if (OpenXRAPI::get_singleton() == nullptr) {709return RID();710}711712return subviewport.swapchain_info.get_image();713}714715void OpenXRCompositionLayerExtension::CompositionLayer::free_swapchain() {716#ifdef ANDROID_ENABLED717if (use_android_surface) {718if (android_surface.swapchain != XR_NULL_HANDLE) {719OpenXRCompositionLayerExtension::get_singleton()->xrDestroySwapchain(android_surface.swapchain);720android_surface.swapchain = XR_NULL_HANDLE;721android_surface.surface.unref();722}723} else724#endif725{726if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) {727subviewport.swapchain_info.queue_free();728}729subviewport.static_image = false;730}731732swapchain_size = Size2i();733}734735#ifdef ANDROID_ENABLED736void OpenXRCompositionLayerExtension::CompositionLayer::create_android_surface() {737ERR_FAIL_COND(android_surface.swapchain != XR_NULL_HANDLE || android_surface.surface.is_valid());738739void *next_pointer = nullptr;740for (OpenXRExtensionWrapper *wrapper : OpenXRAPI::get_registered_extension_wrappers()) {741void *np = wrapper->set_android_surface_swapchain_create_info_and_get_next_pointer(extension_property_values, next_pointer);742if (np != nullptr) {743next_pointer = np;744}745}746747// Check to see if content should be protected.748XrSwapchainCreateFlags create_flags = 0;749750if (protected_content) {751create_flags = XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT;752}753754// The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount,755// faceCount, arraySize, and mipCount must be zero.756XrSwapchainCreateInfo info = {757XR_TYPE_SWAPCHAIN_CREATE_INFO, // type758next_pointer, // next759create_flags, // createFlags760XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags7610, // format7620, // sampleCount763(uint32_t)swapchain_size.x, // width764(uint32_t)swapchain_size.y, // height7650, // faceCount7660, // arraySize7670, // mipCount768};769770jobject surface;771OpenXRCompositionLayerExtension::get_singleton()->create_android_surface_swapchain(&info, &android_surface.swapchain, &surface);772773swapchain_state_is_dirty = true;774775if (surface) {776android_surface.surface.instantiate(JavaClassWrapper::get_singleton()->wrap("android.view.Surface"), surface);777}778}779#endif780781782