diff --git a/src/util/vulkan_device.cpp b/src/util/vulkan_device.cpp index 0891c7960..8b42ce090 100644 --- a/src/util/vulkan_device.cpp +++ b/src/util/vulkan_device.cpp @@ -272,8 +272,12 @@ 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 = + oe->vk_khr_get_surface_capabilities2 = (wi.type != WindowInfo::Type::Surfaceless && + SupportsExtension(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, false)); + oe->vk_ext_surface_maintenance1 = (wi.type != WindowInfo::Type::Surfaceless && SupportsExtension(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, false)); + oe->vk_ext_swapchain_maintenance1 = (wi.type != WindowInfo::Type::Surfaceless && + SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false)); oe->vk_khr_get_physical_device_properties2 = SupportsExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, false); @@ -468,8 +472,7 @@ 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); + enable_surface && SupportsExtension(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, false); // Dynamic rendering isn't strictly needed for FSI, but we want it with framebufferless rendering. m_optional_extensions.vk_ext_fragment_shader_interlock = @@ -797,16 +800,19 @@ void VulkanDevice::ProcessDeviceExtensions() #define LOG_EXT(name, field) INFO_LOG(name " is {}", m_optional_extensions.field ? "supported" : "NOT supported") LOG_EXT("VK_EXT_external_memory_host", vk_ext_external_memory_host); - LOG_EXT("VK_EXT_memory_budget", vk_ext_memory_budget); LOG_EXT("VK_EXT_fragment_shader_interlock", vk_ext_fragment_shader_interlock); + LOG_EXT("VK_EXT_memory_budget", vk_ext_memory_budget); LOG_EXT("VK_EXT_rasterization_order_attachment_access", vk_ext_rasterization_order_attachment_access); + LOG_EXT("VK_EXT_surface_maintenance1", vk_ext_surface_maintenance1); LOG_EXT("VK_EXT_swapchain_maintenance1", vk_ext_swapchain_maintenance1); LOG_EXT("VK_KHR_get_memory_requirements2", vk_khr_get_memory_requirements2); LOG_EXT("VK_KHR_bind_memory2", vk_khr_bind_memory2); LOG_EXT("VK_KHR_get_physical_device_properties2", vk_khr_get_physical_device_properties2); LOG_EXT("VK_KHR_dedicated_allocation", vk_khr_dedicated_allocation); + LOG_EXT("VK_KHR_driver_properties", vk_khr_driver_properties); LOG_EXT("VK_KHR_dynamic_rendering", vk_khr_dynamic_rendering); LOG_EXT("VK_KHR_dynamic_rendering_local_read", vk_khr_dynamic_rendering_local_read); + LOG_EXT("VK_KHR_get_surface_capabilities2", vk_khr_get_surface_capabilities2); LOG_EXT("VK_KHR_maintenance4", vk_khr_maintenance4); LOG_EXT("VK_KHR_maintenance5", vk_khr_maintenance5); LOG_EXT("VK_KHR_push_descriptor", vk_khr_push_descriptor); diff --git a/src/util/vulkan_device.h b/src/util/vulkan_device.h index e32d7496a..af36288f8 100644 --- a/src/util/vulkan_device.h +++ b/src/util/vulkan_device.h @@ -47,6 +47,7 @@ public: bool vk_ext_full_screen_exclusive : 1; bool vk_ext_memory_budget : 1; bool vk_ext_rasterization_order_attachment_access : 1; + bool vk_ext_surface_maintenance1 : 1; bool vk_ext_swapchain_maintenance1 : 1; bool vk_khr_get_memory_requirements2 : 1; bool vk_khr_bind_memory2 : 1; @@ -55,6 +56,7 @@ public: bool vk_khr_driver_properties : 1; bool vk_khr_dynamic_rendering : 1; bool vk_khr_dynamic_rendering_local_read : 1; + bool vk_khr_get_surface_capabilities2 : 1; bool vk_khr_maintenance4 : 1; bool vk_khr_maintenance5 : 1; bool vk_khr_push_descriptor : 1; diff --git a/src/util/vulkan_swap_chain.cpp b/src/util/vulkan_swap_chain.cpp index 52fea0072..80a2e45e0 100644 --- a/src/util/vulkan_swap_chain.cpp +++ b/src/util/vulkan_swap_chain.cpp @@ -321,25 +321,48 @@ bool VulkanSwapChain::CreateSwapChain(VulkanDevice& dev, Error* error) return false; // Look up surface properties to determine image count and dimensions - VkSurfaceCapabilitiesKHR surface_capabilities; - VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physdev, m_surface, &surface_capabilities); + VkSurfaceCapabilities2KHR surface_caps = { + .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR, .pNext = nullptr, .surfaceCapabilities = {}}; + VkResult res = VK_NOT_READY; + + // The present mode can alter the number of images required. Use VK_KHR_get_surface_capabilities2 to confirm it. + if (dev.GetOptionalExtensions().vk_khr_get_surface_capabilities2 && + dev.GetOptionalExtensions().vk_ext_surface_maintenance1) + { + VkPhysicalDeviceSurfaceInfo2KHR dsi = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, .pNext = nullptr, .surface = m_surface}; + VkSurfacePresentModeEXT dsi_pm = { + .sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT, .pNext = nullptr, .presentMode = present_mode.value()}; + Vulkan::AddPointerToChain(&dsi, &dsi_pm); + res = vkGetPhysicalDeviceSurfaceCapabilities2KHR(physdev, &dsi, &surface_caps); + if (res != VK_SUCCESS) + LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceCapabilities2KHR() failed: "); + } + if (res != VK_SUCCESS) { - Vulkan::SetErrorObject(error, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: ", res); - return false; + DEV_LOG("VK_EXT_surface_maintenance1 not supported, image count may be sub-optimal."); + + res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physdev, m_surface, &surface_caps.surfaceCapabilities); + if (res != VK_SUCCESS) + { + Vulkan::SetErrorObject(error, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: ", res); + return false; + } } // Select number of images in swap chain, we prefer one buffer in the background to work on in triple-buffered mode. // maxImageCount can be zero, in which case there isn't an upper limit on the number of buffers. u32 image_count = std::clamp( - (present_mode.value() == VK_PRESENT_MODE_MAILBOX_KHR) ? 3 : 2, surface_capabilities.minImageCount, - (surface_capabilities.maxImageCount == 0) ? std::numeric_limits::max() : surface_capabilities.maxImageCount); + (present_mode.value() == VK_PRESENT_MODE_MAILBOX_KHR) ? 3 : 2, surface_caps.surfaceCapabilities.minImageCount, + (surface_caps.surfaceCapabilities.maxImageCount == 0) ? std::numeric_limits::max() : + surface_caps.surfaceCapabilities.maxImageCount); DEV_LOG("Creating a swap chain with {} images in present mode {}", image_count, PresentModeToString(present_mode.value())); // Determine the dimensions of the swap chain. Values of -1 indicate the size we specify here // determines window size? Android sometimes lags updating currentExtent, so don't use it. - VkExtent2D size = surface_capabilities.currentExtent; + VkExtent2D size = surface_caps.surfaceCapabilities.currentExtent; #ifndef __ANDROID__ if (size.width == UINT32_MAX) #endif @@ -347,27 +370,27 @@ bool VulkanSwapChain::CreateSwapChain(VulkanDevice& dev, Error* error) size.width = m_window_info.surface_width; size.height = m_window_info.surface_height; } - size.width = - std::clamp(size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width); - size.height = - std::clamp(size.height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height); + size.width = std::clamp(size.width, surface_caps.surfaceCapabilities.minImageExtent.width, + surface_caps.surfaceCapabilities.maxImageExtent.width); + size.height = std::clamp(size.height, surface_caps.surfaceCapabilities.minImageExtent.height, + surface_caps.surfaceCapabilities.maxImageExtent.height); // Prefer identity transform if possible VkSurfaceTransformFlagBitsKHR transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - if (!(surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) - transform = surface_capabilities.currentTransform; + if (!(surface_caps.surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) + transform = surface_caps.surfaceCapabilities.currentTransform; VkCompositeAlphaFlagBitsKHR alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - if (!(surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) + if (!(surface_caps.surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) { // If we only support pre-multiplied/post-multiplied... :/ - if (surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + if (surface_caps.surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) alpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; } // Select swap chain flags, we only need a colour attachment VkImageUsageFlags image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - if ((surface_capabilities.supportedUsageFlags & image_usage) != image_usage) + if ((surface_caps.surfaceCapabilities.supportedUsageFlags & image_usage) != image_usage) { Error::SetStringView(error, "Swap chain does not support usage as color attachment"); return false;