diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 23de4011b..aa9431cea 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -42,6 +42,10 @@ VulkanReplay::OutputWindow::OutputWindow() fresh = true; + hasDepth = false; + + failures = recreatePause = 0; + bb = VK_NULL_HANDLE; bbview = VK_NULL_HANDLE; fb = VK_NULL_HANDLE; @@ -159,6 +163,8 @@ void VulkanReplay::OutputWindow::Create(WrappedVulkan *driver, VkDevice device, VkInstance inst = driver->GetInstance(); VkPhysicalDevice phys = driver->GetPhysDev(); + hasDepth = depth; + // save the old swapchain so it isn't destroyed VkSwapchainKHR old = swap; swap = VK_NULL_HANDLE; @@ -315,14 +321,38 @@ void VulkanReplay::OutputWindow::Create(WrappedVulkan *driver, VkDevice device, vkr = vt->CreateSwapchainKHR(Unwrap(device), &swapInfo, NULL, &swap); RDCASSERTEQUAL(vkr, VK_SUCCESS); - GetResourceManager()->WrapResource(Unwrap(device), swap); - if(old != VK_NULL_HANDLE) { vt->DestroySwapchainKHR(Unwrap(device), Unwrap(old), NULL); GetResourceManager()->ReleaseWrappedResource(old); } + if(swap == VK_NULL_HANDLE) + { + RDCERR("Failed to create swapchain. %d consecutive failures!", failures); + failures++; + + // do some sort of backoff. + + // the first time, try to recreate again next frame + if(failures == 1) + recreatePause = 0; + // the next few times, wait 200 'frames' between attempts + else if(failures < 10) + recreatePause = 100; + // otherwise, only reattempt very infrequently. A resize will + // always retrigger a recreate, so ew probably don't want to + // try again + else + recreatePause = 1000; + + return; + } + + failures = 0; + + GetResourceManager()->WrapResource(Unwrap(device), swap); + vkr = vt->GetSwapchainImagesKHR(Unwrap(device), Unwrap(swap), &numImgs, NULL); RDCASSERTEQUAL(vkr, VK_SUCCESS); @@ -1034,6 +1064,11 @@ bool VulkanReplay::RenderTexture(TextureDisplay cfg) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return false; + VkClearValue clearval = {}; VkRenderPassBeginInfo rpbegin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, @@ -1435,6 +1470,11 @@ void VulkanReplay::RenderCheckerboard(Vec3f light, Vec3f dark) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -1503,6 +1543,11 @@ void VulkanReplay::RenderHighlightBox(float w, float h, float scale) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -1628,6 +1673,11 @@ void VulkanReplay::RenderMesh(uint32_t eventID, const vector &second OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -2680,15 +2730,19 @@ bool VulkanReplay::CheckResizeOutputWindow(uint64_t id) outw.height = h; if(outw.width > 0 && outw.height > 0) - { - bool depth = (outw.dsimg != VK_NULL_HANDLE); - - outw.Create(m_pDriver, m_pDriver->GetDev(), depth); - } + outw.Create(m_pDriver, m_pDriver->GetDev(), outw.hasDepth); return true; } + if(outw.swap == VK_NULL_HANDLE && outw.width > 0 && outw.height > 0) + { + if(outw.recreatePause <= 0) + outw.Create(m_pDriver, m_pDriver->GetDev(), outw.hasDepth); + else + outw.recreatePause--; + } + return false; } @@ -2703,6 +2757,11 @@ void VulkanReplay::BindOutputWindow(uint64_t id, bool depth) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + m_DebugWidth = (int32_t)outw.width; m_DebugHeight = (int32_t)outw.height; @@ -2799,6 +2858,11 @@ void VulkanReplay::ClearOutputWindowColour(uint64_t id, float col[4]) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -2844,6 +2908,11 @@ void VulkanReplay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t sten OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); @@ -2892,6 +2961,11 @@ void VulkanReplay::FlipOutputWindow(uint64_t id) OutputWindow &outw = it->second; + // if the swapchain failed to create, do nothing. We will try to recreate it + // again in CheckResizeOutputWindow (once per render 'frame') + if(outw.swap == VK_NULL_HANDLE) + return; + VkDevice dev = m_pDriver->GetDev(); VkCommandBuffer cmd = m_pDriver->GetNextCmd(); const VkLayerDispatchTable *vt = ObjDisp(dev); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index ce5e7f91c..087369c4f 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -227,6 +227,11 @@ private: uint32_t width, height; + bool hasDepth; + + int failures; + int recreatePause; + VkSurfaceKHR surface; VkSwapchainKHR swap; uint32_t numImgs;