diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml index 79aa547c526..338d6325241 100644 --- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml +++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml @@ -84,6 +84,12 @@ Called right before the OpenXR instance is destroyed. + + + + Called right after the main swapchains are (re)created. + + diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index ce03df0b30d..8d05657afce 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -84,6 +84,7 @@ public: // This is when controller data is queried and made available to game logic. virtual void on_process() {} virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewports. + virtual void on_main_swapchains_created() {} // `on_main_swapchains_created` is called right after our main swapchains are (re)created. virtual void on_pre_draw_viewport(RID p_render_target) {} // `on_pre_draw_viewport` is called right before we start rendering this viewport virtual void on_post_draw_viewport(RID p_render_target) {} // `on_port_draw_viewport` is called right after we start rendering this viewport (note that on Vulkan draw commands may only be queued) diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp index 3b31e1b1f66..e09ca484d52 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp @@ -50,6 +50,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() { GDVIRTUAL_BIND(_on_session_created, "session"); GDVIRTUAL_BIND(_on_process); GDVIRTUAL_BIND(_on_pre_render); + GDVIRTUAL_BIND(_on_main_swapchains_created); GDVIRTUAL_BIND(_on_session_destroyed); GDVIRTUAL_BIND(_on_state_idle); GDVIRTUAL_BIND(_on_state_ready); @@ -198,6 +199,10 @@ void OpenXRExtensionWrapperExtension::on_pre_render() { GDVIRTUAL_CALL(_on_pre_render); } +void OpenXRExtensionWrapperExtension::on_main_swapchains_created() { + GDVIRTUAL_CALL(_on_main_swapchains_created); +} + void OpenXRExtensionWrapperExtension::on_session_destroyed() { GDVIRTUAL_CALL(_on_session_destroyed); } diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h index 71d2a57ff89..e37853903b3 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h +++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h @@ -86,6 +86,7 @@ public: virtual void on_session_created(const XrSession p_session) override; virtual void on_process() override; virtual void on_pre_render() override; + virtual void on_main_swapchains_created() override; virtual void on_session_destroyed() override; GDVIRTUAL0(_on_register_metadata); @@ -95,6 +96,7 @@ public: GDVIRTUAL1(_on_session_created, uint64_t); GDVIRTUAL0(_on_process); GDVIRTUAL0(_on_pre_render); + GDVIRTUAL0(_on_main_swapchains_created); GDVIRTUAL0(_on_session_destroyed); virtual void on_state_idle() override; diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.cpp b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp index bbdd2e3c8aa..8ce808dd3c9 100644 --- a/modules/openxr/extensions/openxr_fb_foveation_extension.cpp +++ b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp @@ -101,7 +101,7 @@ void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer } } -void OpenXRFBFoveationExtension::on_state_ready() { +void OpenXRFBFoveationExtension::on_main_swapchains_created() { update_profile(); } @@ -127,26 +127,41 @@ void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_fo update_profile(); } -void OpenXRFBFoveationExtension::update_profile() { - if (!is_enabled()) { +void OpenXRFBFoveationExtension::_update_profile() { + // Must be called from rendering thread! + ERR_NOT_ON_RENDER_THREAD; + + OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton(); + ERR_FAIL_NULL(fov_ext); + + if (!fov_ext->is_enabled()) { + return; + } + + OpenXRAPI *openxr_api = OpenXRAPI::get_singleton(); + ERR_FAIL_NULL(openxr_api); + + XrSwapchain main_color_swapchain = openxr_api->get_color_swapchain(); + if (main_color_swapchain == XR_NULL_HANDLE) { + // Our swapchain hasn't been created yet, we'll call this again once it has. return; } XrFoveationLevelProfileCreateInfoFB level_profile_create_info; level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB; level_profile_create_info.next = nullptr; - level_profile_create_info.level = foveation_level; + level_profile_create_info.level = fov_ext->foveation_level; level_profile_create_info.verticalOffset = 0.0f; - level_profile_create_info.dynamic = foveation_dynamic; + level_profile_create_info.dynamic = fov_ext->foveation_dynamic; XrFoveationProfileCreateInfoFB profile_create_info; profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB; profile_create_info.next = &level_profile_create_info; XrFoveationProfileFB foveation_profile; - XrResult result = xrCreateFoveationProfileFB(OpenXRAPI::get_singleton()->get_session(), &profile_create_info, &foveation_profile); + XrResult result = fov_ext->xrCreateFoveationProfileFB(openxr_api->get_session(), &profile_create_info, &foveation_profile); if (XR_FAILED(result)) { - print_line("OpenXR: Unable to create the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); + print_line("OpenXR: Unable to create the foveation profile [", openxr_api->get_error_string(result), "]"); return; } @@ -154,15 +169,15 @@ void OpenXRFBFoveationExtension::update_profile() { foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB; foveation_update_state.profile = foveation_profile; - result = swapchain_update_state_ext->xrUpdateSwapchainFB(OpenXRAPI::get_singleton()->get_color_swapchain(), (XrSwapchainStateBaseHeaderFB *)&foveation_update_state); + result = fov_ext->swapchain_update_state_ext->xrUpdateSwapchainFB(main_color_swapchain, (XrSwapchainStateBaseHeaderFB *)&foveation_update_state); if (XR_FAILED(result)) { - print_line("OpenXR: Unable to update the swapchain [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); + print_line("OpenXR: Unable to update the swapchain [", openxr_api->get_error_string(result), "]"); // We still want to destroy our profile so keep going... } - result = xrDestroyFoveationProfileFB(foveation_profile); + result = fov_ext->xrDestroyFoveationProfileFB(foveation_profile); if (XR_FAILED(result)) { - print_line("OpenXR: Unable to destroy the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]"); + print_line("OpenXR: Unable to destroy the foveation profile [", openxr_api->get_error_string(result), "]"); } } diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.h b/modules/openxr/extensions/openxr_fb_foveation_extension.h index 1c5e7227316..84bd7011b52 100644 --- a/modules/openxr/extensions/openxr_fb_foveation_extension.h +++ b/modules/openxr/extensions/openxr_fb_foveation_extension.h @@ -60,7 +60,7 @@ public: virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override; - virtual void on_state_ready() override; + virtual void on_main_swapchains_created() override; bool is_enabled() const; @@ -82,7 +82,15 @@ private: XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB; XrFoveationDynamicFB foveation_dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB; - void update_profile(); + static void _update_profile(); + + void update_profile() { + // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready... + RenderingServer *rendering_server = RenderingServer::get_singleton(); + ERR_FAIL_NULL(rendering_server); + + rendering_server->call_on_render_thread(callable_mp_static(&OpenXRFBFoveationExtension::_update_profile)); + } // Enable foveation on this swapchain XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb; diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 32512070d6d..541e3699251 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -1220,6 +1220,10 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) { } }; + for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) { + wrapper->on_main_swapchains_created(); + } + return true; };