Skip to content

Commit 5f08020

Browse files
Vulkan swap chain: improved handling of the out-of-date images (fix #632)
The image may be immediately out of date after it is acquired
1 parent a255d24 commit 5f08020

File tree

2 files changed

+33
-30
lines changed

2 files changed

+33
-30
lines changed

Graphics/GraphicsEngineVulkan/include/SwapChainVkImpl.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class SwapChainVkImpl final : public SwapChainBase<ISwapChainVk>
125125
uint32_t m_BackBufferIndex = 0;
126126
bool m_IsMinimized = false;
127127
bool m_VSyncEnabled = true;
128+
bool m_ImageAcquired = false;
128129
Uint32 m_FrameIndex = 1;
129130
};
130131

Graphics/GraphicsEngineVulkan/src/SwapChainVkImpl.cpp

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ SwapChainVkImpl::SwapChainVkImpl(IReferenceCounters* pRefCounters,
5454
CreateSurface();
5555
CreateVulkanSwapChain();
5656
InitBuffersAndViews();
57-
VkResult res = AcquireNextImage(pDeviceContextVk);
58-
DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the newly created swap chain");
59-
(void)res;
57+
58+
AcquireNextImage(pDeviceContextVk);
59+
// Note that the image may be immediately out of date.
6060

6161
FenceDesc FenceCI;
6262
FenceCI.Name = "Swap chain frame complete fence";
@@ -619,8 +619,9 @@ VkResult SwapChainVkImpl::AcquireNextImage(DeviceContextVkImpl* pDeviceCtxVk)
619619

620620
RefCntAutoPtr<ManagedSemaphore>& ImageAcquiredSemaphore = m_ImageAcquiredSemaphores[m_SemaphoreIndex];
621621

622-
VkResult res = vkAcquireNextImageKHR(LogicalDevice.GetVkDevice(), m_VkSwapChain, UINT64_MAX, ImageAcquiredSemaphore->Get(), VK_NULL_HANDLE, &m_BackBufferIndex);
623-
if (res == VK_SUCCESS)
622+
VkResult res = vkAcquireNextImageKHR(LogicalDevice.GetVkDevice(), m_VkSwapChain, UINT64_MAX, ImageAcquiredSemaphore->Get(), VK_NULL_HANDLE, &m_BackBufferIndex);
623+
m_ImageAcquired = (res == VK_SUCCESS || res == VK_SUBOPTIMAL_KHR);
624+
if (m_ImageAcquired)
624625
{
625626
// Next command in the device context must wait for the next image to be acquired.
626627
// Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore.
@@ -665,7 +666,7 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
665666
// a separate semaphore per swapchain image and index these semaphores using the index of the acquired image
666667
// https://github.com/DiligentGraphics/DiligentCore/issues/682
667668
RefCntAutoPtr<ManagedSemaphore>& DrawCompleteSemaphore = m_DrawCompleteSemaphores[m_BackBufferIndex];
668-
if (!m_IsMinimized)
669+
if (m_ImageAcquired && !m_IsMinimized)
669670
{
670671
// TransitionImageLayout() never triggers flush
671672
pImmediateCtxVk->TransitionImageLayout(pBackBuffer, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
@@ -679,26 +680,28 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
679680

680681
if (!m_IsMinimized)
681682
{
682-
VkPresentInfoKHR PresentInfo = {};
683-
684-
PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
685-
PresentInfo.pNext = nullptr;
686-
PresentInfo.waitSemaphoreCount = 1;
687-
// Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore
688-
VkSemaphore WaitSemaphore[] = {DrawCompleteSemaphore->Get()};
689-
PresentInfo.pWaitSemaphores = WaitSemaphore;
690-
PresentInfo.swapchainCount = 1;
691-
PresentInfo.pSwapchains = &m_VkSwapChain;
692-
PresentInfo.pImageIndices = &m_BackBufferIndex;
693-
VkResult Result = VK_SUCCESS;
694-
PresentInfo.pResults = &Result;
695-
pDeviceVk->LockCmdQueueAndRun(
696-
pImmediateCtxVk->GetCommandQueueId(),
697-
[&PresentInfo](ICommandQueueVk* pCmdQueueVk) //
698-
{
699-
pCmdQueueVk->Present(PresentInfo);
700-
} //
701-
);
683+
VkResult Result = VK_ERROR_OUT_OF_DATE_KHR;
684+
if (m_ImageAcquired)
685+
{
686+
VkPresentInfoKHR PresentInfo{};
687+
PresentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
688+
PresentInfo.pNext = nullptr;
689+
PresentInfo.waitSemaphoreCount = 1;
690+
// Unlike fences or events, the act of waiting for a semaphore also unsignals that semaphore
691+
VkSemaphore WaitSemaphore[] = {DrawCompleteSemaphore->Get()};
692+
PresentInfo.pWaitSemaphores = WaitSemaphore;
693+
PresentInfo.swapchainCount = 1;
694+
PresentInfo.pSwapchains = &m_VkSwapChain;
695+
PresentInfo.pImageIndices = &m_BackBufferIndex;
696+
PresentInfo.pResults = &Result;
697+
pDeviceVk->LockCmdQueueAndRun(
698+
pImmediateCtxVk->GetCommandQueueId(),
699+
[&PresentInfo](ICommandQueueVk* pCmdQueueVk) //
700+
{
701+
pCmdQueueVk->Present(PresentInfo);
702+
} //
703+
);
704+
}
702705

703706
if (Result == VK_SUBOPTIMAL_KHR || Result == VK_ERROR_OUT_OF_DATE_KHR)
704707
{
@@ -745,7 +748,7 @@ void SwapChainVkImpl::Present(Uint32 SyncInterval)
745748
}
746749
#endif
747750
}
748-
DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next swap chain image");
751+
// The image may still be out of date if the window keeps changing size
749752
}
750753
}
751754

@@ -919,9 +922,8 @@ void SwapChainVkImpl::Resize(Uint32 NewWidth, Uint32 NewHeight, SURFACE_TRANSFOR
919922
// RecreateVulkanSwapchain() unbinds default FB
920923
RecreateVulkanSwapchain(pImmediateCtxVk);
921924

922-
VkResult res = AcquireNextImage(pImmediateCtxVk);
923-
DEV_CHECK_ERR(res == VK_SUCCESS, "Failed to acquire next image for the just resized swap chain");
924-
(void)res;
925+
AcquireNextImage(pImmediateCtxVk);
926+
// The image may be immediately out of date if the window keeps being resized
925927
}
926928
catch (const std::runtime_error&)
927929
{

0 commit comments

Comments
 (0)