@@ -76,7 +76,7 @@ namespace Volt::RHI
7676 return 0 ;
7777 }
7878
79- inline static VkSurfaceFormatKHR ChooseSwapchainFormat (const std::span<VulkanSwapchain::SurfaceFormat> swapchainFormats, bool useHDRIfAvailable)
79+ inline static VkSurfaceFormatKHR ChooseSwapchainFormat (const std::span<VulkanSwapchain::SurfaceFormat> swapchainFormats, bool useHDRIfAvailable, ColorSpace& outColorSpace )
8080 {
8181 VT_PROFILE_FUNCTION ();
8282
@@ -154,51 +154,7 @@ namespace Volt::RHI
154154
155155 void VulkanSwapchain::BeginFrame ()
156156 {
157- VT_PROFILE_FUNCTION ();
158-
159- if (m_swapchainNeedsRebuild)
160- {
161- QuerySwapchainCapabilities ();
162- Invalidate (m_width, m_height, m_VSyncEnabled);
163- m_swapchainNeedsRebuild = false ;
164- }
165-
166- auto device = GraphicsContext::GetDevice ();
167- auto & frameData = m_perFrameInFlightData.at (m_currentFrameIndex);
168-
169- vkWaitForFences (device->GetHandle <VkDevice>(), 1 , &frameData.renderFence , VK_TRUE , UINT64_MAX );
170- vkResetFences (device->GetHandle <VkDevice>(), 1 , &frameData.renderFence );
171-
172- VkResult swapchainStatus;
173- {
174- VT_PROFILE_SCOPE (" AcquireNextImage" );
175-
176- // Reset the 'wait' of the semaphore
177- VulkanSemaphore* vkSemaphore = ResourceCast (frameData.acquireSemaphore .GetRaw ());
178- vkSemaphore->ResetWait ();
179-
180- m_swapchainMutex.lock ();
181- swapchainStatus = vkAcquireNextImageKHR (device->GetHandle <VkDevice>(), m_swapchain, 1000000000 , frameData.acquireSemaphore ->GetHandle <VkSemaphore>(), nullptr , &m_currentImageIndex);
182- m_swapchainMutex.unlock ();
183- }
184-
185- if (swapchainStatus == VK_SUCCESS || swapchainStatus == VK_SUBOPTIMAL_KHR )
186- {
187- if (m_perImageData[m_currentImageIndex].imageReference == nullptr )
188- {
189- CreateSwapchainImage (m_currentImageIndex);
190- }
191- }
192-
193- if (swapchainStatus == VK_ERROR_OUT_OF_DATE_KHR )
194- {
195- m_swapchainNeedsRebuild = true ;
196- return ;
197- }
198- else if (swapchainStatus != VK_SUCCESS && swapchainStatus != VK_SUBOPTIMAL_KHR )
199- {
200- VT_ENSURE_NO_ENTRY ();
201- }
157+ BeginFrameInternal (true );
202158 }
203159
204160 void VulkanSwapchain::Present ()
@@ -227,11 +183,6 @@ namespace Volt::RHI
227183
228184 m_commandBuffers.at (m_currentFrameIndex)->End ();
229185
230- if (m_swapchainNeedsRebuild)
231- {
232- return ;
233- }
234-
235186 PerFrameInFlightData& frameData = m_perFrameInFlightData.at (m_currentFrameIndex);
236187 PerImageData& imageData = m_perImageData.at (m_currentImageIndex);
237188
@@ -350,8 +301,17 @@ namespace Volt::RHI
350301
351302 QuerySwapchainCapabilities ();
352303
353- CreateSwapchain (width, height, enableVSync);
354- CreateSyncObjects ();
304+ VkSwapchainKHR oldSwapchain = CreateSwapchain (width, height, enableVSync);
305+
306+ if (oldSwapchain)
307+ {
308+ ReleasePreviousSwapchain (oldSwapchain);
309+ }
310+
311+ if (m_perFrameInFlightData.empty ())
312+ {
313+ CreateSyncObjects ();
314+ }
355315 CreateRenderSemaphores ();
356316 }
357317
@@ -467,7 +427,8 @@ namespace Volt::RHI
467427
468428 VT_VK_CHECK (vkGetPhysicalDeviceSurfacePresentModesKHR (physicalDevice->GetHandle <VkPhysicalDevice>(), m_surface, &presentModeCount, vkPresentModes.data ()));
469429
470- m_capabilities.presentModes .resize (presentModeCount);
430+ m_capabilities.presentModes .clear ();
431+ m_capabilities.presentModes .reserve (presentModeCount);
471432
472433 for (VkPresentModeKHR presentMode : vkPresentModes)
473434 {
@@ -486,18 +447,12 @@ namespace Volt::RHI
486447 {
487448 VT_PROFILE_FUNCTION ();
488449
489- const VkSurfaceFormatKHR surfaceFormat = Utility::ChooseSwapchainFormat (m_capabilities. surfaceFormats , m_createInfo. useHDRIfAvailable ) ;
450+ std::scoped_lock lock{ m_swapchainMutex } ;
490451
491- if (surfaceFormat.format == VK_FORMAT_R16G16B16A16_SFLOAT ||
492- surfaceFormat.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32 ||
493- surfaceFormat.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 )
494- {
495- m_isHDREnabled = true ;
496- }
497- else
498- {
499- m_isHDREnabled = false ;
500- }
452+ ColorSpace selectedColorSpace;
453+ const VkSurfaceFormatKHR surfaceFormat = Utility::ChooseSwapchainFormat (m_capabilities.surfaceFormats , m_createInfo.useHDRIfAvailable , selectedColorSpace);
454+
455+ m_isHDREnabled = Utility::IsHDRColorSpace (selectedColorSpace);
501456
502457 const VkPresentModeKHR presentMode = Utility::ChooseSwapchainPresentMode (enableVSync, m_capabilities.presentModes );
503458
@@ -508,8 +463,23 @@ namespace Volt::RHI
508463 }
509464
510465 // Make sure the requested size is within the capabilities of the swapchain
511- m_width = m_capabilities.currentExtent .width ;
512- m_height = m_capabilities.currentExtent .height ;
466+ if (m_capabilities.currentExtent .width == 0 || m_capabilities.currentExtent .height == 0 )
467+ {
468+ return nullptr ;
469+ }
470+
471+ if (m_capabilities.currentExtent .width == 0xFFFFFFFF )
472+ {
473+ m_width = width;
474+ }
475+
476+ if (m_capabilities.currentExtent .height == 0xFFFFFFFF )
477+ {
478+ m_height = m_capabilities.currentExtent .height ;
479+ }
480+
481+ m_width = std::clamp (m_width, m_capabilities.minImageExtent .width , m_capabilities.maxImageExtent .width );
482+ m_height = std::clamp (m_height, m_capabilities.minImageExtent .height , m_capabilities.maxImageExtent .height );
513483
514484 VkSwapchainKHR oldSwapchain = m_swapchain;
515485
@@ -615,7 +585,7 @@ namespace Volt::RHI
615585 auto vulkanContext = GraphicsContext::Get ().As <VulkanGraphicsContext>();
616586 VkInstance instance = vulkanContext->GetHandle <VkInstance>();
617587
618- vkCreateWin32SurfaceKHR (instance, &createInfo, VT_VULKAN_ALLOCATOR , &m_surface);
588+ VT_VK_CHECK ( vkCreateWin32SurfaceKHR (instance, &createInfo, VT_VULKAN_ALLOCATOR , &m_surface) );
619589#endif
620590 }
621591
@@ -681,4 +651,52 @@ namespace Volt::RHI
681651
682652 }, nullptr );
683653 }
654+
655+ void VulkanSwapchain::BeginFrameInternal (bool waitForFences)
656+ {
657+ VT_PROFILE_FUNCTION ();
658+
659+ auto device = GraphicsContext::GetDevice ();
660+ auto & frameData = m_perFrameInFlightData.at (m_currentFrameIndex);
661+
662+ if (waitForFences)
663+ {
664+ vkWaitForFences (device->GetHandle <VkDevice>(), 1 , &frameData.renderFence , VK_TRUE , UINT64_MAX );
665+ vkResetFences (device->GetHandle <VkDevice>(), 1 , &frameData.renderFence );
666+ }
667+
668+ VkResult swapchainStatus;
669+ {
670+ VT_PROFILE_SCOPE (" AcquireNextImage" );
671+
672+ // Reset the 'wait' of the semaphore
673+ VulkanSemaphore* vkSemaphore = ResourceCast (frameData.acquireSemaphore .GetRaw ());
674+ vkSemaphore->ResetWait ();
675+
676+ m_swapchainMutex.lock ();
677+ swapchainStatus = vkAcquireNextImageKHR (device->GetHandle <VkDevice>(), m_swapchain, 1000000000 , frameData.acquireSemaphore ->GetHandle <VkSemaphore>(), nullptr , &m_currentImageIndex);
678+ m_swapchainMutex.unlock ();
679+ }
680+
681+ if (swapchainStatus == VK_SUCCESS || swapchainStatus == VK_SUBOPTIMAL_KHR )
682+ {
683+ if (m_perImageData[m_currentImageIndex].imageReference == nullptr )
684+ {
685+ CreateSwapchainImage (m_currentImageIndex);
686+ }
687+ }
688+
689+ if (swapchainStatus == VK_ERROR_OUT_OF_DATE_KHR || swapchainStatus == VK_TIMEOUT )
690+ {
691+ Invalidate (m_width, m_height, m_VSyncEnabled);
692+
693+ // Since the fence has already been reset, we should not wait on it,
694+ // or it will wait indefinetly.
695+ BeginFrameInternal (false );
696+ }
697+ else if (swapchainStatus != VK_SUCCESS && swapchainStatus != VK_SUBOPTIMAL_KHR )
698+ {
699+ VT_ENSURE_NO_ENTRY ();
700+ }
701+ }
684702}
0 commit comments