diff options
| author | Stenzek <stenzek@users.noreply.github.com> | 2018-02-20 01:19:45 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-02-20 01:19:45 +1000 |
| commit | 93c502fef8980bf6f6db7316738857bb0818debf (patch) | |
| tree | 7e14390a62a600c8ec89ad39a77919748d6152f1 /Source/Core/VideoBackends/Vulkan/Renderer.cpp | |
| parent | 456c2f42c350e15402eea169a2cc87878327c1fc (diff) | |
| parent | 0dddaf9d7d0837a574c6e8d255bebb3947f09a0e (diff) | |
Merge pull request #6330 from stenzek/resizing
Improve handling of surface change/resize events in graphics backends
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 116 |
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(); |
