|
|
|
@ -2326,20 +2326,28 @@ 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 VkFilter mag_filter{MaxwellToVK::Sampler::Filter(tsc.mag_filter)}; |
|
|
|
const VkFilter min_filter{MaxwellToVK::Sampler::Filter(tsc.min_filter)}; |
|
|
|
const VkSamplerMipmapMode mipmap_mode{MaxwellToVK::Sampler::MipmapMode(tsc.mipmap_filter)}; |
|
|
|
const bool has_linear_filtering{mag_filter == VK_FILTER_LINEAR || |
|
|
|
min_filter == VK_FILTER_LINEAR || |
|
|
|
mipmap_mode == VK_SAMPLER_MIPMAP_MODE_LINEAR}; |
|
|
|
|
|
|
|
const auto create_sampler = [&](const f32 anisotropy, bool force_nearest) { |
|
|
|
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 = force_nearest ? VK_FILTER_NEAREST : mag_filter, |
|
|
|
.minFilter = force_nearest ? VK_FILTER_NEAREST : min_filter, |
|
|
|
.mipmapMode = force_nearest ? VK_SAMPLER_MIPMAP_MODE_NEAREST : 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<VkBool32>(anisotropy > 1.0f ? VK_TRUE : VK_FALSE), |
|
|
|
.maxAnisotropy = anisotropy, |
|
|
|
.anisotropyEnable = |
|
|
|
static_cast<VkBool32>(!force_nearest && anisotropy > 1.0f ? VK_TRUE : VK_FALSE), |
|
|
|
.maxAnisotropy = force_nearest ? 1.0f : anisotropy, |
|
|
|
.compareEnable = tsc.depth_compare_enabled, |
|
|
|
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func), |
|
|
|
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(), |
|
|
|
@ -2350,11 +2358,18 @@ 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<f32>(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); |
|
|
|
} |
|
|
|
if (has_linear_filtering) { |
|
|
|
// Integer-format image views can never be linearly filtered
|
|
|
|
// (VUID-vkCmdDraw*-magFilter-04553); this sampler is cached purely from the guest's TSC,
|
|
|
|
// decoupled from whichever ImageView it ends up paired with, so build a nearest-forced
|
|
|
|
// fallback here for callers to swap to when the paired view turns out to be integer.
|
|
|
|
sampler_nearest = create_sampler(1.0f, true); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|