Vulkan: Acquire/release swapchain images
`GHOST_SwapWindowBuffers` doesn't fit well when using swapchains. In that case an approach where swap chain images are acquired and released would map better. This PR introduces `GHOST_SwapWindowBufferAcquire` and `GHOST_SwapWindowBufferRelease` to be more in line with vulkan swap chains. Previous implementation would first record all GPU commands based on the last used swap chain. In case a swapchain needed to be recreated (window resize, move to other monitor) the recorded commands would not match the swap chain and could lead to artifacts. OpenGL only implements the release functions as they don't have a mechanism to acquire a swap chain image. (Need to validate with the Metal API how this is working and adapt is needed). Currently when starting blender on a HDR capable display the first frame would be based on an sRGB surface and presented on an extended RGB (or other) surface. As these don't match the first frame could be incorrect and also lead to UBs as another surface is expected. Pull Request: https://projects.blender.org/blender/blender/pulls/145728
This commit is contained in:
@@ -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 *));
|
||||
|
||||
|
||||
@@ -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<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback,
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback,
|
||||
std::function<void(void)> swap_buffer_acquired_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback) = 0;
|
||||
#endif
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<void(const GHOST_VulkanSwapChainData *)> /*swap_buffers_pre_callback*/,
|
||||
std::function<void(void)> /*swap_buffers_post_callback*/,
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> /*swap_buffer_draw_callback*/,
|
||||
std::function<void(void)> /*swap_buffer_acquired_callback*/,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> /*openxr_acquire_framebuffer_image_callback*/,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> /*openxr_release_framebuffer_image_callback*/)
|
||||
override
|
||||
|
||||
@@ -32,7 +32,7 @@ GHOST_ContextD3D::~GHOST_ContextD3D()
|
||||
device_ctx_->Release();
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextD3D::swapBuffers()
|
||||
GHOST_TSuccess GHOST_ContextD3D::swapBufferRelease()
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -73,7 +73,7 @@ GHOST_ContextGLX::~GHOST_ContextGLX()
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextGLX::swapBuffers()
|
||||
GHOST_TSuccess GHOST_ContextGLX::swapBufferRelease()
|
||||
{
|
||||
::glXSwapBuffers(display_, window_);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -138,7 +138,7 @@ GHOST_ContextMTL::~GHOST_ContextMTL()
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextMTL::swapBuffers()
|
||||
GHOST_TSuccess GHOST_ContextMTL::swapBufferRelease()
|
||||
{
|
||||
if (metal_view_) {
|
||||
metalSwapBuffers();
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "GHOST_ContextNone.hh"
|
||||
|
||||
GHOST_TSuccess GHOST_ContextNone::swapBuffers()
|
||||
GHOST_TSuccess GHOST_ContextNone::swapBufferRelease()
|
||||
{
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -61,7 +61,7 @@ GHOST_ContextSDL::~GHOST_ContextSDL()
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_ContextSDL::swapBuffers()
|
||||
GHOST_TSuccess GHOST_ContextSDL::swapBufferRelease()
|
||||
{
|
||||
SDL_GL_SwapWindow(window_);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback,
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback,
|
||||
std::function<void(void)> swap_buffer_acquired_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> 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;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#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<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback,
|
||||
std::function<void(void)> swap_buffers_post_callback,
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback,
|
||||
std::function<void(void)> swap_buffer_acquired_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback,
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> 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<void(const GHOST_VulkanSwapChainData *)> swap_buffers_pre_callback_;
|
||||
std::function<void(void)> swap_buffers_post_callback_;
|
||||
std::optional<uint32_t> acquired_swapchain_image_index_;
|
||||
|
||||
std::function<void(const GHOST_VulkanSwapChainData *)> swap_buffer_draw_callback_;
|
||||
std::function<void(void)> swap_buffer_acquired_callback_;
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_acquire_framebuffer_image_callback_;
|
||||
std::function<void(GHOST_VulkanOpenXRData *)> openxr_release_framebuffer_image_callback_;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -609,7 +609,7 @@ bool Application::processEvent(const GHOST_IEvent *event)
|
||||
RenderScene();
|
||||
glPopMatrix();
|
||||
}
|
||||
window2->swapBuffers();
|
||||
window2->swapBufferRelease();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int> 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<int> 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. */
|
||||
|
||||
@@ -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<GHOST_WindowHandle>(win->ghostwin));
|
||||
GHOST_SwapWindowBufferAcquire(static_cast<GHOST_WindowHandle>(win->ghostwin));
|
||||
}
|
||||
|
||||
void wm_window_swap_buffer_release(wmWindow *win)
|
||||
{
|
||||
GHOST_SwapWindowBufferRelease(static_cast<GHOST_WindowHandle>(win->ghostwin));
|
||||
}
|
||||
|
||||
void wm_window_set_swap_interval(wmWindow *win, int interval)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user