summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/Renderer.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-01-26 16:23:24 +1000
committerStenzek <stenzek@gmail.com>2018-02-20 01:15:55 +1000
commitde632fc9c8d7d026ccad1afc2f72224ee9639023 (patch)
treecf182d393ccde05c26d3fa27bc7007e134fbadda /Source/Core/VideoBackends/Vulkan/Renderer.cpp
parent5baf3bbe2e2fb62cac9c1bb4cded45644ebfd3bb (diff)
Renderer: Handle resize events on-demand instead of polling
We now differentiate between a resize event and surface change/destroyed event, reducing the overhead for resizes in the Vulkan backend. It is also now now safe to change the surface multiple times if the video thread is lagging behind.
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp116
1 files changed, 59 insertions, 57 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
index 413f4bb750..7b65884075 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
@@ -500,6 +500,10 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
StateTracker::GetInstance()->EndRenderPass();
StateTracker::GetInstance()->OnEndFrame();
+ // Handle host window resizes.
+ CheckForSurfaceChange();
+ CheckForSurfaceResize();
+
// There are a few variables which can alter the final window draw rectangle, and some of them
// are determined by guest state. Currently, the only way to catch these is to update every frame.
UpdateDrawRectangle();
@@ -543,9 +547,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
// Determine what (if anything) has changed in the config.
CheckForConfigChanges();
- // Handle host window resizes.
- CheckForSurfaceChange();
-
// Clean up stale textures.
TextureCache::GetInstance()->Cleanup(frameCount);
@@ -650,71 +651,83 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r
void Renderer::CheckForSurfaceChange()
{
- if (!m_surface_needs_change.IsSet())
+ if (!m_surface_changed.TestAndClear())
return;
- // Wait for the GPU to catch up since we're going to destroy the swap chain.
+ m_surface_handle = m_new_surface_handle;
+ m_new_surface_handle = nullptr;
+
+ // Submit the current draws up until rendering the XFB.
+ g_command_buffer_mgr->ExecuteCommandBuffer(false, false);
g_command_buffer_mgr->WaitForGPUIdle();
// Clear the present failed flag, since we don't want to resize after recreating.
g_command_buffer_mgr->CheckLastPresentFail();
- // Fast path, if the surface handle is the same, the window has just been resized.
- if (m_swap_chain && m_new_surface_handle == m_swap_chain->GetNativeHandle())
+ // Did we previously have a swap chain?
+ if (m_swap_chain)
{
- INFO_LOG(VIDEO, "Detected window resize.");
- m_swap_chain->RecreateSwapChain();
-
- // Notify the main thread we are done.
- m_surface_needs_change.Clear();
- m_new_surface_handle = nullptr;
- m_surface_changed.Set();
+ if (!m_surface_handle)
+ {
+ // If there is no surface now, destroy the swap chain.
+ m_swap_chain.reset();
+ }
+ else
+ {
+ // Recreate the surface. If this fails we're in trouble.
+ if (!m_swap_chain->RecreateSurface(m_surface_handle))
+ PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
+ }
}
else
{
- // Did we previously have a swap chain?
- if (m_swap_chain)
+ // Previously had no swap chain. So create one.
+ VkSurfaceKHR surface =
+ SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_surface_handle);
+ if (surface != VK_NULL_HANDLE)
{
- if (!m_new_surface_handle)
- {
- // If there is no surface now, destroy the swap chain.
- m_swap_chain.reset();
- }
- else
- {
- // Recreate the surface. If this fails we're in trouble.
- if (!m_swap_chain->RecreateSurface(m_new_surface_handle))
- PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
- }
+ m_swap_chain = SwapChain::Create(m_surface_handle, surface, g_ActiveConfig.IsVSync());
+ if (!m_swap_chain)
+ PanicAlert("Failed to create swap chain.");
}
else
{
- // Previously had no swap chain. So create one.
- VkSurfaceKHR surface = SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(),
- m_new_surface_handle);
- if (surface != VK_NULL_HANDLE)
- {
- m_swap_chain = SwapChain::Create(m_new_surface_handle, surface, g_ActiveConfig.IsVSync());
- if (!m_swap_chain)
- PanicAlert("Failed to create swap chain.");
- }
- else
- {
- PanicAlert("Failed to create surface.");
- }
+ PanicAlert("Failed to create surface.");
}
-
- // Notify calling thread.
- m_surface_needs_change.Clear();
- m_surface_handle = m_new_surface_handle;
- m_new_surface_handle = nullptr;
- m_surface_changed.Set();
}
// Handle case where the dimensions are now different.
OnSwapChainResized();
}
+void Renderer::CheckForSurfaceResize()
+{
+ if (!m_surface_resized.TestAndClear())
+ return;
+
+ m_backbuffer_width = m_new_backbuffer_width;
+ m_backbuffer_height = m_new_backbuffer_height;
+
+ // If we don't have a surface, how can we resize the swap chain?
+ // CheckForSurfaceChange should handle this case.
+ if (!m_swap_chain)
+ {
+ WARN_LOG(VIDEO, "Surface resize event received without active surface, ignoring");
+ return;
+ }
+
+ // Wait for the GPU to catch up since we're going to destroy the swap chain.
+ g_command_buffer_mgr->ExecuteCommandBuffer(false, false);
+ g_command_buffer_mgr->WaitForGPUIdle();
+
+ // Clear the present failed flag, since we don't want to resize after recreating.
+ g_command_buffer_mgr->CheckLastPresentFail();
+
+ // Resize the swap chain.
+ m_swap_chain->RecreateSwapChain();
+ OnSwapChainResized();
+}
+
void Renderer::CheckForConfigChanges()
{
// Save the video config so we can compare against to determine which settings have changed.
@@ -782,9 +795,6 @@ void Renderer::OnSwapChainResized()
{
m_backbuffer_width = m_swap_chain->GetWidth();
m_backbuffer_height = m_swap_chain->GetHeight();
- UpdateDrawRectangle();
- if (CalculateTargetSize())
- RecreateEFBFramebuffer();
}
void Renderer::BindEFBToStateTracker()
@@ -914,14 +924,6 @@ void Renderer::SetViewport(float x, float y, float width, float height, float ne
StateTracker::GetInstance()->SetViewport(viewport);
}
-void Renderer::ChangeSurface(void* new_surface_handle)
-{
- // Called by the main thread when the window is resized.
- m_new_surface_handle = new_surface_handle;
- m_surface_needs_change.Set();
- m_surface_changed.Set();
-}
-
void Renderer::RecompileShaders()
{
DestroyShaders();