diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 910e07a606..f40af69af3 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -12,12 +12,14 @@ #include "shader_recompiler/shader_info.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" +#include "video_core/surface.h" #include "video_core/texture_cache/types.h" #include "video_core/vulkan_common/vulkan_device.h" namespace Vulkan { using Shader::Backend::SPIRV::NUM_TEXTURE_AND_IMAGE_SCALING_WORDS; +using VideoCore::Surface::IsPixelFormatInteger; class DescriptorLayoutBuilder { public: @@ -191,10 +193,14 @@ inline void PushImageDescriptors(TextureCache& texture_cache, ImageView& image_view{texture_cache.GetImageView(image_view_id)}; const VkImageView vk_image_view{image_view.Handle(desc.type)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; + // Integer formats don't support VK_FILTER_LINEAR in Vulkan. + const bool needs_nearest{sampler.HasLinearFilter() && + IsPixelFormatInteger(image_view.format)}; const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && !image_view.SupportsAnisotropy()}; - const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() - : sampler.Handle()}; + const VkSampler vk_sampler{needs_nearest ? sampler.HandleWithNearestFilter() + : use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() + : sampler.Handle()}; guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler); rescaling.PushTexture(texture_cache.IsRescaling(image_view)); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 348e49fb6d..926db191eb 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -38,6 +38,7 @@ namespace Vulkan { using Tegra::Engines::Fermi2D; using Tegra::Texture::SwizzleSource; +using Tegra::Texture::TextureFilter; using Tegra::Texture::TextureMipmapFilter; using VideoCommon::BufferImageCopy; using VideoCommon::ImageFlagBits; @@ -2356,6 +2357,35 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t if (max_anisotropy > max_anisotropy_default) { sampler_default_anisotropy = create_sampler(max_anisotropy_default); } + + // Create a nearest-filter fallback for integer format image views. + // but Vulkan requires the format to support linear filtering. + const bool is_mag_linear = tsc.mag_filter == TextureFilter::Linear; + const bool is_min_linear = tsc.min_filter == TextureFilter::Linear; + has_linear_filter = is_mag_linear || is_min_linear; + if (has_linear_filter) { + sampler_nearest = device.GetLogical().CreateSampler(VkSamplerCreateInfo{ + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = pnext, + .flags = 0, + .magFilter = VK_FILTER_NEAREST, + .minFilter = VK_FILTER_NEAREST, + .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST, + .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter), + .addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, tsc.mag_filter), + .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter), + .mipLodBias = tsc.LodBias(), + .anisotropyEnable = VK_FALSE, + .maxAnisotropy = 1.0f, + .compareEnable = tsc.depth_compare_enabled, + .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), + .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), + .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), + .borderColor = has_custom_border_colors ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT + : ConvertBorderColor(color), + .unnormalizedCoordinates = VK_FALSE, + }); + } } Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span color_buffers, diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 4bb9687ab0..d4113eef4e 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -408,9 +408,19 @@ public: return static_cast(sampler_default_anisotropy); } + [[nodiscard]] bool HasLinearFilter() const noexcept { + return has_linear_filter; + } + + [[nodiscard]] VkSampler HandleWithNearestFilter() const noexcept { + return sampler_nearest ? *sampler_nearest : *sampler; + } + private: vk::Sampler sampler; vk::Sampler sampler_default_anisotropy; + vk::Sampler sampler_nearest; + bool has_linear_filter = false; }; struct TextureCacheParams {