diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 126787909d..34c068d922 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -192,10 +192,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache, const VkImageView vk_image_view{ image_view.SampledView(desc.type, desc.component_type)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; - const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && - !image_view.SupportsAnisotropy()}; - const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy() - : sampler.Handle()}; + const bool supports_linear_filter{ + texture_cache.SupportsLinearFilter(image_view.format)}; + const VkSampler vk_sampler{ + sampler.SelectHandle(supports_linear_filter, image_view.SupportsAnisotropy())}; 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_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index d732268c8f..269b87ac3a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -1263,8 +1263,12 @@ void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs) if (!device.IsDepthBoundsSupported()) { return; } - scheduler.Record([min_depth = regs.depth_bounds[0], max_depth = regs.depth_bounds[1]]( - vk::CommandBuffer cmdbuf) { + const bool unrestricted = device.IsExtDepthRangeUnrestrictedSupported(); + const float min_depth = unrestricted ? regs.depth_bounds[0] + : std::clamp(regs.depth_bounds[0], 0.0f, 1.0f); + const float max_depth = unrestricted ? regs.depth_bounds[1] + : std::clamp(regs.depth_bounds[1], 0.0f, 1.0f); + scheduler.Record([min_depth, max_depth](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBounds(min_depth, max_depth); }); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 6bd8973aad..10f1f3843f 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -838,9 +838,6 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, Scheduler& sched msaa_copy_pass = std::make_unique( device, scheduler, descriptor_pool, staging_buffer_pool, compute_pass_descriptor_queue); } - if (!device.IsKhrImageFormatListSupported()) { - return; - } for (size_t index_a = 0; index_a < VideoCore::Surface::MaxPixelFormat; index_a++) { const auto image_format = static_cast(index_a); if (IsPixelFormatASTC(image_format) && !device.IsOptimalAstcSupported()) { @@ -2357,20 +2354,29 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t // Some games have samplers with garbage. Sanitize them here. const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); - const auto create_sampler = [&](const f32 anisotropy) { + const auto create_sampler = [&](const f32 anisotropy, bool force_point_filter) { + const VkFilter mag_filter = force_point_filter ? VK_FILTER_NEAREST + : MaxwellToVK::Sampler::Filter(tsc.mag_filter); + const VkFilter min_filter = force_point_filter ? VK_FILTER_NEAREST + : MaxwellToVK::Sampler::Filter(tsc.min_filter); + const VkSamplerMipmapMode mipmap_mode = force_point_filter + ? VK_SAMPLER_MIPMAP_MODE_NEAREST + : MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter); + const float resolved_anisotropy = force_point_filter ? 1.0f : anisotropy; + const bool enable_anisotropy = resolved_anisotropy > 1.0f && !force_point_filter; return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = pnext, .flags = 0, - .magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter), - .minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter), - .mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter), + .magFilter = mag_filter, + .minFilter = min_filter, + .mipmapMode = mipmap_mode, .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 = static_cast(anisotropy > 1.0f ? VK_TRUE : VK_FALSE), - .maxAnisotropy = anisotropy, + .anisotropyEnable = static_cast(enable_anisotropy ? VK_TRUE : VK_FALSE), + .maxAnisotropy = enable_anisotropy ? resolved_anisotropy : 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(), @@ -2381,12 +2387,31 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t }); }; - sampler = create_sampler(max_anisotropy); + sampler = create_sampler(max_anisotropy, false); const f32 max_anisotropy_default = static_cast(1U << tsc.max_anisotropy); if (max_anisotropy > max_anisotropy_default) { - sampler_default_anisotropy = create_sampler(max_anisotropy_default); + sampler_default_anisotropy = create_sampler(max_anisotropy_default, false); + } + + uses_linear_filter = (tsc.mag_filter == TextureFilter::Linear) || + (tsc.min_filter == TextureFilter::Linear) || (max_anisotropy > 1.0f); + if (uses_linear_filter) { + sampler_force_point = create_sampler(1.0f, true); + } +} + +VkSampler Sampler::SelectHandle(bool supports_linear_filter, + bool supports_anisotropy) const noexcept { + const bool needs_linear_fallback = uses_linear_filter && !supports_linear_filter; + if (needs_linear_fallback && sampler_force_point) { + return *sampler_force_point; + } + const bool needs_aniso_fallback = HasAddedAnisotropy() && !supports_anisotropy; + if (needs_aniso_fallback) { + return HandleWithDefaultAnisotropy(); } + return Handle(); } 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 d794775c18..45f10bdeb0 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -318,9 +318,14 @@ public: return static_cast(sampler_default_anisotropy); } + [[nodiscard]] VkSampler SelectHandle(bool supports_linear_filter, + bool supports_anisotropy) const noexcept; + private: vk::Sampler sampler; vk::Sampler sampler_default_anisotropy; + vk::Sampler sampler_force_point; + bool uses_linear_filter = false; }; class Framebuffer { diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 5146a8c291..ee10ac2d23 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -182,6 +182,11 @@ public: /// Return a reference to the given sampler id [[nodiscard]] Sampler& GetSampler(SamplerId id) noexcept; + /// Returns true when the runtime format supports linear filtering + [[nodiscard]] bool SupportsLinearFilter(PixelFormat format) const noexcept { + return runtime.SupportsLinearFilter(format); + } + /// Refresh the state for graphics image view and sampler descriptors void SynchronizeGraphicsDescriptors();