Provide custom border color to samplers (#3014)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / linux-sdl-gcc (push) Blocked by required conditions
Build and Release / linux-qt-gcc (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions

This commit is contained in:
Marcin Mikołajczyk 2025-05-30 21:04:31 +02:00 committed by GitHub
parent 790b54bf29
commit 4019319d92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 53 additions and 8 deletions

View file

@ -608,6 +608,16 @@ struct Liverpool {
} }
}; };
struct BorderColorBufferBase {
u32 base_addr_lo;
BitField<0, 8, u32> base_addr_hi;
template <typename T = VAddr>
T Address() const {
return std::bit_cast<T>(u64(base_addr_hi) << 40 | u64(base_addr_lo) << 8);
}
};
struct IndexBufferBase { struct IndexBufferBase {
BitField<0, 8, u32> base_addr_hi; BitField<0, 8, u32> base_addr_hi;
u32 base_addr_lo; u32 base_addr_lo;
@ -1299,7 +1309,9 @@ struct Liverpool {
Scissor screen_scissor; Scissor screen_scissor;
INSERT_PADDING_WORDS(0xA010 - 0xA00C - 2); INSERT_PADDING_WORDS(0xA010 - 0xA00C - 2);
DepthBuffer depth_buffer; DepthBuffer depth_buffer;
INSERT_PADDING_WORDS(0xA080 - 0xA018); INSERT_PADDING_WORDS(8);
BorderColorBufferBase ta_bc_base;
INSERT_PADDING_WORDS(0xA080 - 0xA020 - 2);
WindowOffset window_offset; WindowOffset window_offset;
ViewportScissor window_scissor; ViewportScissor window_scissor;
INSERT_PADDING_WORDS(0xA08E - 0xA081 - 2); INSERT_PADDING_WORDS(0xA08E - 0xA081 - 2);
@ -1626,6 +1638,7 @@ static_assert(GFX6_3D_REG_INDEX(depth_htile_data_base) == 0xA005);
static_assert(GFX6_3D_REG_INDEX(screen_scissor) == 0xA00C); static_assert(GFX6_3D_REG_INDEX(screen_scissor) == 0xA00C);
static_assert(GFX6_3D_REG_INDEX(depth_buffer.z_info) == 0xA010); static_assert(GFX6_3D_REG_INDEX(depth_buffer.z_info) == 0xA010);
static_assert(GFX6_3D_REG_INDEX(depth_buffer.depth_slice) == 0xA017); static_assert(GFX6_3D_REG_INDEX(depth_buffer.depth_slice) == 0xA017);
static_assert(GFX6_3D_REG_INDEX(ta_bc_base) == 0xA020);
static_assert(GFX6_3D_REG_INDEX(window_offset) == 0xA080); static_assert(GFX6_3D_REG_INDEX(window_offset) == 0xA080);
static_assert(GFX6_3D_REG_INDEX(window_scissor) == 0xA081); static_assert(GFX6_3D_REG_INDEX(window_scissor) == 0xA081);
static_assert(GFX6_3D_REG_INDEX(color_target_mask) == 0xA08E); static_assert(GFX6_3D_REG_INDEX(color_target_mask) == 0xA08E);

View file

@ -716,7 +716,7 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One); ssharp.max_aniso.Assign(AmdGpu::AnisoRatio::One);
} }
} }
const auto vk_sampler = texture_cache.GetSampler(ssharp); const auto vk_sampler = texture_cache.GetSampler(ssharp, liverpool->regs.ta_bc_base);
image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral); image_infos.emplace_back(vk_sampler, VK_NULL_HANDLE, vk::ImageLayout::eGeneral);
set_writes.push_back({ set_writes.push_back({
.dstSet = VK_NULL_HANDLE, .dstSet = VK_NULL_HANDLE,

View file

@ -9,7 +9,8 @@
namespace VideoCore { namespace VideoCore {
Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler) { Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler,
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base) {
if (sampler.force_degamma) { if (sampler.force_degamma) {
LOG_WARNING(Render_Vulkan, "Texture requires gamma correction"); LOG_WARNING(Render_Vulkan, "Texture requires gamma correction");
} }
@ -20,7 +21,33 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
const float maxAnisotropy = const float maxAnisotropy =
anisotropyEnable ? std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy()) anisotropyEnable ? std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy())
: 1.0f; : 1.0f;
auto borderColor = LiverpoolToVK::BorderColor(sampler.border_color_type);
if (!instance.IsCustomBorderColorSupported()) {
LOG_WARNING(Render_Vulkan, "Custom border color is not supported, falling back to black");
borderColor = vk::BorderColor::eFloatOpaqueBlack;
}
const auto customColor = [&]() -> std::optional<vk::SamplerCustomBorderColorCreateInfoEXT> {
if (borderColor == vk::BorderColor::eFloatCustomEXT) {
const auto borderColorIndex = sampler.border_color_ptr.Value();
const auto borderColorBuffer = border_color_base.Address<std::array<float, 4>*>();
const auto customBorderColorArray = borderColorBuffer[borderColorIndex];
const vk::SamplerCustomBorderColorCreateInfoEXT ret{
.customBorderColor =
vk::ClearColorValue{
.float32 = customBorderColorArray,
},
.format = vk::Format::eR32G32B32A32Sfloat,
};
return ret;
} else {
return std::nullopt;
}
}();
const vk::SamplerCreateInfo sampler_ci = { const vk::SamplerCreateInfo sampler_ci = {
.pNext = customColor ? &*customColor : nullptr,
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter), .magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),
.minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter), .minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter),
.mipmapMode = LiverpoolToVK::MipFilter(sampler.mip_filter), .mipmapMode = LiverpoolToVK::MipFilter(sampler.mip_filter),
@ -34,7 +61,7 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
.compareOp = LiverpoolToVK::DepthCompare(sampler.depth_compare_func), .compareOp = LiverpoolToVK::DepthCompare(sampler.depth_compare_func),
.minLod = sampler.MinLod(), .minLod = sampler.MinLod(),
.maxLod = sampler.MaxLod(), .maxLod = sampler.MaxLod(),
.borderColor = LiverpoolToVK::BorderColor(sampler.border_color_type), .borderColor = borderColor,
.unnormalizedCoordinates = false, // Handled in shader due to Vulkan limitations. .unnormalizedCoordinates = false, // Handled in shader due to Vulkan limitations.
}; };
auto [sampler_result, smplr] = instance.GetDevice().createSamplerUnique(sampler_ci); auto [sampler_result, smplr] = instance.GetDevice().createSamplerUnique(sampler_ci);

View file

@ -14,7 +14,8 @@ namespace VideoCore {
class Sampler { class Sampler {
public: public:
explicit Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler); explicit Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sampler,
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base);
~Sampler(); ~Sampler();
Sampler(const Sampler&) = delete; Sampler(const Sampler&) = delete;

View file

@ -636,9 +636,11 @@ void TextureCache::RefreshImage(Image& image, Vulkan::Scheduler* custom_schedule
image.flags &= ~ImageFlagBits::Dirty; image.flags &= ~ImageFlagBits::Dirty;
} }
vk::Sampler TextureCache::GetSampler(const AmdGpu::Sampler& sampler) { vk::Sampler TextureCache::GetSampler(
const AmdGpu::Sampler& sampler,
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base) {
const u64 hash = XXH3_64bits(&sampler, sizeof(sampler)); const u64 hash = XXH3_64bits(&sampler, sizeof(sampler));
const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler); const auto [it, new_sampler] = samplers.try_emplace(hash, instance, sampler, border_color_base);
return it->second.Handle(); return it->second.Handle();
} }

View file

@ -139,7 +139,9 @@ public:
void RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler = nullptr); void RefreshImage(Image& image, Vulkan::Scheduler* custom_scheduler = nullptr);
/// Retrieves the sampler that matches the provided S# descriptor. /// Retrieves the sampler that matches the provided S# descriptor.
[[nodiscard]] vk::Sampler GetSampler(const AmdGpu::Sampler& sampler); [[nodiscard]] vk::Sampler GetSampler(
const AmdGpu::Sampler& sampler,
const AmdGpu::Liverpool::BorderColorBufferBase& border_color_base);
/// Retrieves the image with the specified id. /// Retrieves the image with the specified id.
[[nodiscard]] Image& GetImage(ImageId id) { [[nodiscard]] Image& GetImage(ImageId id) {