Browse Source

[vk] VUID-vkCmdDraw-magFilter-04553 fix

pull/2756/head
Ribbit 5 months ago
committed by crueter
parent
commit
d9e85facce
  1. 30
      src/video_core/renderer_vulkan/pipeline_helper.h
  2. 70
      src/video_core/renderer_vulkan/vk_texture_cache.cpp
  3. 63
      src/video_core/renderer_vulkan/vk_texture_cache.h

30
src/video_core/renderer_vulkan/pipeline_helper.h

@ -13,6 +13,7 @@
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h"
#include "video_core/texture_cache/types.h" #include "video_core/texture_cache/types.h"
#include "video_core/surface.h"
#include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_device.h"
namespace Vulkan { namespace Vulkan {
@ -193,8 +194,33 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
const Sampler& sampler{texture_cache.GetSampler(sampler_id)}; const Sampler& sampler{texture_cache.GetSampler(sampler_id)};
const bool use_fallback_sampler{sampler.HasAddedAnisotropy() && const bool use_fallback_sampler{sampler.HasAddedAnisotropy() &&
!image_view.SupportsAnisotropy()}; !image_view.SupportsAnisotropy()};
const VkSampler vk_sampler{use_fallback_sampler ? sampler.HandleWithDefaultAnisotropy()
: sampler.Handle()};
const auto format_type = VideoCore::Surface::GetFormatType(image_view.format);
const bool view_supports_depth_compare =
format_type == VideoCore::Surface::SurfaceType::Depth ||
format_type == VideoCore::Surface::SurfaceType::DepthStencil;
const bool force_disable_compare =
sampler.DepthCompareEnabled() && !view_supports_depth_compare;
const bool is_integer_format = VideoCore::Surface::IsPixelFormatInteger(image_view.format);
const bool needs_nearest = is_integer_format && sampler.HasLinearFiltering();
VkSampler vk_sampler{};
if (use_fallback_sampler) {
if (needs_nearest) {
vk_sampler = force_disable_compare
? sampler.HandleNearestWithDefaultAnisotropyNoCompare()
: sampler.HandleNearestWithDefaultAnisotropy();
} else {
vk_sampler = force_disable_compare
? sampler.HandleWithDefaultAnisotropyNoCompare()
: sampler.HandleWithDefaultAnisotropy();
}
} else {
if (needs_nearest) {
vk_sampler = force_disable_compare ? sampler.HandleNearestNoCompare()
: sampler.HandleNearest();
} else {
vk_sampler = force_disable_compare ? sampler.HandleNoCompare() : sampler.Handle();
}
}
guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler); guest_descriptor_queue.AddSampledImage(vk_image_view, vk_sampler);
rescaling.PushTexture(texture_cache.IsRescaling(image_view)); rescaling.PushTexture(texture_cache.IsRescaling(image_view));
} }

70
src/video_core/renderer_vulkan/vk_texture_cache.cpp

@ -2209,6 +2209,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
const auto& device = runtime.device; const auto& device = runtime.device;
const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported(); const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
const auto color = tsc.BorderColor(); const auto color = tsc.BorderColor();
compare_enabled = tsc.depth_compare_enabled != 0;
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{ const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
@ -2234,21 +2235,52 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
// Some games have samplers with garbage. Sanitize them here. // Some games have samplers with garbage. Sanitize them here.
const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f); const f32 max_anisotropy = std::clamp(tsc.MaxAnisotropy(), 1.0f, 16.0f);
const auto create_sampler = [&](const f32 anisotropy) {
const VkFilter orig_mag = MaxwellToVK::Sampler::Filter(tsc.mag_filter);
const VkFilter orig_min = MaxwellToVK::Sampler::Filter(tsc.min_filter);
const VkSamplerMipmapMode orig_mipmap = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter);
has_linear_filtering = (orig_mag == VK_FILTER_LINEAR) || (orig_min == VK_FILTER_LINEAR) ||
(orig_mipmap == VK_SAMPLER_MIPMAP_MODE_LINEAR);
const auto create_sampler = [&](const f32 anisotropy, VkBool32 compare_enable) {
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = pnext,
.flags = 0,
.magFilter = orig_mag,
.minFilter = orig_min,
.mipmapMode = orig_mipmap,
.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<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = anisotropy,
.compareEnable = compare_enable,
.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_force_nearest = [&](const f32 anisotropy, VkBool32 compare_enable) {
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{ return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.pNext = pnext, .pNext = pnext,
.flags = 0, .flags = 0,
.magFilter = MaxwellToVK::Sampler::Filter(tsc.mag_filter),
.minFilter = MaxwellToVK::Sampler::Filter(tsc.min_filter),
.mipmapMode = MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter),
.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), .addressModeU = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_u, tsc.mag_filter),
.addressModeV = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_v, 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), .addressModeW = MaxwellToVK::Sampler::WrapMode(device, tsc.wrap_p, tsc.mag_filter),
.mipLodBias = tsc.LodBias(), .mipLodBias = tsc.LodBias(),
.anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE), .anisotropyEnable = static_cast<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE),
.maxAnisotropy = anisotropy, .maxAnisotropy = anisotropy,
.compareEnable = tsc.depth_compare_enabled,
.compareEnable = compare_enable,
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), .compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), .minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(), .maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
@ -2258,11 +2290,35 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
}); });
}; };
sampler = create_sampler(max_anisotropy);
const VkBool32 compare_flag = compare_enabled ? VK_TRUE : VK_FALSE;
sampler = create_sampler(max_anisotropy, compare_flag);
if (compare_enabled) {
sampler_no_compare = create_sampler(max_anisotropy, VK_FALSE);
}
const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy); const f32 max_anisotropy_default = static_cast<f32>(1U << tsc.max_anisotropy);
if (max_anisotropy > max_anisotropy_default) { if (max_anisotropy > max_anisotropy_default) {
sampler_default_anisotropy = create_sampler(max_anisotropy_default);
sampler_default_anisotropy = create_sampler(max_anisotropy_default, compare_flag);
if (compare_enabled) {
sampler_default_anisotropy_no_compare =
create_sampler(max_anisotropy_default, VK_FALSE);
}
}
// If any linear filtering was requested, create forced-nearest variants for integer formats.
if (has_linear_filtering) {
sampler_nearest = create_sampler_force_nearest(max_anisotropy, compare_flag);
if (compare_enabled) {
sampler_nearest_no_compare = create_sampler_force_nearest(max_anisotropy, VK_FALSE);
}
if (max_anisotropy > max_anisotropy_default) {
sampler_nearest_default_anisotropy =
create_sampler_force_nearest(max_anisotropy_default, compare_flag);
if (compare_enabled) {
sampler_nearest_default_anisotropy_no_compare =
create_sampler_force_nearest(max_anisotropy_default, VK_FALSE);
}
}
} }
} }

63
src/video_core/renderer_vulkan/vk_texture_cache.h

@ -299,13 +299,76 @@ public:
return *sampler_default_anisotropy; return *sampler_default_anisotropy;
} }
[[nodiscard]] VkSampler HandleNoCompare() const noexcept {
if (compare_enabled && sampler_no_compare) {
return *sampler_no_compare;
}
return *sampler;
}
[[nodiscard]] VkSampler HandleWithDefaultAnisotropyNoCompare() const noexcept {
if (compare_enabled && sampler_default_anisotropy_no_compare) {
return *sampler_default_anisotropy_no_compare;
}
if (sampler_default_anisotropy) {
return *sampler_default_anisotropy;
}
return HandleNoCompare();
}
// Forced-nearest variants used when sampling integer formats that cannot be linearly filtered.
[[nodiscard]] VkSampler HandleNearest() const noexcept {
if (sampler_nearest) {
return *sampler_nearest;
}
return Handle();
}
[[nodiscard]] VkSampler HandleNearestNoCompare() const noexcept {
if (compare_enabled && sampler_nearest_no_compare) {
return *sampler_nearest_no_compare;
}
return HandleNearest();
}
[[nodiscard]] VkSampler HandleNearestWithDefaultAnisotropy() const noexcept {
if (sampler_nearest_default_anisotropy) {
return *sampler_nearest_default_anisotropy;
}
return HandleNearest();
}
[[nodiscard]] VkSampler HandleNearestWithDefaultAnisotropyNoCompare() const noexcept {
if (compare_enabled && sampler_nearest_default_anisotropy_no_compare) {
return *sampler_nearest_default_anisotropy_no_compare;
}
return HandleNearestWithDefaultAnisotropy();
}
[[nodiscard]] bool HasAddedAnisotropy() const noexcept { [[nodiscard]] bool HasAddedAnisotropy() const noexcept {
return static_cast<bool>(sampler_default_anisotropy); return static_cast<bool>(sampler_default_anisotropy);
} }
[[nodiscard]] bool DepthCompareEnabled() const noexcept {
return compare_enabled;
}
// Whether the original sampler requested any linear filtering (min/mag/mipmap)
[[nodiscard]] bool HasLinearFiltering() const noexcept {
return has_linear_filtering;
}
private: private:
vk::Sampler sampler; vk::Sampler sampler;
vk::Sampler sampler_default_anisotropy; vk::Sampler sampler_default_anisotropy;
vk::Sampler sampler_no_compare;
vk::Sampler sampler_default_anisotropy_no_compare;
vk::Sampler sampler_nearest;
vk::Sampler sampler_nearest_default_anisotropy;
vk::Sampler sampler_nearest_no_compare;
vk::Sampler sampler_nearest_default_anisotropy_no_compare;
bool compare_enabled{};
bool has_linear_filtering{};
}; };
class Framebuffer { class Framebuffer {

Loading…
Cancel
Save