diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 52a21456eb..a9f1e7888c 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -206,8 +206,7 @@ bool GSDeviceVK::SelectInstanceExtensions(ExtensionList* extension_list, const W if (enable_debug_utils && !SupportsExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, false)) Console.Warning("VK: Debug report requested, but extension is not available."); - oe->vk_ext_swapchain_maintenance1 = (wi.type != WindowInfo::Type::Surfaceless && - SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false)); + oe->vk_swapchain_maintenance1 = wi.type != WindowInfo::Type::Surfaceless; // Needed for exclusive fullscreen control. SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false); @@ -411,6 +410,13 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab m_optional_extensions.vk_ext_line_rasterization = SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false); m_optional_extensions.vk_khr_driver_properties = SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false); + if (m_optional_extensions.vk_swapchain_maintenance1) + { + const bool khr_swapchain_maintenance1 = SupportsExtension(VK_KHR_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false); + m_optional_extensions.vk_swapchain_maintenance1 = khr_swapchain_maintenance1 ? khr_swapchain_maintenance1 : SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false); + m_optional_extensions.vk_swapchain_maintenance1_is_khr = khr_swapchain_maintenance1; + } + // glslang generates debug info instructions before phi nodes at the beginning of blocks when non-semantic debug info // is enabled, triggering errors by spirv-val. Gate it by an environment variable if you want source debugging until // this is fixed. @@ -420,10 +426,6 @@ bool GSDeviceVK::SelectDeviceExtensions(ExtensionList* extension_list, bool enab SupportsExtension(VK_KHR_SHADER_NON_SEMANTIC_INFO_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 = enable_surface && SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false); @@ -611,8 +613,10 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = { + VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT}; + VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR}; if (m_optional_extensions.vk_ext_provoking_vertex) { @@ -634,10 +638,18 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer attachment_feedback_loop_feature.attachmentFeedbackLoopLayout = VK_TRUE; Vulkan::AddPointerToChain(&device_info, &attachment_feedback_loop_feature); } - if (m_optional_extensions.vk_ext_swapchain_maintenance1) + if (m_optional_extensions.vk_swapchain_maintenance1) { - swapchain_maintenance1_feature.swapchainMaintenance1 = VK_TRUE; - Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_feature); + if (m_optional_extensions.vk_swapchain_maintenance1_is_khr) + { + swapchain_maintenance1_khr_feature.swapchainMaintenance1 = VK_TRUE; + Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_khr_feature); + } + else + { + swapchain_maintenance1_ext_feature.swapchainMaintenance1 = VK_TRUE; + Vulkan::AddPointerToChain(&device_info, &swapchain_maintenance1_ext_feature); + } } VkResult res = vkCreateDevice(m_physical_device, &device_info, nullptr, &m_device); @@ -704,8 +716,10 @@ bool GSDeviceVK::ProcessDeviceExtensions() VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT}; VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT}; - VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_feature = { + VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT swapchain_maintenance1_ext_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT, nullptr, VK_TRUE}; + VkPhysicalDeviceSwapchainMaintenance1FeaturesKHR swapchain_maintenance1_khr_feature = { + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_KHR, nullptr, VK_TRUE}; VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT attachment_feedback_loop_feature = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT}; @@ -718,8 +732,10 @@ bool GSDeviceVK::ProcessDeviceExtensions() Vulkan::AddPointerToChain(&features2, &rasterization_order_access_feature); if (m_optional_extensions.vk_ext_attachment_feedback_loop_layout) Vulkan::AddPointerToChain(&features2, &attachment_feedback_loop_feature); - if (m_optional_extensions.vk_ext_swapchain_maintenance1) - Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_feature); + if (m_optional_extensions.vk_swapchain_maintenance1 && m_optional_extensions.vk_swapchain_maintenance1_is_khr) + Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_khr_feature); + if (m_optional_extensions.vk_swapchain_maintenance1 && !m_optional_extensions.vk_swapchain_maintenance1_is_khr) + Vulkan::AddPointerToChain(&features2, &swapchain_maintenance1_ext_feature); // query vkGetPhysicalDeviceFeatures2(m_physical_device, &features2); @@ -794,8 +810,9 @@ bool GSDeviceVK::ProcessDeviceExtensions() m_optional_extensions.vk_ext_calibrated_timestamps = false; } - m_optional_extensions.vk_ext_swapchain_maintenance1 &= - (swapchain_maintenance1_feature.swapchainMaintenance1 == VK_TRUE); + m_optional_extensions.vk_swapchain_maintenance1 &= m_optional_extensions.vk_swapchain_maintenance1_is_khr ? + (swapchain_maintenance1_khr_feature.swapchainMaintenance1 == VK_TRUE) : + (swapchain_maintenance1_ext_feature.swapchainMaintenance1 == VK_TRUE); Console.WriteLn( "VK_EXT_provoking_vertex is %s", m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported"); @@ -805,8 +822,9 @@ bool GSDeviceVK::ProcessDeviceExtensions() m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported"); Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s", m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported"); - Console.WriteLn("VK_EXT_swapchain_maintenance1 is %s", - m_optional_extensions.vk_ext_swapchain_maintenance1 ? "supported" : "NOT supported"); + Console.WriteLn("VK_%s_swapchain_maintenance1 is %s", + m_optional_extensions.vk_swapchain_maintenance1_is_khr ? "KHR" : "EXT", + m_optional_extensions.vk_swapchain_maintenance1 ? "supported" : "NOT supported"); Console.WriteLn("VK_EXT_full_screen_exclusive is %s", m_optional_extensions.vk_ext_full_screen_exclusive ? "supported" : "NOT supported"); Console.WriteLn("VK_KHR_driver_properties is %s", diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index d696d4addd..2f40fe6c5a 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -41,7 +41,8 @@ public: bool vk_ext_rasterization_order_attachment_access : 1; bool vk_ext_full_screen_exclusive : 1; bool vk_ext_line_rasterization : 1; - bool vk_ext_swapchain_maintenance1 : 1; + bool vk_swapchain_maintenance1 : 1; + bool vk_swapchain_maintenance1_is_khr : 1; bool vk_khr_driver_properties : 1; bool vk_khr_shader_non_semantic_info : 1; bool vk_ext_attachment_feedback_loop_layout : 1; diff --git a/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl b/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl index 60a72c77ee..d203eaba2e 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl +++ b/pcsx2/GS/Renderers/Vulkan/VKEntryPoints.inl @@ -241,4 +241,7 @@ VULKAN_DEVICE_ENTRY_POINT(vkCmdPushDescriptorSetKHR, false) // VK_EXT_swapchain_maintenance1 VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesEXT, false) +// VK_KHR_swapchain_maintenance1 +VULKAN_DEVICE_ENTRY_POINT(vkReleaseSwapchainImagesKHR, false) + #endif // VULKAN_DEVICE_ENTRY_POINT diff --git a/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp index 9b9295ed3a..c50a55782e 100644 --- a/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp +++ b/pcsx2/GS/Renderers/Vulkan/VKSwapChain.cpp @@ -366,7 +366,17 @@ bool VKSwapChain::CreateSwapChain() // Store the old/current swap chain when recreating for resize // Old swap chain is destroyed regardless of whether the create call succeeds - VkSwapchainKHR old_swap_chain = m_swap_chain; + VkSwapchainKHR old_swap_chain; + // RDNA4 experences a 2s delay in the following 2-3 vkAcquireNextImageKHR calls if we pass the old swapchain to the new one. + // Instead, pass null. This requires us to have freed the old image, which we already do with the swapchain maintenance extension. + if (GSDeviceVK::GetInstance()->IsDeviceAMD() && GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1) + { + vkDestroySwapchainKHR(GSDeviceVK::GetInstance()->GetDevice(), m_swap_chain, nullptr); + old_swap_chain = VK_NULL_HANDLE; + } + else + old_swap_chain = m_swap_chain; + m_swap_chain = VK_NULL_HANDLE; // Now we can actually create the swap chain @@ -549,17 +559,29 @@ void VKSwapChain::ReleaseCurrentImage() return; if ((m_image_acquire_result.value() == VK_SUCCESS || m_image_acquire_result.value() == VK_SUBOPTIMAL_KHR) && - GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_ext_swapchain_maintenance1) + GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1) { GSDeviceVK::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(GSDeviceVK::GetInstance()->GetDevice(), &info); + VkResult res; + if (GSDeviceVK::GetInstance()->GetOptionalExtensions().vk_swapchain_maintenance1_is_khr) + { + const VkReleaseSwapchainImagesInfoKHR info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_KHR, + .swapchain = m_swap_chain, + .imageIndexCount = 1, + .pImageIndices = &m_current_image}; + res = vkReleaseSwapchainImagesKHR(GSDeviceVK::GetInstance()->GetDevice(), &info); + } + else + { + const VkReleaseSwapchainImagesInfoEXT info = {.sType = VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT, + .swapchain = m_swap_chain, + .imageIndexCount = 1, + .pImageIndices = &m_current_image}; + res = vkReleaseSwapchainImagesEXT(GSDeviceVK::GetInstance()->GetDevice(), &info); + } if (res != VK_SUCCESS) - LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImagesEXT() failed: "); + LOG_VULKAN_ERROR(res, "vkReleaseSwapchainImages() failed: "); } m_image_acquire_result.reset();