From 3379556d8930dd59abc4ab7dbba5f9640401663f Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Sun, 16 Aug 2026 18:57:37 -0400 Subject: [PATCH] [TEST] Return Xenoblade workaround + extend srgb handling on border colors --- .../renderer_vulkan/pipeline_helper.h | 4 ++ .../renderer_vulkan/vk_texture_cache.cpp | 37 +++++++++++++++++-- .../renderer_vulkan/vk_texture_cache.h | 9 +++++ src/video_core/textures/texture.cpp | 7 ++-- src/video_core/textures/texture.h | 2 + 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 8a4cb6273f..7a71c68c08 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -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(); } diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 7dc73274dd..69d3f745a8 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -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(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(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 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 bea9964313..0dfd87292d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -509,6 +509,14 @@ public: return static_cast(sampler_default_reduction); } + [[nodiscard]] VkSampler HandleWithSrgbBorderColor() const noexcept { + return *sampler_srgb_border; + } + + [[nodiscard]] bool HasSrgbBorderColor() const noexcept { + return static_cast(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 { diff --git a/src/video_core/textures/texture.cpp b/src/video_core/textures/texture.cpp index 1d899eb490..dc3b0b8244 100644 --- a/src/video_core/textures/texture.cpp +++ b/src/video_core/textures/texture.cpp @@ -29,9 +29,10 @@ float SrgbToLinear(u32 value) { } // Anonymous namespace std::array TSCEntry::BorderColor() const noexcept { - if (!srgb_conversion) { - return border_color; - } + return border_color; +} + +std::array TSCEntry::SrgbBorderColor() const noexcept { return {SrgbToLinear(srgb_border_color_r), SrgbToLinear(srgb_border_color_g), SrgbToLinear(srgb_border_color_b), border_color[3]}; } diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 7e5837b206..112885f0c3 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -378,6 +378,8 @@ struct TSCEntry { std::array BorderColor() const noexcept; + std::array SrgbBorderColor() const noexcept; + float MaxAnisotropy() const noexcept; float MinLod() const {