From 328a2c1081b94bc7c3298d4c87b5145586f87c07 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 29 Jul 2026 14:41:36 -0400 Subject: [PATCH] [TEST] Adjust mutable formats usage --- .../renderer_vulkan/vk_texture_cache.cpp | 62 ++++++++++++++++--- .../renderer_vulkan/vk_texture_cache.h | 1 + 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 81a48ba48c..4b3bf536d4 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -163,6 +164,11 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { flags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; } const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); + const VkSampleCountFlagBits samples = ConvertSampleCount(info.num_samples); + VkImageUsageFlags usage = ImageUsageFlags(format_info, info.format); + if (samples != VK_SAMPLE_COUNT_1_BIT && !device.IsStorageImageMultisampleSupported()) { + usage &= ~static_cast(VK_IMAGE_USAGE_STORAGE_BIT); + } return VkImageCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, @@ -176,9 +182,9 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { }, .mipLevels = static_cast(info.resources.levels), .arrayLayers = static_cast(info.resources.layers), - .samples = ConvertSampleCount(info.num_samples), + .samples = samples, .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = ImageUsageFlags(format_info, info.format), + .usage = usage, .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, @@ -200,19 +206,27 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { .pViewFormats = view_formats.data(), }; if (view_formats.size() > 1) { - image_ci.flags |= - VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + image_ci.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; const bool has_storage_compatible_view = std::any_of(view_formats.begin(), view_formats.end(), [&device](VkFormat view_format) { return device.IsFormatSupported(view_format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, FormatType::Optimal); }); + // storageImageSampleCounts is only meaningful once shaderStorageImageMultisample is on; + // that feature is what the spec actually gates multisampled storage usage on. const bool storage_allowed_for_samples = image_ci.samples == VK_SAMPLE_COUNT_1_BIT || - (device.GetStorageImageSampleCounts() & - static_cast(image_ci.samples)) != 0; + (device.IsStorageImageMultisampleSupported() && + (device.GetStorageImageSampleCounts() & + static_cast(image_ci.samples)) != 0); if (has_storage_compatible_view && storage_allowed_for_samples) { + // Requesting a usage the image's own format cannot support is the only thing here + // that needs extended usage; views narrow their own usage on creation. + if (!device.IsFormatSupported(image_ci.format, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, + FormatType::Optimal)) { + image_ci.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; + } image_ci.usage |= VK_IMAGE_USAGE_STORAGE_BIT; } @@ -223,6 +237,25 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { return allocator.CreateImage(image_ci); } +[[nodiscard]] VkImageUsageFlags ViewUsageFlags(const Device& device, VkImageUsageFlags image_usage, + VkFormat view_format) { + static constexpr std::array, 4> CHECKS{{ + {VK_IMAGE_USAGE_SAMPLED_BIT, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT}, + {VK_IMAGE_USAGE_STORAGE_BIT, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT}, + {VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT}, + {VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT}, + }}; + VkImageUsageFlags usage = image_usage; + for (const auto& [usage_bit, feature] : CHECKS) { + if ((usage & usage_bit) != 0 && + !device.IsFormatSupported(view_format, feature, FormatType::Optimal)) { + usage &= ~usage_bit; + } + } + return usage; +} + [[nodiscard]] vk::ImageView MakeStorageView(const vk::Device& device, u32 level, VkImage image, VkFormat format) { static constexpr VkImageViewUsageCreateInfo storage_image_view_usage_create_info{ @@ -2429,7 +2462,7 @@ bool Image::NeedsScaleHelper() const { ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, ImageId image_id_, Image& image) : VideoCommon::ImageViewBase{info, image.info, image_id_, image.gpu_addr}, - device{&runtime.device}, image_handle{image.Handle()}, + device{&runtime.device}, image_handle{image.Handle()}, image_usage{image.UsageFlags()}, samples(ConvertSampleCount(image.info.num_samples)) { using Shader::TextureType; @@ -2547,6 +2580,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageV null_image = MakeImage(*device, runtime.memory_allocator, info, {}); image_handle = *null_image; + image_usage = null_image.UsageFlags(); for (u32 i = 0; i < Shader::NUM_TEXTURE_TYPES; i++) { image_views[i] = MakeView(VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_ASPECT_COLOR_BIT); } @@ -2633,9 +2667,21 @@ vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_ break; } } + // Only attach the narrowing struct when it actually drops something and still leaves a usage + // a view can be built around; otherwise keep inheriting the image's usage as before. + static constexpr VkImageUsageFlags VIEW_MEANINGFUL_USAGE = + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + const VkImageUsageFlags view_usage = ViewUsageFlags(*device, image_usage, vk_format); + const bool narrows = view_usage != image_usage && (view_usage & VIEW_MEANINGFUL_USAGE) != 0; + const VkImageViewUsageCreateInfo usage_ci{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + .pNext = nullptr, + .usage = view_usage, + }; return device->GetLogical().CreateImageView({ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = nullptr, + .pNext = narrows ? &usage_ci : nullptr, .flags = 0, .image = image_handle, .viewType = view_type, diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index dd13aee53b..7515ea05a8 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -509,6 +509,7 @@ private: vk::ImageView color_view; vk::Image null_image; VkImage image_handle = VK_NULL_HANDLE; + VkImageUsageFlags image_usage = 0; VkImageView render_target = VK_NULL_HANDLE; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; u32 buffer_size = 0;