diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index fdd2de2379..7418ad934e 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -306,7 +306,17 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { swapchain_ci.queueFamilyIndexCount = static_cast(queue_indices.size()); swapchain_ci.pQueueFamilyIndices = queue_indices.data(); } - static constexpr std::array view_formats{VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB}; + // According to Vulkan spec, when using VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR, + // the base format (imageFormat) MUST be included in pViewFormats + const std::array view_formats{ + swapchain_ci.imageFormat, // Base format MUST be first + VK_FORMAT_B8G8R8A8_UNORM, + VK_FORMAT_B8G8R8A8_SRGB, +#ifdef ANDROID + VK_FORMAT_R8G8B8A8_UNORM, // Android may use RGBA + VK_FORMAT_R8G8B8A8_SRGB, +#endif + }; VkImageFormatListCreateInfo format_list{ .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR, .pNext = nullptr, diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 22830dff18..0c75e95549 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -1290,7 +1290,22 @@ void Device::RemoveUnsuitableExtensions() { VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME); // VK_EXT_swapchain_maintenance1 (extension only, has features) + // Requires VK_EXT_surface_maintenance1 instance extension extensions.swapchain_maintenance1 = features.swapchain_maintenance1.swapchainMaintenance1; + if (extensions.swapchain_maintenance1) { + // Check if VK_EXT_surface_maintenance1 instance extension is available + const auto instance_extensions = vk::EnumerateInstanceExtensionProperties(dld); + const bool has_surface_maintenance1 = instance_extensions && std::ranges::any_of(*instance_extensions, + [](const VkExtensionProperties& prop) { + return std::strcmp(prop.extensionName, VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) == 0; + }); + if (!has_surface_maintenance1) { + LOG_WARNING(Render_Vulkan, + "VK_EXT_swapchain_maintenance1 requires VK_EXT_surface_maintenance1, disabling"); + extensions.swapchain_maintenance1 = false; + features.swapchain_maintenance1.swapchainMaintenance1 = false; + } + } RemoveExtensionFeatureIfUnsuitable(extensions.swapchain_maintenance1, features.swapchain_maintenance1, VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index d9404933cd..bf99489373 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -87,6 +87,11 @@ namespace { AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME})) { extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } + // VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1 + if (window_type != Core::Frontend::WindowSystemType::Headless && + AreExtensionsSupported(dld, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME})) { + extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME); + } return extensions; }