[TEST] Return Xenoblade workaround + extend srgb handling on border colors

This commit is contained in:
CamilleLaVey
2026-08-16 18:57:37 -04:00
parent 8e687924b8
commit 3379556d89
5 changed files with 53 additions and 6 deletions
@@ -383,6 +383,10 @@ inline void PushImageDescriptors(TextureCache& texture_cache,
!image_view.SupportsDepthComparison()) {
vk_sampler = sampler.HandleWithoutDepthComparison();
}
if (sampler.HasSrgbBorderColor() &&
VideoCore::Surface::IsPixelFormatSRGB(image_view.format)) {
vk_sampler = sampler.HandleWithSrgbBorderColor();
}
if (sampler.HasMinmaxReduction() && !image_view.SupportsMinmaxFilter()) {
vk_sampler = sampler.HandleWithDefaultReduction();
}
@@ -2607,6 +2607,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
const auto& device = runtime.device;
const bool has_custom_border_colors = runtime.device.IsCustomBorderColorUsable();
const auto color = tsc.BorderColor();
const auto srgb_color = tsc.SrgbBorderColor();
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
@@ -2614,9 +2615,17 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
.customBorderColor = std::bit_cast<VkClearColorValue>(color),
.format = VK_FORMAT_UNDEFINED,
};
const VkSamplerCustomBorderColorCreateInfoEXT srgb_border_ci{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
.pNext = nullptr,
.customBorderColor = std::bit_cast<VkClearColorValue>(srgb_color),
.format = VK_FORMAT_UNDEFINED,
};
const void* pnext = nullptr;
const void* srgb_pnext = nullptr;
if (has_custom_border_colors) {
pnext = &border_ci;
srgb_pnext = &srgb_border_ci;
if (GPU::Logging::IsActive()) {
GPU::Logging::GPULogger::GetInstance().LogExtensionUsage(
"VK_EXT_custom_border_color", "Sampler::Sampler");
@@ -2631,6 +2640,11 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
.pNext = pnext,
.reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter),
};
const VkSamplerReductionModeCreateInfoEXT reduction_ci_srgb{
.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
.pNext = srgb_pnext,
.reductionMode = MaxwellToVK::SamplerReduction(tsc.reduction_filter),
};
const VkSamplerReductionModeCreateInfoEXT reduction_ci_without_border{
.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT,
.pNext = nullptr,
@@ -2642,6 +2656,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT;
if (runtime.device.IsExtSamplerFilterMinmaxSupported()) {
pnext = &reduction_ci;
srgb_pnext = &reduction_ci_srgb;
pnext_without_border = &reduction_ci_without_border;
} else if (reduction_ci.reductionMode != VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT) {
LOG_WARNING(Render_Vulkan, "VK_EXT_sampler_filter_minmax is required");
@@ -2659,16 +2674,29 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
const auto create_sampler = [&](const f32 anisotropy, bool force_nearest,
bool disable_compare = false,
bool disable_custom_border = false,
bool disable_minmax = false) {
bool disable_minmax = false, bool use_srgb_border = false) {
const bool custom_border = has_custom_border_colors && !disable_custom_border;
const bool minmax = has_minmax_reduction && !disable_minmax;
const void* chain = nullptr;
if (custom_border && minmax) {
chain = pnext;
if (use_srgb_border) {
chain = srgb_pnext;
}
} else if (minmax) {
chain = pnext_without_border;
} else if (custom_border) {
chain = &border_ci;
if (use_srgb_border) {
chain = &srgb_border_ci;
}
}
VkBorderColor fixed_border = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT;
if (!custom_border) {
fixed_border = ConvertBorderColor(color);
if (use_srgb_border) {
fixed_border = ConvertBorderColor(srgb_color);
}
}
return device.GetLogical().CreateSampler(VkSamplerCreateInfo{
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
@@ -2689,8 +2717,7 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
.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 = custom_border ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT
: ConvertBorderColor(color),
.borderColor = fixed_border,
.unnormalizedCoordinates = VK_FALSE,
});
};
@@ -2713,6 +2740,10 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
if (has_minmax_reduction) {
sampler_default_reduction = create_sampler(max_anisotropy, false, false, false, true);
}
if (tsc.srgb_conversion && srgb_color != color) {
sampler_srgb_border =
create_sampler(max_anisotropy, false, false, false, false, true);
}
}
Framebuffer::Framebuffer(TextureCacheRuntime& runtime, std::span<ImageView*, NUM_RT> color_buffers,
@@ -509,6 +509,14 @@ public:
return static_cast<bool>(sampler_default_reduction);
}
[[nodiscard]] VkSampler HandleWithSrgbBorderColor() const noexcept {
return *sampler_srgb_border;
}
[[nodiscard]] bool HasSrgbBorderColor() const noexcept {
return static_cast<bool>(sampler_srgb_border);
}
private:
vk::Sampler sampler;
vk::Sampler sampler_default_anisotropy;
@@ -516,6 +524,7 @@ private:
vk::Sampler sampler_noncompare;
vk::Sampler sampler_default_border;
vk::Sampler sampler_default_reduction;
vk::Sampler sampler_srgb_border;
};
struct TextureCacheParams {
+4 -3
View File
@@ -29,9 +29,10 @@ float SrgbToLinear(u32 value) {
} // Anonymous namespace
std::array<float, 4> TSCEntry::BorderColor() const noexcept {
if (!srgb_conversion) {
return border_color;
}
return border_color;
}
std::array<float, 4> TSCEntry::SrgbBorderColor() const noexcept {
return {SrgbToLinear(srgb_border_color_r), SrgbToLinear(srgb_border_color_g),
SrgbToLinear(srgb_border_color_b), border_color[3]};
}
+2
View File
@@ -378,6 +378,8 @@ struct TSCEntry {
std::array<float, 4> BorderColor() const noexcept;
std::array<float, 4> SrgbBorderColor() const noexcept;
float MaxAnisotropy() const noexcept;
float MinLod() const {