diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index d6dfeb641..ade9f27b3 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -269,6 +269,8 @@ bool VulkanDevice::SelectInstanceExtensions(ExtensionList* extension_list, const // Needed for exclusive fullscreen control. SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false); + oe->vk_ext_swapchain_maintenance1 = + (wi.type != WindowInfo::Type::Surfaceless && SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false)); oe->vk_khr_get_physical_device_properties2 = SupportsExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); @@ -409,6 +411,9 @@ bool VulkanDevice::SelectDeviceExtensions(ExtensionList* extension_list, bool en m_optional_extensions.vk_ext_external_memory_host = SupportsExtension(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, false); + m_optional_extensions.vk_ext_swapchain_maintenance1 = + m_optional_extensions.vk_ext_swapchain_maintenance1 && + SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false); #ifdef _WIN32 m_optional_extensions.vk_ext_full_screen_exclusive = @@ -581,9 +586,13 @@ bool VulkanDevice::CreateDevice(VkSurfaceKHR surface, bool enable_validation_lay VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, nullptr, VK_TRUE}; VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR dynamic_rendering_local_read_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_TRUE}; + VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE}; if (m_optional_extensions.vk_ext_rasterization_order_attachment_access) Vulkan::AddPointerToChain(&device_info, &rasterization_order_access_feature); + if (m_optional_extensions.vk_ext_swapchain_maintenance1) + Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_feature); if (m_optional_extensions.vk_khr_dynamic_rendering) { Vulkan::AddPointerToChain(&device_info, &dynamic_rendering_feature); @@ -631,10 +640,14 @@ void VulkanDevice::ProcessDeviceExtensions() VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, nullptr, VK_FALSE}; VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR dynamic_rendering_local_read_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, nullptr, VK_FALSE}; + VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_FALSE}; // add in optional feature structs if (m_optional_extensions.vk_ext_rasterization_order_attachment_access) Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature); + if (m_optional_extensions.vk_ext_swapchain_maintenance1) + Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_feature); if (m_optional_extensions.vk_khr_dynamic_rendering) { Vulkan::AddPointerToChain(&features2, &dynamic_rendering_feature); @@ -669,6 +682,8 @@ void VulkanDevice::ProcessDeviceExtensions() // confirm we actually support it m_optional_extensions.vk_ext_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE); + m_optional_extensions.vk_ext_swapchain_maintenance1 &= + (swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE); m_optional_extensions.vk_khr_dynamic_rendering &= (dynamic_rendering_feature.dynamicRendering == VK_TRUE); m_optional_extensions.vk_khr_dynamic_rendering_local_read &= (dynamic_rendering_local_read_feature.dynamicRenderingLocalRead == VK_TRUE); @@ -700,9 +715,13 @@ void VulkanDevice::ProcessDeviceExtensions() m_optional_extensions.vk_ext_external_memory_host &= (external_memory_host_properties.minImportedHostPointerAlignment == HOST_PAGE_SIZE); + INFO_LOG("VK_EXT_external_memory_host is {}", + m_optional_extensions.vk_ext_external_memory_host ? "supported" : "NOT supported"); INFO_LOG("VK_EXT_memory_budget is {}", m_optional_extensions.vk_ext_memory_budget ? "supported" : "NOT supported"); INFO_LOG("VK_EXT_rasterization_order_attachment_access is {}", m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported"); + INFO_LOG("VK_EXT_swapchain_maintenance1 is {}", + m_optional_extensions.vk_ext_swapchain_maintenance1 ? "supported" : "NOT supported"); INFO_LOG("VK_KHR_get_memory_requirements2 is {}", m_optional_extensions.vk_khr_get_memory_requirements2 ? "supported" : "NOT supported"); INFO_LOG("VK_KHR_bind_memory2 is {}", m_optional_extensions.vk_khr_bind_memory2 ? "supported" : "NOT supported"); @@ -716,8 +735,6 @@ void VulkanDevice::ProcessDeviceExtensions() m_optional_extensions.vk_khr_dynamic_rendering_local_read ? "supported" : "NOT supported"); INFO_LOG("VK_KHR_push_descriptor is {}", m_optional_extensions.vk_khr_push_descriptor ? "supported" : "NOT supported"); - INFO_LOG("VK_EXT_external_memory_host is {}", - m_optional_extensions.vk_ext_external_memory_host ? "supported" : "NOT supported"); } bool VulkanDevice::CreateAllocator() @@ -1350,16 +1367,17 @@ void VulkanDevice::DoPresent(VulkanSwapChain* present_swap_chain) present_swap_chain->GetCurrentImageIndexPtr(), nullptr}; - present_swap_chain->ReleaseCurrentImage(); + present_swap_chain->ResetImageAcquireResult(); const VkResult res = vkQueuePresentKHR(m_present_queue, &present_info); - if (res != VK_SUCCESS) + if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) { // VK_ERROR_OUT_OF_DATE_KHR is not fatal, just means we need to recreate our swap chain. - if (res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR) + if (res == VK_ERROR_OUT_OF_DATE_KHR) + ResizeWindow(0, 0, m_window_info.surface_scale); + else LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: "); - m_last_present_failed.store(true, std::memory_order_release); return; } @@ -1521,11 +1539,6 @@ void VulkanDevice::SubmitCommandBufferAndRestartRenderPass(const char* reason) BeginRenderPass(); } -bool VulkanDevice::CheckLastPresentFail() -{ - return m_last_present_failed.exchange(false, std::memory_order_acq_rel); -} - bool VulkanDevice::CheckLastSubmitFail() { return m_last_submit_failed.load(std::memory_order_acquire); diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index b79500209..e5cdfb475 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -42,9 +42,11 @@ public: struct OptionalExtensions { + bool vk_ext_external_memory_host : 1; + bool vk_ext_full_screen_exclusive : 1; bool vk_ext_memory_budget : 1; bool vk_ext_rasterization_order_attachment_access : 1; - bool vk_ext_full_screen_exclusive : 1; + bool vk_ext_swapchain_maintenance1 : 1; bool vk_khr_get_memory_requirements2 : 1; bool vk_khr_bind_memory2 : 1; bool vk_khr_get_physical_device_properties2 : 1; @@ -54,7 +56,6 @@ public: bool vk_khr_dynamic_rendering_local_read : 1; bool vk_khr_push_descriptor : 1; bool vk_khr_shader_non_semantic_info : 1; - bool vk_ext_external_memory_host : 1; }; static GPUTexture::Format GetFormatForVkFormat(VkFormat format); @@ -318,9 +319,6 @@ private: void EndAndSubmitCommandBuffer(VulkanSwapChain* present_swap_chain, bool explicit_present, bool submit_on_thread); void MoveToNextCommandBuffer(); void WaitForPresentComplete(); - - // Was the last present submitted to the queue a failure? If so, we must recreate our swapchain. - bool CheckLastPresentFail(); bool CheckLastSubmitFail(); using ExtensionList = std::vector; @@ -415,7 +413,6 @@ private: u32 m_current_frame = 0; std::atomic_bool m_last_submit_failed{false}; - std::atomic_bool m_last_present_failed{false}; std::atomic_bool m_present_done{true}; std::mutex m_present_mutex; std::condition_variable m_present_queued_cv; diff --git a/src/util/vulkan_entry_points.inl b/src/util/vulkan_entry_points.inl index 10b262691..d313d91ed 100644 --- a/src/util/vulkan_entry_points.inl +++ b/src/util/vulkan_entry_points.inl @@ -251,5 +251,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false) // VK_EXT_external_memory_host VULKAN_DEVICE_ENTRY_POINT(vkGetMemoryHostPointerPropertiesEXT, false) +// VK_EXT_swapchain_maintenance1 +VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesEXT, false) #endif // VULKAN_DEVICE_ENTRY_POINT diff --git a/src/util/vulkan_swap_chain.cpp b/src/util/vulkan_swap_chain.cpp index 5305c8e2e..3b637a269 100644 --- a/src/util/vulkan_swap_chain.cpp +++ b/src/util/vulkan_swap_chain.cpp @@ -623,12 +623,35 @@ VkResult VulkanSwapChain::AcquireNextImage() } void VulkanSwapChain::ReleaseCurrentImage() +{ + if (!m_image_acquire_result.has_value()) + return; + + if ((m_image_acquire_result.value() == VK_SUCCESS || m_image_acquire_result.value() == VK_SUBOPTIMAL_KHR) && + VulkanDevice::GetInstance().GetOptionalExtensions().vk_ext_swapchain_maintenance1) + { + VulkanDevice::GetInstance().WaitForGPUIdle(); + + const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT, + .swapchain = m_swap_chain, + .imageIndexCount = 1, + .pImageIndices = &m_current_image}; + VkResult res = vkReleaseSwapchainImagesEXT(VulkanDevice::GetInstance().GetVulkanDevice(), &info); + if (res != VK_SUCCESS) + LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImagesEXT() failed: "); + } + + m_image_acquire_result.reset(); +} + +void VulkanSwapChain::ResetImageAcquireResult() { m_image_acquire_result.reset(); } bool VulkanSwapChain::ResizeSwapChain(u32 new_width, u32 new_height, float new_scale) { + ReleaseCurrentImage(); DestroySwapChainImages(); if (new_width != 0 && new_height != 0) @@ -657,6 +680,7 @@ bool VulkanSwapChain::SetPresentMode(VkPresentModeKHR present_mode) // Recreate the swap chain with the new present mode. VERBOSE_LOG("Recreating swap chain to change present mode."); + ReleaseCurrentImage(); DestroySwapChainImages(); if (!CreateSwapChain()) { diff --git a/src/util/vulkan_swap_chain.h b/src/util/vulkan_swap_chain.h index 02a6cc8f8..7763613fe 100644 --- a/src/util/vulkan_swap_chain.h +++ b/src/util/vulkan_swap_chain.h @@ -75,6 +75,7 @@ public: VkResult AcquireNextImage(); void ReleaseCurrentImage(); + void ResetImageAcquireResult(); bool RecreateSurface(const WindowInfo& new_wi); bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);