diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 1b78196fd9f..2dea63ef0db 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -721,12 +721,19 @@ extern GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhand extern GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, GHOST_TWindowOrder order); +/** + * Acquire a swap chain buffer. + * \param windowhandle: The handle to the window. + * \return A success indicator. + */ +extern GHOST_TSuccess GHOST_SwapWindowBufferAcquire(GHOST_WindowHandle windowhandle); + /** * Swaps front and back buffers of a window. * \param windowhandle: The handle to the window. * \return A success indicator. */ -extern GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle); +extern GHOST_TSuccess GHOST_SwapWindowBufferRelease(GHOST_WindowHandle windowhandle); /** * Sets the swap interval for #swapBuffers. @@ -1299,20 +1306,20 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle context, GHOST_VulkanHandles *r_ * * \param context: GHOST context handle of a vulkan context to * get the Vulkan handles from. - * \param swap_buffers_pre_callback: Function pointer to be called at the beginning of swapBuffers. - * Inside this callback the next swap-chain image needs to be acquired and filled. - * \param swap_buffers_post_callback: Function to be called at th end of swapBuffers. swapBuffers - * can recreate the swap-chain. When this is done the application should be informed by those - * changes. + * \param swap_buffer_draw_callback: Function pointer to be called when acquired swap buffer is + * released, allowing Vulkan backend to update the swap chain. + * \param swap_buffer_acquired_callback: Function to be called at when swap buffer is acquired. + * Allowing Vulkan backend to update the framebuffer. It is also called when no swap chain + * exists indicating that the window was minimuzed. * \param openxr_acquire_image_callback: Function to be called when an image needs to be acquired * to be drawn to an OpenXR swap-chain. - * \param openxr_release_image_callback: Function to be called after an image has been drawn to the - * OpenXR swap-chain. + * \param openxr_release_image_callback: Function to be called after an image has been drawn to + * the OpenXR swap-chain. */ void GHOST_SetVulkanSwapBuffersCallbacks( GHOST_ContextHandle context, - void (*swap_buffers_pre_callback)(const GHOST_VulkanSwapChainData *), - void (*swap_buffers_post_callback)(void), + void (*swap_buffer_draw_callback)(const GHOST_VulkanSwapChainData *), + void (*swap_buffer_acquired_callback)(void), void (*openxr_acquire_image_callback)(GHOST_VulkanOpenXRData *), void (*openxr_release_image_callback)(GHOST_VulkanOpenXRData *)); diff --git a/intern/ghost/GHOST_IContext.hh b/intern/ghost/GHOST_IContext.hh index a6331a1487e..0b95762eb99 100644 --- a/intern/ghost/GHOST_IContext.hh +++ b/intern/ghost/GHOST_IContext.hh @@ -51,11 +51,17 @@ class GHOST_IContext { * \return The ID of an OpenGL frame-buffer object. */ virtual unsigned int getDefaultFramebuffer() = 0; + /** + * Acquire next buffer for drawing. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBufferAcquire() = 0; + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess swapBuffers() = 0; + virtual GHOST_TSuccess swapBufferRelease() = 0; #ifdef WITH_VULKAN_BACKEND /** @@ -91,20 +97,19 @@ class GHOST_IContext { * * \param context: GHOST context handle of a vulkan context to * get the Vulkan handles from. - * \param swap_buffers_pre_callback: Function pointer to be called at the beginning of - * swapBuffers. Inside this callback the next swap-chain image needs to be acquired and - * filled. - * \param swap_buffers_post_callback: Function to be called at th end of swapBuffers. - * swapBuffers can recreate the swap-chain. When this is done the application should be - * informed by those changes. - * \param openxr_acquire_image_callback: Function to be called when an - * image needs to be acquired to be drawn to an OpenXR swap-chain. + * \param swap_buffer_draw_callback: Function pointer to be called when acquired swap buffer is + * released, allowing Vulkan backend to update the swap chain. + * \param swap_buffer_acquired_callback: Function to be called at when swap buffer is acquired. + * Allowing Vulkan backend to update the framebuffer. It is also called when no swap chain + * exists indicating that the window was minimuzed. + * \param openxr_acquire_image_callback: Function to be called when an image needs to be acquired + * to be drawn to an OpenXR swap-chain. * \param openxr_release_image_callback: Function to be called after an image has been drawn to * the OpenXR swap-chain. */ virtual GHOST_TSuccess setVulkanSwapBuffersCallbacks( - std::function swap_buffers_pre_callback, - std::function swap_buffers_post_callback, + std::function swap_buffer_draw_callback, + std::function swap_buffer_acquired_callback, std::function openxr_acquire_framebuffer_image_callback, std::function openxr_release_framebuffer_image_callback) = 0; #endif diff --git a/intern/ghost/GHOST_IWindow.hh b/intern/ghost/GHOST_IWindow.hh index b7a95bed10b..0725dff60e5 100644 --- a/intern/ghost/GHOST_IWindow.hh +++ b/intern/ghost/GHOST_IWindow.hh @@ -205,11 +205,17 @@ class GHOST_IWindow { */ virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; + /** + * Acquire the next buffer of the swap chain. + * \return A boolean success indicator. + */ + virtual GHOST_TSuccess swapBufferAcquire() = 0; + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - virtual GHOST_TSuccess swapBuffers() = 0; + virtual GHOST_TSuccess swapBufferRelease() = 0; /** * Sets the swap interval for #swapBuffers. diff --git a/intern/ghost/intern/GHOST_C-api.cc b/intern/ghost/intern/GHOST_C-api.cc index c10e0b20f24..913e0f069d4 100644 --- a/intern/ghost/intern/GHOST_C-api.cc +++ b/intern/ghost/intern/GHOST_C-api.cc @@ -711,11 +711,18 @@ GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, GHOST_TWind return window->setOrder(order); } -GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle) +GHOST_TSuccess GHOST_SwapWindowBufferAcquire(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; - return window->swapBuffers(); + return window->swapBufferAcquire(); +} + +GHOST_TSuccess GHOST_SwapWindowBufferRelease(GHOST_WindowHandle windowhandle) +{ + GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; + + return window->swapBufferRelease(); } GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interval) @@ -1273,14 +1280,14 @@ void GHOST_GetVulkanHandles(GHOST_ContextHandle contexthandle, GHOST_VulkanHandl void GHOST_SetVulkanSwapBuffersCallbacks( GHOST_ContextHandle contexthandle, - void (*swap_buffers_pre_callback)(const GHOST_VulkanSwapChainData *), - void (*swap_buffers_post_callback)(void), + void (*swap_buffer_draw_callback)(const GHOST_VulkanSwapChainData *), + void (*swap_buffer_acquired_callback)(void), void (*openxr_acquire_image_callback)(GHOST_VulkanOpenXRData *), void (*openxr_release_image_callback)(GHOST_VulkanOpenXRData *)) { GHOST_IContext *context = (GHOST_IContext *)contexthandle; - context->setVulkanSwapBuffersCallbacks(swap_buffers_pre_callback, - swap_buffers_post_callback, + context->setVulkanSwapBuffersCallbacks(swap_buffer_draw_callback, + swap_buffer_acquired_callback, openxr_acquire_image_callback, openxr_release_image_callback); } diff --git a/intern/ghost/intern/GHOST_Context.hh b/intern/ghost/intern/GHOST_Context.hh index 2214d86fa6d..cd3bfbb0022 100644 --- a/intern/ghost/intern/GHOST_Context.hh +++ b/intern/ghost/intern/GHOST_Context.hh @@ -43,8 +43,11 @@ class GHOST_Context : public GHOST_IContext { return active_context_; } + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override = 0; + /** \copydoc #GHOST_IContext::swapBuffers */ - GHOST_TSuccess swapBuffers() override = 0; + GHOST_TSuccess swapBufferRelease() override = 0; /** \copydoc #GHOST_IContext::activateDrawingContext */ GHOST_TSuccess activateDrawingContext() override = 0; @@ -155,8 +158,8 @@ class GHOST_Context : public GHOST_IContext { /** \copydoc #GHOST_IContext::setVulkanSwapBuffersCallbacks */ virtual GHOST_TSuccess setVulkanSwapBuffersCallbacks( - std::function /*swap_buffers_pre_callback*/, - std::function /*swap_buffers_post_callback*/, + std::function /*swap_buffer_draw_callback*/, + std::function /*swap_buffer_acquired_callback*/, std::function /*openxr_acquire_framebuffer_image_callback*/, std::function /*openxr_release_framebuffer_image_callback*/) override diff --git a/intern/ghost/intern/GHOST_ContextD3D.cc b/intern/ghost/intern/GHOST_ContextD3D.cc index e50d555d5b0..b5baec045c1 100644 --- a/intern/ghost/intern/GHOST_ContextD3D.cc +++ b/intern/ghost/intern/GHOST_ContextD3D.cc @@ -32,7 +32,7 @@ GHOST_ContextD3D::~GHOST_ContextD3D() device_ctx_->Release(); } -GHOST_TSuccess GHOST_ContextD3D::swapBuffers() +GHOST_TSuccess GHOST_ContextD3D::swapBufferRelease() { return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_ContextD3D.hh b/intern/ghost/intern/GHOST_ContextD3D.hh index feb811a9f7e..48de1ee7c22 100644 --- a/intern/ghost/intern/GHOST_ContextD3D.hh +++ b/intern/ghost/intern/GHOST_ContextD3D.hh @@ -26,11 +26,17 @@ class GHOST_ContextD3D : public GHOST_Context { GHOST_ContextD3D(const GHOST_ContextParams &context_params, HWND hWnd); ~GHOST_ContextD3D() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_ContextEGL.cc b/intern/ghost/intern/GHOST_ContextEGL.cc index 4c623c64bc3..adb88fe0904 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.cc +++ b/intern/ghost/intern/GHOST_ContextEGL.cc @@ -246,7 +246,7 @@ GHOST_ContextEGL::~GHOST_ContextEGL() } } -GHOST_TSuccess GHOST_ContextEGL::swapBuffers() +GHOST_TSuccess GHOST_ContextEGL::swapBufferRelease() { return EGL_CHK(::eglSwapBuffers(display_, surface_)) ? GHOST_kSuccess : GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_ContextEGL.hh b/intern/ghost/intern/GHOST_ContextEGL.hh index 5f5f620ec7b..a26cd4926d0 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.hh +++ b/intern/ghost/intern/GHOST_ContextEGL.hh @@ -50,11 +50,17 @@ class GHOST_ContextEGL : public GHOST_Context { */ ~GHOST_ContextEGL() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_ContextGLX.cc b/intern/ghost/intern/GHOST_ContextGLX.cc index bd5ed6c16a2..35584790b87 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cc +++ b/intern/ghost/intern/GHOST_ContextGLX.cc @@ -73,7 +73,7 @@ GHOST_ContextGLX::~GHOST_ContextGLX() } } -GHOST_TSuccess GHOST_ContextGLX::swapBuffers() +GHOST_TSuccess GHOST_ContextGLX::swapBufferRelease() { ::glXSwapBuffers(display_, window_); diff --git a/intern/ghost/intern/GHOST_ContextGLX.hh b/intern/ghost/intern/GHOST_ContextGLX.hh index 2707dc2e24e..6ed91793e34 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.hh +++ b/intern/ghost/intern/GHOST_ContextGLX.hh @@ -44,11 +44,17 @@ class GHOST_ContextGLX : public GHOST_Context { */ ~GHOST_ContextGLX() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_ContextMTL.hh b/intern/ghost/intern/GHOST_ContextMTL.hh index 28cb6431412..ec8f25bc735 100644 --- a/intern/ghost/intern/GHOST_ContextMTL.hh +++ b/intern/ghost/intern/GHOST_ContextMTL.hh @@ -50,11 +50,17 @@ class GHOST_ContextMTL : public GHOST_Context { */ ~GHOST_ContextMTL() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_ContextMTL.mm b/intern/ghost/intern/GHOST_ContextMTL.mm index 051add2bf4a..66da5873514 100644 --- a/intern/ghost/intern/GHOST_ContextMTL.mm +++ b/intern/ghost/intern/GHOST_ContextMTL.mm @@ -138,7 +138,7 @@ GHOST_ContextMTL::~GHOST_ContextMTL() } } -GHOST_TSuccess GHOST_ContextMTL::swapBuffers() +GHOST_TSuccess GHOST_ContextMTL::swapBufferRelease() { if (metal_view_) { metalSwapBuffers(); diff --git a/intern/ghost/intern/GHOST_ContextNone.cc b/intern/ghost/intern/GHOST_ContextNone.cc index 25614d4ac4e..c7b7f731608 100644 --- a/intern/ghost/intern/GHOST_ContextNone.cc +++ b/intern/ghost/intern/GHOST_ContextNone.cc @@ -10,7 +10,7 @@ #include "GHOST_ContextNone.hh" -GHOST_TSuccess GHOST_ContextNone::swapBuffers() +GHOST_TSuccess GHOST_ContextNone::swapBufferRelease() { return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_ContextNone.hh b/intern/ghost/intern/GHOST_ContextNone.hh index 55ca1807e5c..0b776d6a832 100644 --- a/intern/ghost/intern/GHOST_ContextNone.hh +++ b/intern/ghost/intern/GHOST_ContextNone.hh @@ -16,11 +16,17 @@ class GHOST_ContextNone : public GHOST_Context { public: GHOST_ContextNone(const GHOST_ContextParams &context_params) : GHOST_Context(context_params) {} + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Dummy function * \return Always succeeds */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Dummy function diff --git a/intern/ghost/intern/GHOST_ContextSDL.cc b/intern/ghost/intern/GHOST_ContextSDL.cc index 5b7a51cc5df..f62976eecb4 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.cc +++ b/intern/ghost/intern/GHOST_ContextSDL.cc @@ -61,7 +61,7 @@ GHOST_ContextSDL::~GHOST_ContextSDL() } } -GHOST_TSuccess GHOST_ContextSDL::swapBuffers() +GHOST_TSuccess GHOST_ContextSDL::swapBufferRelease() { SDL_GL_SwapWindow(window_); diff --git a/intern/ghost/intern/GHOST_ContextSDL.hh b/intern/ghost/intern/GHOST_ContextSDL.hh index e504235c038..4d0e918afc7 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.hh +++ b/intern/ghost/intern/GHOST_ContextSDL.hh @@ -44,11 +44,17 @@ class GHOST_ContextSDL : public GHOST_Context { */ ~GHOST_ContextSDL() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index 8928814bc77..66aeb68211b 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -696,8 +696,13 @@ GHOST_ContextVK::~GHOST_ContextVK() } } -GHOST_TSuccess GHOST_ContextVK::swapBuffers() +GHOST_TSuccess GHOST_ContextVK::swapBufferAcquire() { + if (acquired_swapchain_image_index_.has_value()) { + assert(false); + return GHOST_kFailure; + } + GHOST_DeviceVK &device_vk = vulkan_instance->device.value(); VkDevice vk_device = device_vk.vk_device; @@ -708,7 +713,7 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() * submission fence to be signaled, to ensure the invariant holds for the next call to * `swapBuffers`. * - * We will pass the current GHOST_Frame to the swap_buffers_pre_callback_ for command buffer + * We will pass the current GHOST_Frame to the swap_buffer_draw_callback_ for command buffer * submission, and it is the responsibility of that callback to use the current GHOST_Frame's * fence for it's submission fence. Since the callback is called after we wait for the next frame * to be complete, it is also safe in the callback to clean up resources associated with the next @@ -749,8 +754,8 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() } #endif } - /* There is no valid swapchain as the previous window was minimized. User can have maximized the - * window so we need to check if the swapchain can be created. */ + /* there is no valid swapchain when the previous window was minimized. User can have maximized + * the window so we need to check if the swapchain has to be created. */ if (swapchain_ == VK_NULL_HANDLE) { recreateSwapchain(use_hdr_swapchain); } @@ -776,21 +781,22 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() } } - /* Fast path for invalid swapchains. When not valid we don't acquire/present, but we do render to - * make sure the render graphs don't keep memory allocated that isn't used. */ - if (swapchain_ == VK_NULL_HANDLE) { - CLOG_TRACE( - &LOG, - "Swap-chain invalid (due to minimized window), perform rendering to reduce render graph " - "resources."); - GHOST_VulkanSwapChainData swap_chain_data = {}; - if (swap_buffers_pre_callback_) { - swap_buffers_pre_callback_(&swap_chain_data); - } - if (swap_buffers_post_callback_) { - swap_buffers_post_callback_(); - } + /* Acquired callback is also called when there is no swapchain. + * + * When acquiring swap chain (image) and the swap chain is discarded (window has been minimized). + * We have trigger a last acquired callback to reduce the attachments of the GPUFramebuffer. + * Vulkan backend will retrieve the data (getVulkanSwapChainFormat) containing a render extent of + * 0,0. + * + * The next frame window manager will detect that the window is minimized and doesn't draw the + * window at all. + */ + if (swap_buffer_acquired_callback_) { + swap_buffer_acquired_callback_(); + } + if (swapchain_ == VK_NULL_HANDLE) { + CLOG_TRACE(&LOG, "Swap-chain unavailable (minimized window)."); return GHOST_kSuccess; } @@ -798,7 +804,35 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() "Acquired swap-chain image (render_frame=%lu, image_index=%u)", render_frame_, image_index); + acquired_swapchain_image_index_ = image_index; + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_ContextVK::swapBufferRelease() +{ + /* Minimized windows don't have a swapchain and swapchain image. In this case we perform the draw + * to release render graph and discarded resources. */ + if (swapchain_ == VK_NULL_HANDLE) { + GHOST_VulkanSwapChainData swap_chain_data = {}; + if (swap_buffer_draw_callback_) { + swap_buffer_draw_callback_(&swap_chain_data); + } + return GHOST_kSuccess; + } + + if (!acquired_swapchain_image_index_.has_value()) { + assert(false); + return GHOST_kFailure; + } + GHOST_DeviceVK &device_vk = vulkan_instance->device.value(); + VkDevice vk_device = device_vk.vk_device; + + uint32_t image_index = acquired_swapchain_image_index_.value(); GHOST_SwapchainImage &swapchain_image = swapchain_images_[image_index]; + GHOST_Frame &submission_frame_data = frame_data_[render_frame_]; + const bool use_hdr_swapchain = hdr_info_ && hdr_info_->hdr_enabled && + device_vk.use_vk_ext_swapchain_colorspace; GHOST_VulkanSwapChainData swap_chain_data; swap_chain_data.image = swapchain_image.vk_image; @@ -810,8 +844,8 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() swap_chain_data.sdr_scale = (hdr_info_) ? hdr_info_->sdr_white_level : 1.0f; vkResetFences(vk_device, 1, &submission_frame_data.submission_fence); - if (swap_buffers_pre_callback_) { - swap_buffers_pre_callback_(&swap_chain_data); + if (swap_buffer_draw_callback_) { + swap_buffer_draw_callback_(&swap_chain_data); } VkPresentInfoKHR present_info = {}; @@ -828,22 +862,17 @@ GHOST_TSuccess GHOST_ContextVK::swapBuffers() std::scoped_lock lock(device_vk.queue_mutex); present_result = vkQueuePresentKHR(device_vk.generic_queue, &present_info); } + acquired_swapchain_image_index_.reset(); if (present_result == VK_ERROR_OUT_OF_DATE_KHR || present_result == VK_SUBOPTIMAL_KHR) { recreateSwapchain(use_hdr_swapchain); - if (swap_buffers_post_callback_) { - swap_buffers_post_callback_(); - } return GHOST_kSuccess; } if (present_result != VK_SUCCESS) { CLOG_ERROR(&LOG, "Vulkan: failed to present swap-chain image : %s", vulkan_error_as_string(present_result)); - } - - if (swap_buffers_post_callback_) { - swap_buffers_post_callback_(); + return GHOST_kFailure; } return GHOST_kSuccess; @@ -888,13 +917,13 @@ GHOST_TSuccess GHOST_ContextVK::getVulkanHandles(GHOST_VulkanHandles &r_handles) } GHOST_TSuccess GHOST_ContextVK::setVulkanSwapBuffersCallbacks( - std::function swap_buffers_pre_callback, - std::function swap_buffers_post_callback, + std::function swap_buffer_draw_callback, + std::function swap_buffer_acquired_callback, std::function openxr_acquire_framebuffer_image_callback, std::function openxr_release_framebuffer_image_callback) { - swap_buffers_pre_callback_ = swap_buffers_pre_callback; - swap_buffers_post_callback_ = swap_buffers_post_callback; + swap_buffer_draw_callback_ = swap_buffer_draw_callback; + swap_buffer_acquired_callback_ = swap_buffer_acquired_callback; openxr_acquire_framebuffer_image_callback_ = openxr_acquire_framebuffer_image_callback; openxr_release_framebuffer_image_callback_ = openxr_release_framebuffer_image_callback; return GHOST_kSuccess; diff --git a/intern/ghost/intern/GHOST_ContextVK.hh b/intern/ghost/intern/GHOST_ContextVK.hh index f5fcc30a540..9ebf9bf0996 100644 --- a/intern/ghost/intern/GHOST_ContextVK.hh +++ b/intern/ghost/intern/GHOST_ContextVK.hh @@ -33,6 +33,7 @@ # endif #endif +#include #include #ifndef GHOST_OPENGL_VK_CONTEXT_FLAGS @@ -125,11 +126,13 @@ class GHOST_ContextVK : public GHOST_Context { */ ~GHOST_ContextVK() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override; /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. @@ -165,8 +168,8 @@ class GHOST_ContextVK : public GHOST_Context { GHOST_TSuccess getVulkanSwapChainFormat(GHOST_VulkanSwapChainData *r_swap_chain_data) override; GHOST_TSuccess setVulkanSwapBuffersCallbacks( - std::function swap_buffers_pre_callback, - std::function swap_buffers_post_callback, + std::function swap_buffer_draw_callback, + std::function swap_buffer_acquired_callback, std::function openxr_acquire_framebuffer_image_callback, std::function openxr_release_framebuffer_image_callback) override; @@ -237,8 +240,10 @@ class GHOST_ContextVK : public GHOST_Context { VkSurfaceFormatKHR surface_format_; bool use_hdr_swapchain_; - std::function swap_buffers_pre_callback_; - std::function swap_buffers_post_callback_; + std::optional acquired_swapchain_image_index_; + + std::function swap_buffer_draw_callback_; + std::function swap_buffer_acquired_callback_; std::function openxr_acquire_framebuffer_image_callback_; std::function openxr_release_framebuffer_image_callback_; diff --git a/intern/ghost/intern/GHOST_ContextWGL.cc b/intern/ghost/intern/GHOST_ContextWGL.cc index 0762b577145..b2adf52b6ee 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cc +++ b/intern/ghost/intern/GHOST_ContextWGL.cc @@ -83,7 +83,7 @@ GHOST_ContextWGL::~GHOST_ContextWGL() #endif } -GHOST_TSuccess GHOST_ContextWGL::swapBuffers() +GHOST_TSuccess GHOST_ContextWGL::swapBufferRelease() { return WIN32_CHK(::SwapBuffers(h_DC_)) ? GHOST_kSuccess : GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_ContextWGL.hh b/intern/ghost/intern/GHOST_ContextWGL.hh index a97ad414e97..26d9b1ddd39 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.hh +++ b/intern/ghost/intern/GHOST_ContextWGL.hh @@ -39,11 +39,17 @@ class GHOST_ContextWGL : public GHOST_Context { */ ~GHOST_ContextWGL() override; + /** \copydoc #GHOST_IContext::swapBuffersAcquire */ + GHOST_TSuccess swapBufferAcquire() override + { + return GHOST_kSuccess; + } + /** * Swaps front and back buffers of a window. * \return A boolean success indicator. */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** * Activates the drawing context of this window. diff --git a/intern/ghost/intern/GHOST_Window.cc b/intern/ghost/intern/GHOST_Window.cc index 143bac01a8e..c392da7cdf3 100644 --- a/intern/ghost/intern/GHOST_Window.cc +++ b/intern/ghost/intern/GHOST_Window.cc @@ -102,9 +102,13 @@ GHOST_IContext *GHOST_Window::getDrawingContext() return context_; } -GHOST_TSuccess GHOST_Window::swapBuffers() +GHOST_TSuccess GHOST_Window::swapBufferAcquire() { - return context_->swapBuffers(); + return context_->swapBufferAcquire(); +} +GHOST_TSuccess GHOST_Window::swapBufferRelease() +{ + return context_->swapBufferRelease(); } GHOST_TSuccess GHOST_Window::setSwapInterval(int interval) diff --git a/intern/ghost/intern/GHOST_Window.hh b/intern/ghost/intern/GHOST_Window.hh index aaa8c4fef65..f7536de6925 100644 --- a/intern/ghost/intern/GHOST_Window.hh +++ b/intern/ghost/intern/GHOST_Window.hh @@ -56,7 +56,8 @@ class GHOST_Window : public GHOST_IWindow { * virtual GHOST_TWindowState getState() const = 0; * virtual GHOST_TSuccess setState(GHOST_TWindowState state) = 0; * virtual GHOST_TSuccess setOrder(GHOST_TWindowOrder order) = 0; - * virtual GHOST_TSuccess swapBuffers() = 0; + * virtual GHOST_TSuccess swapBufferAcquire() = 0; + * virtual GHOST_TSuccess swapBufferRelease() = 0; * virtual GHOST_TSuccess setSwapInterval() = 0; * virtual GHOST_TSuccess getSwapInterval(int& interval_out) = 0; * virtual GHOST_TSuccess activateDrawingContext() = 0; @@ -195,8 +196,10 @@ class GHOST_Window : public GHOST_IWindow { /** \copydoc #GHOST_IWindow::getDrawingContext */ GHOST_IContext *getDrawingContext() override; + /** \copydoc #GHOST_IWindow::swapBufferAcquire */ + GHOST_TSuccess swapBufferAcquire() override; /** \copydoc #GHOST_IWindow::swapBuffers */ - GHOST_TSuccess swapBuffers() override; + GHOST_TSuccess swapBufferRelease() override; /** \copydoc #GHOST_IWindow::activateDrawingContext */ GHOST_TSuccess activateDrawingContext() override; diff --git a/intern/ghost/intern/GHOST_WindowNULL.hh b/intern/ghost/intern/GHOST_WindowNULL.hh index b81cf6dd8b1..06c6c898d4d 100644 --- a/intern/ghost/intern/GHOST_WindowNULL.hh +++ b/intern/ghost/intern/GHOST_WindowNULL.hh @@ -105,7 +105,7 @@ class GHOST_WindowNULL : public GHOST_Window { outX = inX; outY = inY; } - GHOST_TSuccess swapBuffers() override + GHOST_TSuccess swapBufferRelease() override { return GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_WindowWayland.cc b/intern/ghost/intern/GHOST_WindowWayland.cc index 954e812be26..db92925e72b 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.cc +++ b/intern/ghost/intern/GHOST_WindowWayland.cc @@ -2170,10 +2170,10 @@ GHOST_WindowWayland::~GHOST_WindowWayland() } #ifdef USE_EVENT_BACKGROUND_THREAD -GHOST_TSuccess GHOST_WindowWayland::swapBuffers() +GHOST_TSuccess GHOST_WindowWayland::swapBufferRelease() { GHOST_ASSERT(system_->main_thread_id == std::this_thread::get_id(), "Only from main thread!"); - return GHOST_Window::swapBuffers(); + return GHOST_Window::swapBufferRelease(); } #endif /* USE_EVENT_BACKGROUND_THREAD */ diff --git a/intern/ghost/intern/GHOST_WindowWayland.hh b/intern/ghost/intern/GHOST_WindowWayland.hh index 4aeab9e0acf..6e78fb3faae 100644 --- a/intern/ghost/intern/GHOST_WindowWayland.hh +++ b/intern/ghost/intern/GHOST_WindowWayland.hh @@ -85,7 +85,7 @@ class GHOST_WindowWayland : public GHOST_Window { /* Ghost API */ #ifdef USE_EVENT_BACKGROUND_THREAD - GHOST_TSuccess swapBuffers() override; /* Only for assertion. */ + GHOST_TSuccess swapBufferRelease() override; /* Only for assertion. */ #endif uint16_t getDPIHint() override; diff --git a/intern/ghost/test/gears/GHOST_C-Test.c b/intern/ghost/test/gears/GHOST_C-Test.c index 703165ed6a4..b725f8b7e4f 100644 --- a/intern/ghost/test/gears/GHOST_C-Test.c +++ b/intern/ghost/test/gears/GHOST_C-Test.c @@ -376,8 +376,9 @@ bool processEvent(GHOST_EventHandle hEvent, GHOST_TUserDataPtr user_data) break; } setViewPortGL(window2); + GHOST_SwapWindowBufferAcquire(window2); drawGL(); - GHOST_SwapWindowBuffers(window2); + GHOST_SwapWindowBufferRelease(window2); break; } default: diff --git a/intern/ghost/test/gears/GHOST_Test.cpp b/intern/ghost/test/gears/GHOST_Test.cpp index 7d8bfec7531..15f051e1c56 100644 --- a/intern/ghost/test/gears/GHOST_Test.cpp +++ b/intern/ghost/test/gears/GHOST_Test.cpp @@ -609,7 +609,7 @@ bool Application::processEvent(const GHOST_IEvent *event) RenderScene(); glPopMatrix(); } - window2->swapBuffers(); + window2->swapBufferRelease(); break; } diff --git a/intern/ghost/test/multitest/MultiTest.c b/intern/ghost/test/multitest/MultiTest.c index 50a3cb8602f..16083408ae3 100644 --- a/intern/ghost/test/multitest/MultiTest.c +++ b/intern/ghost/test/multitest/MultiTest.c @@ -141,6 +141,7 @@ static void mainwindow_log(MainWindow *mw, char *str) static void mainwindow_do_draw(MainWindow *mw) { GHOST_ActivateWindowDrawingContext(mw->win); + GHOST_SwapWindowBufferAcquire(mw->win); GPU_context_active_set(mw->gpu_context); if (mw->lmbut[0]) { @@ -154,7 +155,7 @@ static void mainwindow_do_draw(MainWindow *mw) glColor3f(0.5, 0.6, 0.8); glRecti(mw->tmouse[0] - 5, mw->tmouse[1] - 5, mw->tmouse[0] + 5, mw->tmouse[1] + 5); - GHOST_SwapWindowBuffers(mw->win); + GHOST_SwapWindowBufferRelease(mw->win); } static void mainwindow_do_reshape(MainWindow *mw) @@ -432,6 +433,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw) int sb_rect[2][2], sb_thumb[2][2]; GHOST_ActivateWindowDrawingContext(lw->win); + GHOST_SwapWindowBufferAcquire(lw->win); GPU_context_active_set(lw->gpu_context); glClearColor(1, 1, 1, 1); @@ -468,7 +470,7 @@ static void loggerwindow_do_draw(LoggerWindow *lw) BLF_draw(lw->font, line, 256); // XXX } - GHOST_SwapWindowBuffers(lw->win); + GHOST_SwapWindowBufferRelease(lw->win); immDeactivate(); } @@ -657,6 +659,7 @@ typedef struct { static void extrawindow_do_draw(ExtraWindow *ew) { GHOST_ActivateWindowDrawingContext(ew->win); + GHOST_SwapWindowBufferAcquire(eq->win); GPU_context_active_set(ew->gpu_context); glClearColor(1, 1, 1, 1); @@ -665,7 +668,7 @@ static void extrawindow_do_draw(ExtraWindow *ew) glColor3f(0.8, 0.8, 0.8); glRecti(10, 10, ew->size[0] - 10, ew->size[1] - 10); - GHOST_SwapWindowBuffers(ew->win); + GHOST_SwapWindowBufferRelease(ew->win); } static void extrawindow_do_reshape(ExtraWindow *ew) diff --git a/source/blender/gpu/vulkan/vk_backend.cc b/source/blender/gpu/vulkan/vk_backend.cc index 9389190dc66..c82931e27a2 100644 --- a/source/blender/gpu/vulkan/vk_backend.cc +++ b/source/blender/gpu/vulkan/vk_backend.cc @@ -589,8 +589,8 @@ Context *VKBackend::context_alloc(void *ghost_window, void *ghost_context) VKContext *context = new VKContext(ghost_window, ghost_context); device.context_register(*context); GHOST_SetVulkanSwapBuffersCallbacks((GHOST_ContextHandle)ghost_context, - VKContext::swap_buffers_pre_callback, - VKContext::swap_buffers_post_callback, + VKContext::swap_buffer_draw_callback, + VKContext::swap_buffer_acquired_callback, VKContext::openxr_acquire_framebuffer_image_callback, VKContext::openxr_release_framebuffer_image_callback); diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index 8947f41ef38..3a72e700882 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -348,21 +348,26 @@ render_graph::VKResourceAccessInfo &VKContext::reset_and_get_access_info() /** \name Graphics pipeline * \{ */ -void VKContext::swap_buffers_pre_callback(const GHOST_VulkanSwapChainData *swap_chain_data) +void VKContext::swap_buffer_acquired_callback() { VKContext *context = VKContext::get(); BLI_assert(context); - context->swap_buffers_pre_handler(*swap_chain_data); + context->swap_buffer_acquired_handler(); } -void VKContext::swap_buffers_post_callback() +void VKContext::swap_buffer_draw_callback(const GHOST_VulkanSwapChainData *swap_chain_data) { VKContext *context = VKContext::get(); BLI_assert(context); - context->swap_buffers_post_handler(); + context->swap_buffer_draw_handler(*swap_chain_data); } -void VKContext::swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &swap_chain_data) +void VKContext::swap_buffer_acquired_handler() +{ + sync_backbuffer(); +} + +void VKContext::swap_buffer_draw_handler(const GHOST_VulkanSwapChainData &swap_chain_data) { const bool do_blit_to_swapchain = swap_chain_data.image != VK_NULL_HANDLE; const bool use_shader = swap_chain_data.surface_format.colorSpace == @@ -445,11 +450,6 @@ void VKContext::swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &swap_c #endif } -void VKContext::swap_buffers_post_handler() -{ - sync_backbuffer(); -} - void VKContext::specialization_constants_set( const shader::SpecializationConstants *constants_state) { diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index bce610762ce..5de362dbf90 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -148,16 +148,16 @@ class VKContext : public Context, NonCopyable { VKDescriptorSetTracker &descriptor_set_get(); VKStateManager &state_manager_get() const; - static void swap_buffers_pre_callback(const GHOST_VulkanSwapChainData *data); - static void swap_buffers_post_callback(); + static void swap_buffer_draw_callback(const GHOST_VulkanSwapChainData *data); + static void swap_buffer_acquired_callback(); static void openxr_acquire_framebuffer_image_callback(GHOST_VulkanOpenXRData *data); static void openxr_release_framebuffer_image_callback(GHOST_VulkanOpenXRData *data); void specialization_constants_set(const shader::SpecializationConstants *constants_state); private: - void swap_buffers_pre_handler(const GHOST_VulkanSwapChainData &data); - void swap_buffers_post_handler(); + void swap_buffer_draw_handler(const GHOST_VulkanSwapChainData &data); + void swap_buffer_acquired_handler(); void openxr_acquire_framebuffer_image_handler(GHOST_VulkanOpenXRData &data); void openxr_release_framebuffer_image_handler(GHOST_VulkanOpenXRData &data); diff --git a/source/blender/windowmanager/intern/wm_draw.cc b/source/blender/windowmanager/intern/wm_draw.cc index 3bcd4821493..dba7aa1603d 100644 --- a/source/blender/windowmanager/intern/wm_draw.cc +++ b/source/blender/windowmanager/intern/wm_draw.cc @@ -1645,6 +1645,7 @@ void wm_draw_update(bContext *C) if (wm_draw_update_test_window(bmain, C, win)) { /* Sets context window+screen. */ wm_window_make_drawable(wm, win); + wm_window_swap_buffer_acquire(win); /* Notifiers for screen redraw. */ ED_screen_ensure_updated(C, wm, win); @@ -1652,7 +1653,7 @@ void wm_draw_update(bContext *C) wm_draw_window(C, win); wm_draw_update_clear_window(C, win); - wm_window_swap_buffers(win); + wm_window_swap_buffer_release(win); } } diff --git a/source/blender/windowmanager/intern/wm_playanim.cc b/source/blender/windowmanager/intern/wm_playanim.cc index a6b7b68fafd..d588fa503c1 100644 --- a/source/blender/windowmanager/intern/wm_playanim.cc +++ b/source/blender/windowmanager/intern/wm_playanim.cc @@ -676,7 +676,9 @@ static void playanim_toscreen_ex(GhostData &ghost_data, GHOST_ActivateWindowDrawingContext(ghost_data.window); GPU_render_begin(); + GHOST_SwapWindowBufferAcquire(ghost_data.window); GPUContext *restore_context = GPU_context_active_get(); + GPU_context_active_set(ghost_data.gpu_context); GPU_context_begin_frame(ghost_data.gpu_context); @@ -787,7 +789,7 @@ static void playanim_toscreen_ex(GhostData &ghost_data, } GPU_context_end_frame(ghost_data.gpu_context); - GHOST_SwapWindowBuffers(ghost_data.window); + GHOST_SwapWindowBufferRelease(ghost_data.window); GPU_context_active_set(restore_context); GPU_render_end(); } @@ -1921,6 +1923,7 @@ static std::optional wm_main_playanim_intern(int argc, const char **argv, P ps.display_ctx.size = ps.ibuf_size; + GHOST_SwapWindowBufferAcquire(ps.ghost_data.window); GPU_render_begin(); GPU_render_step(); GPU_clear_color(0.1f, 0.1f, 0.1f, 0.0f); @@ -1932,7 +1935,7 @@ static std::optional wm_main_playanim_intern(int argc, const char **argv, P playanim_gpu_matrix(); } - GHOST_SwapWindowBuffers(ps.ghost_data.window); + GHOST_SwapWindowBufferRelease(ps.ghost_data.window); GPU_render_end(); /* One of the frames was invalid or not passed in. */ diff --git a/source/blender/windowmanager/intern/wm_window.cc b/source/blender/windowmanager/intern/wm_window.cc index 0de9e585a37..976b37d7fc8 100644 --- a/source/blender/windowmanager/intern/wm_window.cc +++ b/source/blender/windowmanager/intern/wm_window.cc @@ -1005,12 +1005,13 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, UI_GetThemeColor3fv(TH_BACK, window_bg_color); /* Until screens get drawn, draw a default background using the window theme color. */ + wm_window_swap_buffer_acquire(win); GPU_clear_color(window_bg_color[0], window_bg_color[1], window_bg_color[2], 1.0f); /* Needed here, because it's used before it reads #UserDef. */ WM_window_dpi_set_userdef(win); - wm_window_swap_buffers(win); + wm_window_swap_buffer_release(win); /* Clear double buffer to avoids flickering of new windows on certain drivers, see #97600. */ GPU_clear_color(window_bg_color[0], window_bg_color[1], window_bg_color[2], 1.0f); @@ -1768,7 +1769,7 @@ static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr C #if 0 /* NOTE(@ideasman42): Ideally we could swap-buffers to avoid a full redraw. * however this causes window flickering on resize with LIBDECOR under WAYLAND. */ - wm_window_swap_buffers(win); + wm_window_swap_buffer_release(win); #else WM_event_add_notifier_ex(wm, win, NC_WINDOW, nullptr); #endif @@ -2725,9 +2726,14 @@ void wm_window_raise(wmWindow *win) /** \name Window Buffers * \{ */ -void wm_window_swap_buffers(wmWindow *win) +void wm_window_swap_buffer_acquire(wmWindow *win) { - GHOST_SwapWindowBuffers(static_cast(win->ghostwin)); + GHOST_SwapWindowBufferAcquire(static_cast(win->ghostwin)); +} + +void wm_window_swap_buffer_release(wmWindow *win) +{ + GHOST_SwapWindowBufferRelease(static_cast(win->ghostwin)); } void wm_window_set_swap_interval(wmWindow *win, int interval) diff --git a/source/blender/windowmanager/wm_window.hh b/source/blender/windowmanager/wm_window.hh index b86f4c13c5f..7fde735addd 100644 --- a/source/blender/windowmanager/wm_window.hh +++ b/source/blender/windowmanager/wm_window.hh @@ -100,7 +100,8 @@ void wm_window_set_size(wmWindow *win, int width, int height); /** * \brief Push rendered buffer to the screen. */ -void wm_window_swap_buffers(wmWindow *win); +void wm_window_swap_buffer_acquire(wmWindow *win); +void wm_window_swap_buffer_release(wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *r_interval);