From 42c944b250d8d5c8147b24b3a453cba29968d46c Mon Sep 17 00:00:00 2001 From: Wollnashorn Date: Thu, 15 Jun 2023 18:19:32 +0200 Subject: video_core: Add per-image anisotropy heuristics (format & mip count) --- src/video_core/renderer_vulkan/pipeline_helper.h | 10 +++-- .../renderer_vulkan/vk_compute_pipeline.cpp | 6 +-- .../renderer_vulkan/vk_graphics_pipeline.cpp | 6 +-- .../renderer_vulkan/vk_texture_cache.cpp | 49 ++++++++++++---------- src/video_core/renderer_vulkan/vk_texture_cache.h | 9 ++++ 5 files changed, 50 insertions(+), 30 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 983e1c2e1..1632a6f26 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -178,7 +178,7 @@ public: inline void PushImageDescriptors(TextureCache& texture_cache, GuestDescriptorQueue& guest_descriptor_queue, const Shader::Info& info, RescalingPushConstant& rescaling, - const VkSampler*& samplers, + const Sampler**& samplers, const VideoCommon::ImageViewInOut*& views) { const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors); const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors); @@ -187,10 +187,14 @@ inline void PushImageDescriptors(TextureCache& texture_cache, for (const auto& desc : info.texture_descriptors) { for (u32 index = 0; index < desc.count; ++index) { const VideoCommon::ImageViewId image_view_id{(views++)->id}; - const VkSampler sampler{*(samplers++)}; ImageView& image_view{texture_cache.GetImageView(image_view_id)}; const VkImageView vk_image_view{image_view.Handle(desc.type)}; - guest_descriptor_queue.AddSampledImage(vk_image_view, sampler); + const Sampler& sampler{**(samplers++)}; + const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && + !image_view.SupportsAnisotropy()}; + const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithoutAnisotropy() + : 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_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 733e70d9d..eb292dc34 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -115,7 +115,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, static constexpr size_t max_elements = 64; boost::container::static_vector views; - boost::container::static_vector samplers; + boost::container::static_vector samplers; const auto& qmd{kepler_compute.launch_description}; const auto& cbufs{qmd.const_buffer_config}; @@ -161,7 +161,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, views.push_back({handle.first}); Sampler* const sampler = texture_cache.GetComputeSampler(handle.second); - samplers.push_back(sampler->Handle()); + samplers.push_back(sampler); } } for (const auto& desc : info.image_descriptors) { @@ -192,7 +192,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, buffer_cache.BindHostComputeBuffers(); RescalingPushConstant rescaling; - const VkSampler* samplers_it{samplers.data()}; + const Sampler** samplers_it{samplers.data()}; const VideoCommon::ImageViewInOut* views_it{views.data()}; PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it, views_it); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 506b78f08..e6e004cb6 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -298,7 +298,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) { template void GraphicsPipeline::ConfigureImpl(bool is_indexed) { std::array views; - std::array samplers; + std::array samplers; size_t sampler_index{}; size_t view_index{}; @@ -368,7 +368,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { views[view_index++] = {handle.first}; Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)}; - samplers[sampler_index++] = sampler->Handle(); + samplers[sampler_index++] = sampler; } } if constexpr (Spec::has_images) { @@ -453,7 +453,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { RescalingPushConstant rescaling; RenderAreaPushConstant render_area; - const VkSampler* samplers_it{samplers.data()}; + const Sampler** samplers_it{samplers.data()}; const VideoCommon::ImageViewInOut* views_it{views.data()}; const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { buffer_cache.BindHostStageBuffers(stage); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 8711e2a87..0e8f8a064 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1802,27 +1802,34 @@ 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); - sampler = 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), - .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(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), - .maxAnisotropy = max_anisotropy, - .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 = - arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color), - .unnormalizedCoordinates = VK_FALSE, - }); + const auto create_sampler = [&](const f32 max_anisotropy) { + 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), + .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(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), + .maxAnisotropy = max_anisotropy, + .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 = + arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color), + .unnormalizedCoordinates = VK_FALSE, + }); + }; + + sampler = create_sampler(max_anisotropy); + if (Settings::values.max_anisotropy.GetValue() > 0 && max_anisotropy > 1.0f) { + sampler_without_anisotropy = create_sampler(1.0f); + } } 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 0f7a5ffd4..ee0d0480d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -279,8 +279,17 @@ public: return *sampler; } + [[nodiscard]] VkSampler HandleWithoutAnisotropy() const noexcept { + return *sampler_without_anisotropy; + } + + [[nodiscard]] bool HasAddedAnisotropy() const noexcept { + return static_cast(sampler_without_anisotropy); + } + private: vk::Sampler sampler; + vk::Sampler sampler_without_anisotropy; }; class Framebuffer { -- cgit v1.2.3 From 3e8cd91d548433344d9c479bb7ad83a3bf1560c1 Mon Sep 17 00:00:00 2001 From: Wollnashorn Date: Thu, 15 Jun 2023 18:46:40 +0200 Subject: video_core: Fixed compilation errors because of name shadowing --- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 0e8f8a064..8ec181335 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1802,7 +1802,7 @@ 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 max_anisotropy) { + const auto create_sampler = [&](const f32 anisotropy) { return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .pNext = pnext, @@ -1814,8 +1814,8 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t .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(max_anisotropy > 1.0f ? VK_TRUE : VK_FALSE), - .maxAnisotropy = max_anisotropy, + .anisotropyEnable = static_cast(anisotropy > 1.0f ? VK_TRUE : VK_FALSE), + .maxAnisotropy = anisotropy, .compareEnable = tsc.depth_compare_enabled, .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), -- cgit v1.2.3 From a3b7b5b22af8ef83fc765afac9d6f6b8dac7f62b Mon Sep 17 00:00:00 2001 From: Wollnashorn Date: Thu, 15 Jun 2023 23:16:26 +0200 Subject: video_core: Fallback to default anisotropy instead to 1x anisotropy --- src/video_core/renderer_vulkan/pipeline_helper.h | 2 +- src/video_core/renderer_vulkan/vk_texture_cache.cpp | 6 ++++-- src/video_core/renderer_vulkan/vk_texture_cache.h | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 1632a6f26..0a9dce937 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -192,7 +192,7 @@ inline void PushImageDescriptors(TextureCache& texture_cache, const Sampler& sampler{**(samplers++)}; const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && !image_view.SupportsAnisotropy()}; - const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithoutAnisotropy() + const VkSampler vk_sampler{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 8ec181335..f025f618b 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1827,8 +1827,10 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t }; sampler = create_sampler(max_anisotropy); - if (Settings::values.max_anisotropy.GetValue() > 0 && max_anisotropy > 1.0f) { - sampler_without_anisotropy = create_sampler(1.0f); + + 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); } } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index ee0d0480d..f14525dcb 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -279,17 +279,17 @@ public: return *sampler; } - [[nodiscard]] VkSampler HandleWithoutAnisotropy() const noexcept { - return *sampler_without_anisotropy; + [[nodiscard]] VkSampler HandleWithDefaultAnisotropy() const noexcept { + return *sampler_default_anisotropy; } [[nodiscard]] bool HasAddedAnisotropy() const noexcept { - return static_cast(sampler_without_anisotropy); + return static_cast(sampler_default_anisotropy); } private: vk::Sampler sampler; - vk::Sampler sampler_without_anisotropy; + vk::Sampler sampler_default_anisotropy; }; class Framebuffer { -- cgit v1.2.3 From 2dc0ff79ece34286c7078922668fd9f0a19b47b7 Mon Sep 17 00:00:00 2001 From: Wollnashorn Date: Fri, 16 Jun 2023 13:26:44 +0200 Subject: video_core: Use sampler IDs instead pointers in the pipeline config The previous approach of storing pointers returned by `GetGraphicsSampler`/`GetComputeSampler` caused UB, as these functions can cause reallocation of the sampler slot vector and therefore invalidate the pointers --- src/video_core/renderer_vulkan/pipeline_helper.h | 5 +++-- src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 6 +++--- src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/video_core/renderer_vulkan') diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 0a9dce937..71c783709 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -178,7 +178,7 @@ public: inline void PushImageDescriptors(TextureCache& texture_cache, GuestDescriptorQueue& guest_descriptor_queue, const Shader::Info& info, RescalingPushConstant& rescaling, - const Sampler**& samplers, + const VideoCommon::SamplerId*& samplers, const VideoCommon::ImageViewInOut*& views) { const u32 num_texture_buffers = Shader::NumDescriptors(info.texture_buffer_descriptors); const u32 num_image_buffers = Shader::NumDescriptors(info.image_buffer_descriptors); @@ -187,9 +187,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache, for (const auto& desc : info.texture_descriptors) { for (u32 index = 0; index < desc.count; ++index) { 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 Sampler& sampler{**(samplers++)}; + 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() diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index eb292dc34..73e585c2b 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -115,7 +115,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, static constexpr size_t max_elements = 64; boost::container::static_vector views; - boost::container::static_vector samplers; + boost::container::static_vector samplers; const auto& qmd{kepler_compute.launch_description}; const auto& cbufs{qmd.const_buffer_config}; @@ -160,7 +160,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, const auto handle{read_handle(desc, index)}; views.push_back({handle.first}); - Sampler* const sampler = texture_cache.GetComputeSampler(handle.second); + VideoCommon::SamplerId sampler = texture_cache.GetComputeSamplerId(handle.second); samplers.push_back(sampler); } } @@ -192,7 +192,7 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, buffer_cache.BindHostComputeBuffers(); RescalingPushConstant rescaling; - const Sampler** samplers_it{samplers.data()}; + const VideoCommon::SamplerId* samplers_it{samplers.data()}; const VideoCommon::ImageViewInOut* views_it{views.data()}; PushImageDescriptors(texture_cache, guest_descriptor_queue, info, rescaling, samplers_it, views_it); diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index e6e004cb6..c1595642e 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -298,7 +298,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) { template void GraphicsPipeline::ConfigureImpl(bool is_indexed) { std::array views; - std::array samplers; + std::array samplers; size_t sampler_index{}; size_t view_index{}; @@ -367,7 +367,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { const auto handle{read_handle(desc, index)}; views[view_index++] = {handle.first}; - Sampler* const sampler{texture_cache.GetGraphicsSampler(handle.second)}; + VideoCommon::SamplerId sampler{texture_cache.GetGraphicsSamplerId(handle.second)}; samplers[sampler_index++] = sampler; } } @@ -453,7 +453,7 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) { RescalingPushConstant rescaling; RenderAreaPushConstant render_area; - const Sampler** samplers_it{samplers.data()}; + const VideoCommon::SamplerId* samplers_it{samplers.data()}; const VideoCommon::ImageViewInOut* views_it{views.data()}; const auto prepare_stage{[&](size_t stage) LAMBDA_FORCEINLINE { buffer_cache.BindHostStageBuffers(stage); -- cgit v1.2.3