VulkanDevice: Select advertised surface format pairs

Return complete VkSurfaceFormatKHR entries from the surface query, preserve
color spaces, and only choose an arbitrary format for the single
undefined-format case.
pull/3782/head
Stenzek 2 months ago
parent 8462365389
commit 5f40f0ac1b
No known key found for this signature in database

@ -20,27 +20,6 @@
LOG_CHANNEL(GPUDevice);
static VkFormat GetLinearFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R8_SRGB:
return VK_FORMAT_R8_UNORM;
case VK_FORMAT_R8G8_SRGB:
return VK_FORMAT_R8G8_UNORM;
case VK_FORMAT_R8G8B8_SRGB:
return VK_FORMAT_R8G8B8_UNORM;
case VK_FORMAT_R8G8B8A8_SRGB:
return VK_FORMAT_R8G8B8A8_UNORM;
case VK_FORMAT_B8G8R8_SRGB:
return VK_FORMAT_B8G8R8_UNORM;
case VK_FORMAT_B8G8R8A8_SRGB:
return VK_FORMAT_B8G8R8A8_UNORM;
default:
return format;
}
}
static const char* PresentModeToString(VkPresentModeKHR mode)
{
switch (mode)
@ -219,23 +198,31 @@ std::optional<VkSurfaceFormatKHR> VulkanSwapChain::SelectSurfaceFormat(VkPhysica
std::vector<VkSurfaceFormatKHR> surface_formats(format_count);
res = vkGetPhysicalDeviceSurfaceFormatsKHR(physdev, m_surface, &format_count, surface_formats.data());
Assert(res == VK_SUCCESS);
if (res != VK_SUCCESS)
{
Vulkan::SetErrorObject(error, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: ", res);
return std::nullopt;
}
surface_formats.resize(format_count);
// If there is a single undefined surface format, the device doesn't care, so we'll just use RGBA
const auto has_format = [&surface_formats](VkFormat fmt) {
return std::any_of(surface_formats.begin(), surface_formats.end(), [fmt](const VkSurfaceFormatKHR& sf) {
return (sf.format == fmt || GetLinearFormat(sf.format) == fmt);
});
};
if (has_format(VK_FORMAT_UNDEFINED))
return VkSurfaceFormatKHR{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
// NOTE: This is prehistoric shit, Vulkan 1.1+ drivers not allowed to return UNDEFINED.
if (surface_formats.size() == 1 && surface_formats[0].format == VK_FORMAT_UNDEFINED)
return VkSurfaceFormatKHR{VK_FORMAT_R8G8B8A8_UNORM, surface_formats[0].colorSpace};
// Prefer 8-bit formats.
for (VkFormat format : {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16,
VK_FORMAT_R5G5B5A1_UNORM_PACK16})
// Prefer 8-bit formats. Fall back to an advertised sRGB counterpart when no preferred linear format is available.
for (const VkFormat format : {VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16,
VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB})
{
if (has_format(format))
return VkSurfaceFormatKHR{format, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};
const auto it =
std::ranges::find_if(surface_formats, [format](const VkSurfaceFormatKHR& sf) { return sf.format == format; });
if (it != surface_formats.end())
{
if (format == VK_FORMAT_R8G8B8A8_SRGB || format == VK_FORMAT_B8G8R8A8_SRGB) [[unlikely]]
WARNING_LOG("Using SRGB output format {}", static_cast<u32>(format));
return *it;
}
}
SmallString errormsg("Failed to find a suitable format for swap chain buffers. Available formats were:");

Loading…
Cancel
Save