Merge pull request #13087 from TellowKrinkle/PresentSkip
VideoBackends:Vulkan: Prevent freezes during window resize on Linux
This commit is contained in:
commit
e259831bcf
|
@ -157,10 +157,11 @@ void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u
|
||||||
D3D::context->Dispatch(groups_x, groups_y, groups_z);
|
D3D::context->Dispatch(groups_x, groups_y, groups_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::BindBackbuffer(const ClearColor& clear_color)
|
bool Gfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
CheckForSwapChainChanges();
|
CheckForSwapChainChanges();
|
||||||
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
|
SetAndClearFramebuffer(m_swap_chain->GetFramebuffer(), clear_color);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::PresentBackbuffer()
|
void Gfx::PresentBackbuffer()
|
||||||
|
|
|
@ -60,7 +60,7 @@ public:
|
||||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||||
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
void PresentBackbuffer() override;
|
void PresentBackbuffer() override;
|
||||||
void SetFullscreen(bool enable_fullscreen) override;
|
void SetFullscreen(bool enable_fullscreen) override;
|
||||||
bool IsFullscreen() const override;
|
bool IsFullscreen() const override;
|
||||||
|
|
|
@ -365,10 +365,11 @@ void Gfx::DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u
|
||||||
m_dirty_bits |= DirtyState_Pipeline;
|
m_dirty_bits |= DirtyState_Pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::BindBackbuffer(const ClearColor& clear_color)
|
bool Gfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
CheckForSwapChainChanges();
|
CheckForSwapChainChanges();
|
||||||
SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(), clear_color);
|
SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(), clear_color);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Gfx::CheckForSwapChainChanges()
|
void Gfx::CheckForSwapChainChanges()
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||||
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
void PresentBackbuffer() override;
|
void PresentBackbuffer() override;
|
||||||
|
|
||||||
SurfaceInfo GetSurfaceInfo() const override;
|
SurfaceInfo GetSurfaceInfo() const override;
|
||||||
|
|
|
@ -67,7 +67,7 @@ public:
|
||||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||||
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
void PresentBackbuffer() override;
|
void PresentBackbuffer() override;
|
||||||
|
|
||||||
SurfaceInfo GetSurfaceInfo() const override;
|
SurfaceInfo GetSurfaceInfo() const override;
|
||||||
|
|
|
@ -447,7 +447,7 @@ void Metal::Gfx::DispatchComputeShader(const AbstractShader* shader, //
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
|
bool Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
|
@ -456,6 +456,7 @@ void Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
m_drawable = MRCRetain([m_layer nextDrawable]);
|
m_drawable = MRCRetain([m_layer nextDrawable]);
|
||||||
m_backbuffer->UpdateBackbufferTexture([m_drawable texture]);
|
m_backbuffer->UpdateBackbufferTexture([m_drawable texture]);
|
||||||
SetAndClearFramebuffer(m_backbuffer.get(), clear_color);
|
SetAndClearFramebuffer(m_backbuffer.get(), clear_color);
|
||||||
|
return m_drawable != nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -407,11 +407,12 @@ void OGLGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEn
|
||||||
glDepthMask(m_current_depth_state.updateenable);
|
glDepthMask(m_current_depth_state.updateenable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLGfx::BindBackbuffer(const ClearColor& clear_color)
|
bool OGLGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
CheckForSurfaceChange();
|
CheckForSurfaceChange();
|
||||||
CheckForSurfaceResize();
|
CheckForSurfaceResize();
|
||||||
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
|
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLGfx::PresentBackbuffer()
|
void OGLGfx::PresentBackbuffer()
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||||
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
void PresentBackbuffer() override;
|
void PresentBackbuffer() override;
|
||||||
|
|
||||||
void BeginUtilityDrawing() override;
|
void BeginUtilityDrawing() override;
|
||||||
|
|
|
@ -55,15 +55,16 @@ SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* dep
|
||||||
std::move(additional_color_attachments));
|
std::move(additional_color_attachments));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SWGfx::BindBackbuffer(const ClearColor& clear_color)
|
bool SWGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
// Look for framebuffer resizes
|
// Look for framebuffer resizes
|
||||||
if (!g_presenter->SurfaceResizedTestAndClear())
|
if (!g_presenter->SurfaceResizedTestAndClear())
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
GLContext* context = m_window->GetContext();
|
GLContext* context = m_window->GetContext();
|
||||||
context->Update();
|
context->Update();
|
||||||
g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight());
|
g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SWShader final : public AbstractShader
|
class SWShader final : public AbstractShader
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment,
|
||||||
std::vector<AbstractTexture*> additional_color_attachments) override;
|
std::vector<AbstractTexture*> additional_color_attachments) override;
|
||||||
|
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage, std::string_view source,
|
||||||
std::string_view name) override;
|
std::string_view name) override;
|
||||||
|
|
|
@ -300,7 +300,7 @@ void CommandBufferManager::WaitForCommandBufferCompletion(u32 index)
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
||||||
bool wait_for_completion,
|
bool wait_for_completion, bool advance_to_next_frame,
|
||||||
VkSwapchainKHR present_swap_chain,
|
VkSwapchainKHR present_swap_chain,
|
||||||
uint32_t present_image_index)
|
uint32_t present_image_index)
|
||||||
{
|
{
|
||||||
|
@ -334,7 +334,7 @@ void CommandBufferManager::SubmitCommandBuffer(bool submit_on_worker_thread,
|
||||||
WaitForCommandBufferCompletion(m_current_cmd_buffer);
|
WaitForCommandBufferCompletion(m_current_cmd_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (present_swap_chain != VK_NULL_HANDLE)
|
if (advance_to_next_frame)
|
||||||
{
|
{
|
||||||
m_current_frame = (m_current_frame + 1) % NUM_FRAMES_IN_FLIGHT;
|
m_current_frame = (m_current_frame + 1) % NUM_FRAMES_IN_FLIGHT;
|
||||||
|
|
||||||
|
|
|
@ -63,11 +63,18 @@ public:
|
||||||
|
|
||||||
// Returns the semaphore for the current command buffer, which can be used to ensure the
|
// Returns the semaphore for the current command buffer, which can be used to ensure the
|
||||||
// swap chain image is ready before the command buffer executes.
|
// swap chain image is ready before the command buffer executes.
|
||||||
|
// Once you've confirmed that the semaphore will be signalled this frame, call
|
||||||
|
// `MarkCurrentCommandBufferSemaphoreUsed`.
|
||||||
VkSemaphore GetCurrentCommandBufferSemaphore()
|
VkSemaphore GetCurrentCommandBufferSemaphore()
|
||||||
{
|
{
|
||||||
auto& resources = m_command_buffers[m_current_cmd_buffer];
|
return m_command_buffers[m_current_cmd_buffer].semaphore;
|
||||||
resources.semaphore_used = true;
|
}
|
||||||
return resources.semaphore;
|
|
||||||
|
// Marks the current command buffer's semaphore as used, so we'll wait on it in the next
|
||||||
|
// command buffer submission.
|
||||||
|
void MarkCurrentCommandBufferSemaphoreUsed()
|
||||||
|
{
|
||||||
|
m_command_buffers[m_current_cmd_buffer].semaphore_used = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the worker thread has submitted any previous command buffers and is idle.
|
// Ensure that the worker thread has submitted any previous command buffers and is idle.
|
||||||
|
@ -78,6 +85,7 @@ public:
|
||||||
void WaitForFenceCounter(u64 fence_counter);
|
void WaitForFenceCounter(u64 fence_counter);
|
||||||
|
|
||||||
void SubmitCommandBuffer(bool submit_on_worker_thread, bool wait_for_completion,
|
void SubmitCommandBuffer(bool submit_on_worker_thread, bool wait_for_completion,
|
||||||
|
bool advance_to_next_frame = false,
|
||||||
VkSwapchainKHR present_swap_chain = VK_NULL_HANDLE,
|
VkSwapchainKHR present_swap_chain = VK_NULL_HANDLE,
|
||||||
uint32_t present_image_index = 0xFFFFFFFF);
|
uint32_t present_image_index = 0xFFFFFFFF);
|
||||||
|
|
||||||
|
|
|
@ -221,7 +221,7 @@ void VKGfx::WaitForGPUIdle()
|
||||||
ExecuteCommandBuffer(false, true);
|
ExecuteCommandBuffer(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
bool VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
{
|
{
|
||||||
StateTracker::GetInstance()->EndRenderPass();
|
StateTracker::GetInstance()->EndRenderPass();
|
||||||
|
|
||||||
|
@ -284,9 +284,21 @@ void VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
|
|
||||||
res = m_swap_chain->AcquireNextImage();
|
res = m_swap_chain->AcquireNextImage();
|
||||||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||||
PanicAlertFmt("Failed to grab image from swap chain: {:#010X} {}", Common::ToUnderlying(res),
|
{
|
||||||
VkResultToString(res));
|
if (res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||||
|
{
|
||||||
|
INFO_LOG_FMT(VIDEO, "Swapchain still out of date, will try again next frame...");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PanicAlertFmt("Failed to grab image from swap chain: {:#010X} {}",
|
||||||
|
Common::ToUnderlying(res), VkResultToString(res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_swap_chain->IsCurrentImageValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
// Transition from undefined (or present src, but it can be substituted) to
|
// Transition from undefined (or present src, but it can be substituted) to
|
||||||
// color attachment ready for writing. These transitions must occur outside
|
// color attachment ready for writing. These transitions must occur outside
|
||||||
|
@ -296,6 +308,7 @@ void VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(),
|
SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(),
|
||||||
ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}});
|
ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}});
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VKGfx::PresentBackbuffer()
|
void VKGfx::PresentBackbuffer()
|
||||||
|
@ -303,6 +316,8 @@ void VKGfx::PresentBackbuffer()
|
||||||
// End drawing to backbuffer
|
// End drawing to backbuffer
|
||||||
StateTracker::GetInstance()->EndRenderPass();
|
StateTracker::GetInstance()->EndRenderPass();
|
||||||
|
|
||||||
|
if (m_swap_chain->IsCurrentImageValid())
|
||||||
|
{
|
||||||
// Transition the backbuffer to PRESENT_SRC to ensure all commands drawing
|
// Transition the backbuffer to PRESENT_SRC to ensure all commands drawing
|
||||||
// to it have finished before present.
|
// to it have finished before present.
|
||||||
m_swap_chain->GetCurrentTexture()->TransitionToLayout(
|
m_swap_chain->GetCurrentTexture()->TransitionToLayout(
|
||||||
|
@ -312,8 +327,13 @@ void VKGfx::PresentBackbuffer()
|
||||||
// Because this final command buffer is rendering to the swap chain, we need to wait for
|
// Because this final command buffer is rendering to the swap chain, we need to wait for
|
||||||
// the available semaphore to be signaled before executing the buffer. This final submission
|
// the available semaphore to be signaled before executing the buffer. This final submission
|
||||||
// can happen off-thread in the background while we're preparing the next frame.
|
// can happen off-thread in the background while we're preparing the next frame.
|
||||||
g_command_buffer_mgr->SubmitCommandBuffer(true, false, m_swap_chain->GetSwapChain(),
|
g_command_buffer_mgr->SubmitCommandBuffer(true, false, true, m_swap_chain->GetSwapChain(),
|
||||||
m_swap_chain->GetCurrentImageIndex());
|
m_swap_chain->GetCurrentImageIndex());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_command_buffer_mgr->SubmitCommandBuffer(true, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
// New cmdbuffer, so invalidate state.
|
// New cmdbuffer, so invalidate state.
|
||||||
StateTracker::GetInstance()->InvalidateCachedState();
|
StateTracker::GetInstance()->InvalidateCachedState();
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) override;
|
||||||
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z) override;
|
||||||
void BindBackbuffer(const ClearColor& clear_color = {}) override;
|
bool BindBackbuffer(const ClearColor& clear_color = {}) override;
|
||||||
void PresentBackbuffer() override;
|
void PresentBackbuffer() override;
|
||||||
void SetFullscreen(bool enable_fullscreen) override;
|
void SetFullscreen(bool enable_fullscreen) override;
|
||||||
bool IsFullscreen() const override;
|
bool IsFullscreen() const override;
|
||||||
|
|
|
@ -497,6 +497,9 @@ VkResult SwapChain::AcquireNextImage()
|
||||||
VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
|
VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
|
||||||
g_command_buffer_mgr->GetCurrentCommandBufferSemaphore(),
|
g_command_buffer_mgr->GetCurrentCommandBufferSemaphore(),
|
||||||
VK_NULL_HANDLE, &m_current_swap_chain_image_index);
|
VK_NULL_HANDLE, &m_current_swap_chain_image_index);
|
||||||
|
m_current_swap_chain_image_is_valid = res >= 0;
|
||||||
|
if (IsCurrentImageValid())
|
||||||
|
g_command_buffer_mgr->MarkCurrentCommandBufferSemaphoreUsed();
|
||||||
if (res != VK_SUCCESS && res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR)
|
if (res != VK_SUCCESS && res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR)
|
||||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR failed: ");
|
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR failed: ");
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
u32 GetWidth() const { return m_width; }
|
u32 GetWidth() const { return m_width; }
|
||||||
u32 GetHeight() const { return m_height; }
|
u32 GetHeight() const { return m_height; }
|
||||||
u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; }
|
u32 GetCurrentImageIndex() const { return m_current_swap_chain_image_index; }
|
||||||
|
bool IsCurrentImageValid() const { return m_current_swap_chain_image_is_valid; }
|
||||||
VkImage GetCurrentImage() const
|
VkImage GetCurrentImage() const
|
||||||
{
|
{
|
||||||
return m_swap_chain_images[m_current_swap_chain_image_index].image;
|
return m_swap_chain_images[m_current_swap_chain_image_index].image;
|
||||||
|
@ -98,6 +99,7 @@ private:
|
||||||
bool m_fullscreen_supported = false;
|
bool m_fullscreen_supported = false;
|
||||||
bool m_current_fullscreen_state = false;
|
bool m_current_fullscreen_state = false;
|
||||||
bool m_next_fullscreen_state = false;
|
bool m_next_fullscreen_state = false;
|
||||||
|
bool m_current_swap_chain_image_is_valid = false;
|
||||||
|
|
||||||
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
|
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
|
||||||
std::vector<SwapChainImage> m_swap_chain_images;
|
std::vector<SwapChainImage> m_swap_chain_images;
|
||||||
|
|
|
@ -101,7 +101,10 @@ public:
|
||||||
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
|
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
|
||||||
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
|
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
|
||||||
// m_backbuffer_height may change after this function returns.
|
// m_backbuffer_height may change after this function returns.
|
||||||
virtual void BindBackbuffer(const ClearColor& clear_color = {}) {}
|
// If this returns false, a problem occurred binding the backbuffer.
|
||||||
|
// Don't render anything to it, but still call `PresentBackbuffer`, which will reset any
|
||||||
|
// per-frame resources and prepare for the next frame.
|
||||||
|
virtual bool BindBackbuffer(const ClearColor& clear_color = {}) { return true; }
|
||||||
|
|
||||||
// Presents the backbuffer to the window system, or "swaps buffers".
|
// Presents the backbuffer to the window system, or "swaps buffers".
|
||||||
virtual void PresentBackbuffer() {}
|
virtual void PresentBackbuffer() {}
|
||||||
|
|
|
@ -844,10 +844,10 @@ void Presenter::Present()
|
||||||
UpdateDrawRectangle();
|
UpdateDrawRectangle();
|
||||||
|
|
||||||
g_gfx->BeginUtilityDrawing();
|
g_gfx->BeginUtilityDrawing();
|
||||||
g_gfx->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
|
const bool backbuffer_bound = g_gfx->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
|
||||||
|
|
||||||
// Render the XFB to the screen.
|
// Render the XFB to the screen.
|
||||||
if (m_xfb_entry)
|
if (backbuffer_bound && m_xfb_entry)
|
||||||
{
|
{
|
||||||
// Adjust the source rectangle instead of using an oversized viewport to render the XFB.
|
// Adjust the source rectangle instead of using an oversized viewport to render the XFB.
|
||||||
auto render_target_rc = GetTargetRectangle();
|
auto render_target_rc = GetTargetRectangle();
|
||||||
|
@ -860,6 +860,7 @@ void Presenter::Present()
|
||||||
if (m_onscreen_ui)
|
if (m_onscreen_ui)
|
||||||
{
|
{
|
||||||
m_onscreen_ui->Finalize();
|
m_onscreen_ui->Finalize();
|
||||||
|
if (backbuffer_bound)
|
||||||
m_onscreen_ui->DrawImGui();
|
m_onscreen_ui->DrawImGui();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue