From 6b00443bc1c8379794f82f07636bed05499c2779 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 15 Jan 2021 21:37:17 -0300 Subject: [PATCH] vk_texture_cache: Support image store on sRGB images with VkImageViewUsageCreateInfo Vulkan 1.0 didn't support creating sRGB image views on an ABGR8 VkImage with storage usage bits. VK_KHR_maintenance2 addressed this allowing to reduce the usage bits on a VkImageView. To allow image store on non-sRGB image views when the VkImage is created with sRGB, always create VkImages without sRGB and add the sRGB format on the view. --- .../renderer_vulkan/maxwell_to_vk.cpp | 27 ++++--- .../renderer_vulkan/maxwell_to_vk.h | 10 ++- .../renderer_vulkan/vk_texture_cache.cpp | 73 ++++++++++++------- 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index ca7c2c579..b4473f194 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp @@ -110,8 +110,8 @@ VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_ } // namespace Sampler namespace { - -enum : u32 { Attachable = 1, Storage = 2 }; +constexpr u32 Attachable = 1 << 0; +constexpr u32 Storage = 1 << 1; struct FormatTuple { VkFormat format; ///< Vulkan format @@ -222,22 +222,27 @@ constexpr bool IsZetaFormat(PixelFormat pixel_format) { } // Anonymous namespace -FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format) { - ASSERT(static_cast(pixel_format) < std::size(tex_format_tuples)); - - auto tuple = tex_format_tuples[static_cast(pixel_format)]; +FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with_srgb, + PixelFormat pixel_format) { + ASSERT(static_cast(pixel_format) < std::size(tex_format_tuples)); + FormatTuple tuple = tex_format_tuples[static_cast(pixel_format)]; if (tuple.format == VK_FORMAT_UNDEFINED) { UNIMPLEMENTED_MSG("Unimplemented texture format with pixel format={}", pixel_format); - return {VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; + return FormatInfo{VK_FORMAT_A8B8G8R8_UNORM_PACK32, true, true}; } // Use A8B8G8R8_UNORM on hardware that doesn't support ASTC natively if (!device.IsOptimalAstcSupported() && VideoCore::Surface::IsPixelFormatASTC(pixel_format)) { - const bool is_srgb = VideoCore::Surface::IsPixelFormatSRGB(pixel_format); - tuple.format = is_srgb ? VK_FORMAT_A8B8G8R8_SRGB_PACK32 : VK_FORMAT_A8B8G8R8_UNORM_PACK32; + const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format); + if (is_srgb) { + tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32; + } else { + tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32; + tuple.usage |= Storage; + } } - const bool attachable = tuple.usage & Attachable; - const bool storage = tuple.usage & Storage; + const bool attachable = (tuple.usage & Attachable) != 0; + const bool storage = (tuple.usage & Storage) != 0; VkFormatFeatureFlags usage{}; switch (format_type) { diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.h b/src/video_core/renderer_vulkan/maxwell_to_vk.h index 537969840..e59e6b6e2 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.h +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.h @@ -35,7 +35,15 @@ struct FormatInfo { bool storage; }; -FormatInfo SurfaceFormat(const Device& device, FormatType format_type, PixelFormat pixel_format); +/** + * Returns format properties supported in the host + * @param device Host device + * @param format_type Type of image the buffer will use + * @param with_srgb True when the format can be sRGB when converted to another format (ASTC) + * @param pixel_format Guest pixel format to describe + */ +[[nodiscard]] FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with_srgb, + PixelFormat pixel_format); VkShaderStageFlagBits ShaderStage(Tegra::Engines::ShaderType stage); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index bd11de012..0f9e93e48 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -95,20 +95,12 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { } } -[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { - const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, info.format); - VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; - if (info.type == ImageType::e2D && info.resources.layers >= 6 && - info.size.width == info.size.height) { - flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - } - if (info.type == ImageType::e3D) { - flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; - } +[[nodiscard]] VkImageUsageFlags ImageUsageFlags(const MaxwellToVK::FormatInfo& info, + PixelFormat format) { VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - if (format_info.attachable) { - switch (VideoCore::Surface::GetFormatType(info.format)) { + if (info.attachable) { + switch (VideoCore::Surface::GetFormatType(format)) { case VideoCore::Surface::SurfaceType::ColorTexture: usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; break; @@ -120,9 +112,33 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { UNREACHABLE_MSG("Invalid surface type"); } } - if (format_info.storage) { + if (info.storage) { usage |= VK_IMAGE_USAGE_STORAGE_BIT; } + return usage; +} + +/// Returns the preferred format for a VkImage +[[nodiscard]] PixelFormat StorageFormat(PixelFormat format) { + switch (format) { + case PixelFormat::A8B8G8R8_SRGB: + return PixelFormat::A8B8G8R8_UNORM; + default: + return format; + } +} + +[[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info) { + const PixelFormat format = StorageFormat(info.format); + const auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, format); + VkImageCreateFlags flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + if (info.type == ImageType::e2D && info.resources.layers >= 6 && + info.size.width == info.size.height) { + flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } + if (info.type == ImageType::e3D) { + flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + } const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); return VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, @@ -130,17 +146,16 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { .flags = flags, .imageType = ConvertImageType(info.type), .format = format_info.format, - .extent = - { - .width = info.size.width >> samples_x, - .height = info.size.height >> samples_y, - .depth = info.size.depth, - }, + .extent{ + .width = info.size.width >> samples_x, + .height = info.size.height >> samples_y, + .depth = info.size.depth, + }, .mipLevels = static_cast(info.resources.levels), .arrayLayers = static_cast(info.resources.layers), .samples = ConvertSampleCount(info.num_samples), .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = usage, + .usage = ImageUsageFlags(format_info, format), .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -209,10 +224,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { [[nodiscard]] VkAttachmentDescription AttachmentDescription(const Device& device, const ImageView* image_view) { - const auto pixel_format = image_view->format; + using MaxwellToVK::SurfaceFormat; + const PixelFormat pixel_format = image_view->format; return VkAttachmentDescription{ .flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, - .format = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, pixel_format).format, + .format = SurfaceFormat(device, FormatType::Optimal, true, pixel_format).format, .samples = image_view->Samples(), .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, .storeOp = VK_ATTACHMENT_STORE_OP_STORE, @@ -860,11 +876,16 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI std::ranges::transform(swizzle, swizzle.begin(), ConvertGreenRed); } } - const VkFormat vk_format = - MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format; + const auto format_info = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format); + const VkFormat vk_format = format_info.format; + const VkImageViewUsageCreateInfo image_view_usage{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + .pNext = nullptr, + .usage = ImageUsageFlags(format_info, format), + }; const VkImageViewCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = nullptr, + .pNext = &image_view_usage, .flags = 0, .image = image.Handle(), .viewType = VkImageViewType{}, @@ -954,7 +975,7 @@ vk::ImageView ImageView::MakeDepthStencilView(VkImageAspectFlags aspect_mask) { .flags = 0, .image = image_handle, .viewType = ImageViewType(type), - .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, format).format, + .format = MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, format).format, .components{ .r = VK_COMPONENT_SWIZZLE_IDENTITY, .g = VK_COMPONENT_SWIZZLE_IDENTITY,