diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 910e07a606..0e12c5eda4 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -189,7 +189,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache, const VideoCommon::ImageViewId image_view_id{(views++)->id}; const VideoCommon::SamplerId sampler_id{*(samplers++)}; ImageView& image_view{texture_cache.GetImageView(image_view_id)}; - const VkImageView vk_image_view{image_view.Handle(desc.type)}; + const VkImageView vk_image_view{image_view.SampledHandle(desc.type)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && !image_view.SupportsAnisotropy()}; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 8a924d9046..a37d747c68 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -45,6 +45,7 @@ using VideoCore::Surface::BytesPerBlock; using VideoCore::Surface::HasAlpha; using VideoCore::Surface::IsPixelFormatASTC; using VideoCore::Surface::IsPixelFormatInteger; +using VideoCore::Surface::NormalizedCompatibleFormat; using VideoCore::Surface::SurfaceType; namespace { @@ -2040,7 +2041,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI samples(ConvertSampleCount(image.info.num_samples)) { using Shader::TextureType; - const VkImageAspectFlags aspect_mask = ImageViewAspectMask(info); + const VkImageAspectFlags aspect_mask_local = ImageViewAspectMask(info); + aspect_mask = aspect_mask_local; std::array swizzle{ SwizzleSource::R, SwizzleSource::G, @@ -2072,6 +2074,14 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI .pNext = nullptr, .usage = view_usage, }; + view_usage_flags = view_usage; + const VkComponentMapping components{ + .r = ComponentSwizzle(swizzle[0]), + .g = ComponentSwizzle(swizzle[1]), + .b = ComponentSwizzle(swizzle[2]), + .a = ComponentSwizzle(swizzle[3]), + }; + component_mapping = components; const VkImageViewCreateInfo create_info{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = &image_view_usage, @@ -2079,13 +2089,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI .image = image.Handle(), .viewType = VkImageViewType{}, .format = format_info.format, - .components{ - .r = ComponentSwizzle(swizzle[0]), - .g = ComponentSwizzle(swizzle[1]), - .b = ComponentSwizzle(swizzle[2]), - .a = ComponentSwizzle(swizzle[3]), - }, - .subresourceRange = MakeSubresourceRange(aspect_mask, info.range), + .components = components, + .subresourceRange = MakeSubresourceRange(aspect_mask_local, info.range), }; const auto create = [&](TextureType tex_type, std::optional num_layers) { VkImageViewCreateInfo ci{create_info}; @@ -2098,6 +2103,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI handle.SetObjectNameEXT(VideoCommon::Name(*this, gpu_addr).c_str()); } image_views[static_cast(tex_type)] = std::move(handle); + view_layer_counts[static_cast(tex_type)] = num_layers; }; switch (info.type) { case VideoCommon::ImageViewType::e1D: @@ -2151,6 +2157,8 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::NullImageV null_image = MakeImage(*device, runtime.memory_allocator, info, {}); image_handle = *null_image; + aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT; + view_usage_flags = VK_IMAGE_USAGE_SAMPLED_BIT; for (u32 i = 0; i < Shader::NUM_TEXTURE_TYPES; i++) { image_views[i] = MakeView(VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_ASPECT_COLOR_BIT); } @@ -2215,6 +2223,24 @@ VkImageView ImageView::StorageView(Shader::TextureType texture_type, return *view; } +VkImageView ImageView::SampledHandle(Shader::TextureType texture_type) { + if (!IsPixelFormatInteger(format)) { + return Handle(texture_type); + } + const auto compatible_format = NormalizedCompatibleFormat(format); + if (!compatible_format) { + return Handle(texture_type); + } + auto& view = sampled_float_views[static_cast(texture_type)]; + if (view) { + return *view; + } + const auto format_info = + MaxwellToVK::SurfaceFormat(*device, FormatType::Optimal, true, *compatible_format); + view = CreateSampledView(texture_type, format_info.format); + return *view; +} + bool ImageView::IsRescaled() const noexcept { if (!slot_images) { return false; @@ -2242,6 +2268,30 @@ vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_ }); } +vk::ImageView ImageView::CreateSampledView(Shader::TextureType texture_type, + VkFormat vk_format) const { + const VkImageViewUsageCreateInfo usage_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, + .pNext = nullptr, + .usage = view_usage_flags, + }; + VkImageViewCreateInfo create_info{ + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = &usage_info, + .flags = 0, + .image = image_handle, + .viewType = ImageViewType(texture_type), + .format = vk_format, + .components = component_mapping, + .subresourceRange = MakeSubresourceRange(aspect_mask, range), + }; + const auto idx = static_cast(texture_type); + if (view_layer_counts[idx]) { + create_info.subresourceRange.layerCount = *view_layer_counts[idx]; + } + return device->GetLogical().CreateImageView(create_info); +} + Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) { const auto& device = runtime.device; // Check if custom border colors are supported diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index cd11cc8fc7..799e474bda 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -3,6 +3,8 @@ #pragma once +#include +#include #include #include "video_core/texture_cache/texture_cache_base.h" @@ -242,6 +244,8 @@ public: return *image_views[static_cast(texture_type)]; } + [[nodiscard]] VkImageView SampledHandle(Shader::TextureType texture_type); + [[nodiscard]] VkImage ImageHandle() const noexcept { return image_handle; } @@ -269,11 +273,15 @@ private: }; [[nodiscard]] vk::ImageView MakeView(VkFormat vk_format, VkImageAspectFlags aspect_mask); + [[nodiscard]] vk::ImageView CreateSampledView(Shader::TextureType texture_type, + VkFormat vk_format) const; const Device* device = nullptr; const SlotVector* slot_images = nullptr; std::array image_views; + std::array sampled_float_views; + std::array, Shader::NUM_TEXTURE_TYPES> view_layer_counts{}; std::unique_ptr storage_views; vk::ImageView depth_view; vk::ImageView stencil_view; @@ -282,6 +290,14 @@ private: VkImage image_handle = VK_NULL_HANDLE; VkImageView render_target = VK_NULL_HANDLE; VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT; + VkComponentMapping component_mapping{ + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + VK_COMPONENT_SWIZZLE_IDENTITY, + }; + VkImageAspectFlags aspect_mask = 0; + VkImageUsageFlags view_usage_flags = 0; u32 buffer_size = 0; }; diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp index 1998849e84..3590ed0226 100644 --- a/src/video_core/surface.cpp +++ b/src/video_core/surface.cpp @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include + #include "common/common_types.h" #include "common/math_util.h" #include "common/settings.h" @@ -408,6 +410,39 @@ bool IsPixelFormatSignedInteger(PixelFormat format) { } } +std::optional NormalizedCompatibleFormat(PixelFormat format) { + switch (format) { + case PixelFormat::A8B8G8R8_UINT: + return PixelFormat::A8B8G8R8_UNORM; + case PixelFormat::A8B8G8R8_SINT: + return PixelFormat::A8B8G8R8_SNORM; + case PixelFormat::A2B10G10R10_UINT: + return PixelFormat::A2B10G10R10_UNORM; + case PixelFormat::R8_UINT: + return PixelFormat::R8_UNORM; + case PixelFormat::R8_SINT: + return PixelFormat::R8_SNORM; + case PixelFormat::R8G8_UINT: + return PixelFormat::R8G8_UNORM; + case PixelFormat::R8G8_SINT: + return PixelFormat::R8G8_SNORM; + case PixelFormat::R16_UINT: + return PixelFormat::R16_UNORM; + case PixelFormat::R16_SINT: + return PixelFormat::R16_SNORM; + case PixelFormat::R16G16_UINT: + return PixelFormat::R16G16_UNORM; + case PixelFormat::R16G16_SINT: + return PixelFormat::R16G16_SNORM; + case PixelFormat::R16G16B16A16_UINT: + return PixelFormat::R16G16B16A16_UNORM; + case PixelFormat::R16G16B16A16_SINT: + return PixelFormat::R16G16B16A16_SNORM; + default: + return std::nullopt; + } +} + size_t PixelComponentSizeBitsInteger(PixelFormat format) { switch (format) { case PixelFormat::A8B8G8R8_SINT: diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 4ccb24f27d..6c8b087ea6 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include "common/assert.h" #include "common/common_types.h" @@ -515,6 +516,8 @@ bool IsPixelFormatInteger(PixelFormat format); bool IsPixelFormatSignedInteger(PixelFormat format); +std::optional NormalizedCompatibleFormat(PixelFormat format); + size_t PixelComponentSizeBitsInteger(PixelFormat format); std::pair GetASTCBlockSize(PixelFormat format);