From d1eb08c03618b59fe8131481b2bd295fd1bcbd40 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 29 Jul 2026 20:49:36 -0400 Subject: [PATCH] [TEST] Change on storage views per request instead of always granted --- src/video_core/compatible_formats.cpp | 81 ++++++-- .../renderer_opengl/gl_texture_cache.h | 8 + .../renderer_vulkan/vk_compute_pipeline.cpp | 5 +- .../renderer_vulkan/vk_graphics_pipeline.cpp | 6 +- .../renderer_vulkan/vk_texture_cache.cpp | 196 +++++++++++++++++- .../renderer_vulkan/vk_texture_cache.h | 10 + src/video_core/texture_cache/texture_cache.h | 8 + .../texture_cache/texture_cache_base.h | 1 + 8 files changed, 285 insertions(+), 30 deletions(-) diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp index 87d69ebc53..f75f386cec 100644 --- a/src/video_core/compatible_formats.cpp +++ b/src/video_core/compatible_formats.cpp @@ -28,16 +28,28 @@ constexpr std::array VIEW_CLASS_96_BITS{ // PixelFormat::RGB32UI, // PixelFormat::RGB32I, -constexpr std::array VIEW_CLASS_64_BITS{ +constexpr std::array SIZE_CLASS_64_BITS{ PixelFormat::R32G32_FLOAT, PixelFormat::R32G32_UINT, PixelFormat::R32G32_SINT, PixelFormat::R16G16B16A16_FLOAT, PixelFormat::R16G16B16A16_UNORM, PixelFormat::R16G16B16A16_SNORM, PixelFormat::R16G16B16A16_UINT, PixelFormat::R16G16B16A16_SINT, }; +constexpr std::array VIEW_CLASS_RG32{ + PixelFormat::R32G32_FLOAT, + PixelFormat::R32G32_UINT, + PixelFormat::R32G32_SINT, +}; + +constexpr std::array VIEW_CLASS_RGBA16{ + PixelFormat::R16G16B16A16_FLOAT, PixelFormat::R16G16B16A16_UNORM, + PixelFormat::R16G16B16A16_SNORM, PixelFormat::R16G16B16A16_UINT, + PixelFormat::R16G16B16A16_SINT, +}; + // TODO: How should we handle 48 bits? -constexpr std::array VIEW_CLASS_32_BITS{ +constexpr std::array SIZE_CLASS_32_BITS{ PixelFormat::R16G16_FLOAT, PixelFormat::B10G11R11_FLOAT, PixelFormat::R32_FLOAT, PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT, PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM, @@ -47,23 +59,53 @@ constexpr std::array VIEW_CLASS_32_BITS{ PixelFormat::A2B10G10R10_UINT, }; -constexpr std::array VIEW_CLASS_32_BITS_NO_BGR{ - PixelFormat::R16G16_FLOAT, PixelFormat::B10G11R11_FLOAT, PixelFormat::R32_FLOAT, - PixelFormat::A2B10G10R10_UNORM, PixelFormat::R16G16_UINT, PixelFormat::R32_UINT, - PixelFormat::R16G16_SINT, PixelFormat::R32_SINT, PixelFormat::A8B8G8R8_UNORM, - PixelFormat::R16G16_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::R16G16_SNORM, - PixelFormat::A8B8G8R8_SRGB, PixelFormat::E5B9G9R9_FLOAT, PixelFormat::A8B8G8R8_UINT, - PixelFormat::A8B8G8R8_SINT, PixelFormat::A2B10G10R10_UINT, +constexpr std::array VIEW_CLASS_RGBA8{ + PixelFormat::A8B8G8R8_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::A8B8G8R8_SRGB, + PixelFormat::A8B8G8R8_UINT, PixelFormat::A8B8G8R8_SINT, +}; + +constexpr std::array VIEW_CLASS_RGBA8_NATIVE_BGR{ + PixelFormat::A8B8G8R8_UNORM, PixelFormat::A8B8G8R8_SNORM, PixelFormat::A8B8G8R8_SRGB, + PixelFormat::A8B8G8R8_UINT, PixelFormat::A8B8G8R8_SINT, PixelFormat::B8G8R8A8_UNORM, + PixelFormat::B8G8R8A8_SRGB, +}; + +constexpr std::array VIEW_CLASS_RG16{ + PixelFormat::R16G16_FLOAT, PixelFormat::R16G16_UNORM, PixelFormat::R16G16_SNORM, + PixelFormat::R16G16_UINT, PixelFormat::R16G16_SINT, +}; + +constexpr std::array VIEW_CLASS_R32{ + PixelFormat::R32_FLOAT, + PixelFormat::R32_UINT, + PixelFormat::R32_SINT, +}; + +constexpr std::array VIEW_CLASS_RGB10A2{ + PixelFormat::A2B10G10R10_UNORM, + PixelFormat::A2B10G10R10_UINT, }; // TODO: How should we handle 24 bits? -constexpr std::array VIEW_CLASS_16_BITS{ +constexpr std::array SIZE_CLASS_16_BITS{ PixelFormat::R16_FLOAT, PixelFormat::R8G8_UINT, PixelFormat::R16_UINT, PixelFormat::R16_SINT, PixelFormat::R8G8_UNORM, PixelFormat::R16_UNORM, PixelFormat::R8G8_SNORM, PixelFormat::R16_SNORM, PixelFormat::R8G8_SINT, }; +constexpr std::array VIEW_CLASS_R16{ + PixelFormat::R16_FLOAT, PixelFormat::R16_UINT, PixelFormat::R16_SINT, + PixelFormat::R16_UNORM, PixelFormat::R16_SNORM, +}; + +constexpr std::array VIEW_CLASS_RG8{ + PixelFormat::R8G8_UINT, + PixelFormat::R8G8_UNORM, + PixelFormat::R8G8_SNORM, + PixelFormat::R8G8_SINT, +}; + constexpr std::array VIEW_CLASS_8_BITS{ PixelFormat::R8_UINT, PixelFormat::R8_UNORM, @@ -215,8 +257,13 @@ constexpr Table MakeViewTable() { } EnableRange(view, VIEW_CLASS_128_BITS); EnableRange(view, VIEW_CLASS_96_BITS); - EnableRange(view, VIEW_CLASS_64_BITS); - EnableRange(view, VIEW_CLASS_16_BITS); + EnableRange(view, VIEW_CLASS_RG32); + EnableRange(view, VIEW_CLASS_RGBA16); + EnableRange(view, VIEW_CLASS_RG16); + EnableRange(view, VIEW_CLASS_R32); + EnableRange(view, VIEW_CLASS_RGB10A2); + EnableRange(view, VIEW_CLASS_R16); + EnableRange(view, VIEW_CLASS_RG8); EnableRange(view, VIEW_CLASS_8_BITS); EnableRange(view, VIEW_CLASS_RGTC1_RED); EnableRange(view, VIEW_CLASS_RGTC2_RG); @@ -242,30 +289,32 @@ constexpr Table MakeCopyTable() { Table copy = MakeViewTable(); EnableRange(copy, COPY_CLASS_128_BITS); EnableRange(copy, COPY_CLASS_64_BITS); + EnableRange(copy, SIZE_CLASS_64_BITS); + EnableRange(copy, SIZE_CLASS_16_BITS); return copy; } constexpr Table MakeNativeBgrViewTable() { Table copy = MakeViewTable(); - EnableRange(copy, VIEW_CLASS_32_BITS); + EnableRange(copy, VIEW_CLASS_RGBA8_NATIVE_BGR); return copy; } constexpr Table MakeNonNativeBgrViewTable() { Table copy = MakeViewTable(); - EnableRange(copy, VIEW_CLASS_32_BITS_NO_BGR); + EnableRange(copy, VIEW_CLASS_RGBA8); return copy; } constexpr Table MakeNativeBgrCopyTable() { Table copy = MakeCopyTable(); - EnableRange(copy, VIEW_CLASS_32_BITS); + EnableRange(copy, SIZE_CLASS_32_BITS); return copy; } constexpr Table MakeNonNativeBgrCopyTable() { Table copy = MakeCopyTable(); - EnableRange(copy, VIEW_CLASS_32_BITS); + EnableRange(copy, SIZE_CLASS_32_BITS); return copy; } } // Anonymous namespace diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 17f860f910..5dd2a80ec1 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -244,6 +244,14 @@ public: return gl_type; } + [[nodiscard]] bool NeedsStorageUsage() const noexcept { + return false; + } + + bool EnableStorageUsage() { + return false; + } + bool IsRescaled() const; bool ScaleUp(bool ignore = false); diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 006bfc0a09..5bb1543d53 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -167,12 +167,13 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, } return TexturePair(gpu_memory.Read(addr), via_header_index); }}; - const auto add_image{[&](const auto& desc, bool blacklist) { + const auto add_image{[&](const auto& desc, bool blacklist, bool storage = false) { for (u32 index = 0; index < desc.count; ++index) { const auto handle{read_handle(desc, index)}; views.push_back({ .index = handle.first, .blacklist = blacklist, + .storage = storage, .id = {}, }); } @@ -193,7 +194,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, } } for (const auto& desc : info.image_descriptors) { - add_image(desc, desc.is_written); + add_image(desc, desc.is_written, true); } texture_cache.FillImageViews(std::span(views.data(), views.size()), true); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 8112087730..a566ba0df4 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -378,12 +378,14 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { } return TexturePair(gpu_memory->Read(addr), via_header_index); }}; - const auto add_image{[&](const auto& desc, bool blacklist) LAMBDA_FORCEINLINE { + const auto add_image{[&](const auto& desc, bool blacklist, + bool storage = false) LAMBDA_FORCEINLINE { for (u32 index = 0; index < desc.count; ++index) { const auto handle{read_handle(desc, index)}; views.push_back({ .index = handle.first, .blacklist = blacklist, + .storage = storage, .id = {} }); } @@ -409,7 +411,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { } if constexpr (Spec::has_images) { for (const auto& desc : info.image_descriptors) { - add_image(desc, desc.is_written); + add_image(desc, desc.is_written, true); } } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 7b1b2ef2fa..246bd0f112 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -111,7 +111,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { } [[nodiscard]] VkImageUsageFlags ImageUsageFlags(const MaxwellToVK::FormatInfo& info, - PixelFormat format) { + PixelFormat format, bool want_storage = true) { VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; if (info.attachable) { @@ -129,7 +129,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { break; } } - if (info.storage) { + if (info.storage && want_storage) { usage |= VK_IMAGE_USAGE_STORAGE_BIT; } return usage; @@ -147,8 +147,19 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { info.size.depth == 1; } +[[nodiscard]] bool WillUseComputeUnswizzle(const ImageInfo& info) { + return Settings::values.gpu_unswizzle_enabled.GetValue() && IsPixelFormatBCn(info.format) && + info.type == ImageType::e3D && info.resources.levels == 1 && + info.resources.layers == 1; +} + +[[nodiscard]] bool StorageNeededAtCreation(const Device& device, const ImageInfo& info) { + return WillUseAcceleratedAstcDecode(device, info) || WillUseComputeUnswizzle(info); +} + [[nodiscard]] VkImageCreateInfo MakeImageCreateInfo(const Device& device, const ImageInfo& info, - std::optional format_override = {}) { + std::optional format_override = {}, + bool want_storage = true) { auto format_info = MaxwellToVK::SurfaceFormat(device, FormatType::Optimal, false, info.format); if (format_override) { @@ -166,7 +177,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { } 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); + VkImageUsageFlags usage = ImageUsageFlags(format_info, info.format, want_storage); if (samples != VK_SAMPLE_COUNT_1_BIT && !device.IsStorageImageMultisampleSupported()) { usage &= ~static_cast(VK_IMAGE_USAGE_STORAGE_BIT); } @@ -195,11 +206,13 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { [[nodiscard]] vk::Image MakeImage(const Device& device, const MemoryAllocator& allocator, const ImageInfo& info, std::span view_formats, - std::optional format_override = {}) { + std::optional format_override = {}, + bool want_storage = true) { if (info.type == ImageType::Buffer) { return vk::Image{}; } - VkImageCreateInfo image_ci = MakeImageCreateInfo(device, info, format_override); + VkImageCreateInfo image_ci = + MakeImageCreateInfo(device, info, format_override, want_storage); const VkImageFormatListCreateInfo image_format_list = { .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO, .pNext = nullptr, @@ -221,7 +234,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { (device.IsStorageImageMultisampleSupported() && (device.GetStorageImageSampleCounts() & static_cast(image_ci.samples)) != 0); - if (has_storage_compatible_view && storage_allowed_for_samples) { + if (want_storage && 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, @@ -931,6 +944,109 @@ void BlitScale(Scheduler& scheduler, VkImage src_image, VkImage dst_image, const }); } +void CopyWholeImage(Scheduler& scheduler, VkImage src_image, VkImage dst_image, + const ImageInfo& info, VkImageAspectFlags aspect_mask) { + const auto [samples_x, samples_y] = VideoCommon::SamplesLog2(info.num_samples); + const auto resources = info.resources; + const bool is_3d = info.type == ImageType::e3D; + const VkExtent3D extent{ + .width = info.size.width >> samples_x, + .height = info.size.height >> samples_y, + .depth = is_3d ? info.size.depth : 1u, + }; + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([src_image, dst_image, extent, resources, aspect_mask, + is_3d](vk::CommandBuffer cmdbuf) { + boost::container::small_vector regions; + regions.reserve(resources.levels); + for (s32 level = 0; level < resources.levels; ++level) { + const u32 level_u = static_cast(level); + const VkImageSubresourceLayers layers{ + .aspectMask = aspect_mask, + .mipLevel = level_u, + .baseArrayLayer = 0, + .layerCount = static_cast(resources.layers), + }; + regions.push_back({ + .srcSubresource = layers, + .srcOffset{}, + .dstSubresource = layers, + .dstOffset{}, + .extent{ + .width = (std::max)(1u, extent.width >> level_u), + .height = (std::max)(1u, extent.height >> level_u), + .depth = is_3d ? (std::max)(1u, extent.depth >> level_u) : 1u, + }, + }); + } + const VkImageSubresourceRange subresource_range{ + .aspectMask = aspect_mask, + .baseMipLevel = 0, + .levelCount = VK_REMAINING_MIP_LEVELS, + .baseArrayLayer = 0, + .layerCount = VK_REMAINING_ARRAY_LAYERS, + }; + const std::array read_barriers{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_GENERAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = src_image, + .subresourceRange = subresource_range, + }, + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange = subresource_range, + }, + }; + const std::array write_barriers{ + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = src_image, + .subresourceRange = subresource_range, + }, + VkImageMemoryBarrier{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = dst_image, + .subresourceRange = subresource_range, + }, + }; + cmdbuf.PipelineBarrier(vk::PIPELINE_STAGE_GRAPHICS_COMPUTE_TRANSFER, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr, read_barriers); + cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regions); + cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, vk::PIPELINE_STAGE_GRAPHICS_COMPUTE, + 0, nullptr, nullptr, write_barriers); + }); +} + [[nodiscard]] bool CanBlitNatively(const Device& device, PixelFormat format) { static constexpr auto OPTIMAL_FORMAT = FormatType::Optimal; static constexpr VkFormatFeatureFlags BLIT_USAGE = @@ -971,6 +1087,9 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched view_formats[index_a].push_back(view_info.format); } } + auto& formats = view_formats[index_a]; + std::ranges::sort(formats); + formats.erase(std::ranges::unique(formats).begin(), formats.end()); } if (Settings::values.gpu_unswizzle_enabled.GetValue()) { @@ -1889,8 +2008,12 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu VAddr cpu_addr_) : VideoCommon::ImageBase(info_, gpu_addr_, cpu_addr_), scheduler{&runtime_.scheduler}, runtime{&runtime_}, + storage_capable(MaxwellToVK::SurfaceFormat(runtime_.device, FormatType::Optimal, false, + info_.format) + .storage), + wants_storage(StorageNeededAtCreation(runtime_.device, info_)), original_image(MakeImage(runtime_.device, runtime_.memory_allocator, info, - runtime->ViewFormats(info.format))), + runtime->ViewFormats(info.format), {}, wants_storage)), aspect_mask(ImageAspectMask(info.format)) { if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported()) { switch (Settings::values.accelerate_astc.GetValue()) { @@ -1917,7 +2040,8 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu } current_image = &Image::original_image; storage_image_views.resize(info.resources.levels); - if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() && + if (wants_storage && IsPixelFormatASTC(info.format) && + !runtime->device.IsOptimalAstcSupported() && Settings::values.astc_recompression.GetValue() == Settings::AstcRecompression::Uncompressed) { const auto& device = runtime->device.GetLogical(); @@ -2307,6 +2431,7 @@ void Image::DownloadMemory(const StagingBufferRef& map, std::spanViewFormats(info.format); + auto scaled_info = info; + if (scaled_image) { + const auto& resolution = runtime->resolution; + scaled_info.size.width = resolution.ScaleUp(info.size.width); + if (info.type == ImageType::e2D) { + scaled_info.size.height = resolution.ScaleUp(info.size.height); + } + } + vk::Image new_original = MakeImage(runtime->device, runtime->memory_allocator, info, + view_formats, {}, true); + if (!new_original) { + return false; + } + vk::Image new_scaled; + if (scaled_image) { + new_scaled = MakeImage(runtime->device, runtime->memory_allocator, scaled_info, + view_formats, {}, true); + if (!new_scaled) { + return false; + } + } + const auto commit = [&](vk::Image& target, vk::Image& replacement, + const ImageInfo& target_info) { + if (initialized) { + CopyWholeImage(*scheduler, *target, *replacement, target_info, aspect_mask); + } + runtime->pending_msaa_images.emplace_back(scheduler->CurrentTick(), std::move(target)); + target = std::move(replacement); + }; + commit(original_image, new_original, info); + if (scaled_image) { + commit(scaled_image, new_scaled, scaled_info); + } + wants_storage = true; + storage_image_views.clear(); + storage_image_views.resize(info.resources.levels); + scale_framebuffer.reset(); + normal_framebuffer.reset(); + scale_view.reset(); + normal_view.reset(); + return true; +} + bool Image::IsRescaled() const noexcept { return True(flags & ImageFlagBits::Rescaled); } @@ -2343,7 +2519,7 @@ bool Image::ScaleUp(bool ignore) { scaled_info.size.width = scaled_width; scaled_info.size.height = scaled_height; scaled_image = MakeImage(runtime->device, runtime->memory_allocator, scaled_info, - runtime->ViewFormats(info.format)); + runtime->ViewFormats(info.format), {}, wants_storage); ignore = false; } current_image = &Image::scaled_image; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 7515ea05a8..eaa83f2d6a 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -392,6 +392,13 @@ public: VkImageView StorageImageView(s32 level) noexcept; + [[nodiscard]] bool NeedsStorageUsage() const noexcept { + return storage_capable && !wants_storage && runtime != nullptr && + current_image != nullptr && static_cast(this->*current_image); + } + + bool EnableStorageUsage(); + bool IsRescaled() const noexcept; bool ScaleUp(bool ignore = false); @@ -410,6 +417,9 @@ private: Scheduler* scheduler{}; TextureCacheRuntime* runtime{}; + bool storage_capable = false; + bool wants_storage = false; + vk::Image original_image; vk::Image scaled_image; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 9fc90b73bb..6c9d185b6c 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -303,6 +303,14 @@ void TextureCache

::FillImageViews(std::span views, bool compu } for (ImageViewInOut& view : views) { view.id = VisitImageView(view.index, compute); + if (view.storage && view.id != NULL_IMAGE_VIEW_ID && view.id != ImageViewId{}) { + const ImageViewBase& image_view = slot_image_views[view.id]; + auto& image = slot_images[image_view.image_id]; + if (image.NeedsStorageUsage() && image.EnableStorageUsage()) { + InvalidateScale(image); + break; + } + } if (blacklist) { if (view.blacklist && view.id != NULL_IMAGE_VIEW_ID) { const ImageViewBase& image_view = slot_image_views[view.id]; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 93a6a36f45..6007ec3b85 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -57,6 +57,7 @@ using namespace Common::Literals; struct ImageViewInOut { u32 index{}; bool blacklist{}; + bool storage{}; ImageViewId id{}; };