From 24e1bba31cf7aa1e9f4066b960e9ca7230d2ffc9 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sun, 26 Jan 2025 10:23:07 +0100 Subject: [PATCH] choose the closest matching sampler border color --- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 3 +- .../Renderer/Metal/MetalSamplerCache.cpp | 73 +++++++++++++++---- .../Latte/Renderer/Metal/MetalSamplerCache.h | 5 +- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index eccab5ab..93f330c0 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -2049,8 +2049,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE MTL::SamplerState* sampler; if (stageSamplerIndex != LATTE_DECOMPILER_SAMPLER_NONE) { - uint32 samplerIndex = stageSamplerIndex + LatteDecompiler_getTextureSamplerBaseIndex(shader->shaderType); - sampler = m_samplerCache->GetSamplerState(LatteGPUState.contextNew, samplerIndex); + sampler = m_samplerCache->GetSamplerState(LatteGPUState.contextNew, shader->shaderType, stageSamplerIndex); } else { diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.cpp index a4d734ee..abc3d19c 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.cpp @@ -1,6 +1,21 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" -#include "HW/Latte/Renderer/Metal/LatteToMtl.h" +#include "Cafe/HW/Latte/Core/LatteShader.h" +#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" +#include "Metal/MTLSampler.hpp" + +inline const char* BorderColorToStr(MTL::SamplerBorderColor borderColor) +{ + switch (borderColor) + { + case MTL::SamplerBorderColorTransparentBlack: + return "transparent black"; + case MTL::SamplerBorderColorOpaqueBlack: + return "opaque black"; + case MTL::SamplerBorderColorOpaqueWhite: + return "opaque white"; + } +} MetalSamplerCache::~MetalSamplerCache() { @@ -11,9 +26,11 @@ MetalSamplerCache::~MetalSamplerCache() m_samplerCache.clear(); } -MTL::SamplerState* MetalSamplerCache::GetSamplerState(const LatteContextRegister& lcr, uint32 samplerIndex) +MTL::SamplerState* MetalSamplerCache::GetSamplerState(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex) { - uint64 stateHash = CalculateSamplerHash(lcr, samplerIndex); + uint32 samplerIndex = stageSamplerIndex + LatteDecompiler_getTextureSamplerBaseIndex(shaderType); + + uint64 stateHash = CalculateSamplerHash(lcr, shaderType, stageSamplerIndex, samplerIndex); auto& samplerState = m_samplerCache[stateHash]; if (samplerState) return samplerState; @@ -77,9 +94,9 @@ MTL::SamplerState* MetalSamplerCache::GetSamplerState(const LatteContextRegister auto clampY = samplerWords->WORD0.get_CLAMP_Y(); auto clampZ = samplerWords->WORD0.get_CLAMP_Z(); - samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampX)); - samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampY)); - samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampZ)); + samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampX)); + samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampY)); + samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampZ)); auto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO(); @@ -101,25 +118,53 @@ MTL::SamplerState* MetalSamplerCache::GetSamplerState(const LatteContextRegister // border auto borderType = samplerWords->WORD0.get_BORDER_COLOR_TYPE(); + MTL::SamplerBorderColor borderColor; if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::TRANSPARENT_BLACK) - samplerDescriptor->setBorderColor(MTL::SamplerBorderColorTransparentBlack); + borderColor = MTL::SamplerBorderColorTransparentBlack; else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_BLACK) - samplerDescriptor->setBorderColor(MTL::SamplerBorderColorOpaqueBlack); + borderColor = MTL::SamplerBorderColorOpaqueBlack; else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_WHITE) - samplerDescriptor->setBorderColor(MTL::SamplerBorderColorOpaqueWhite); - else + borderColor = MTL::SamplerBorderColorOpaqueWhite; + else [[unlikely]] { - // Metal doesn't support custom border color - cemuLog_logOnce(LogType::Force, "Custom border color is not supported in Metal, using transparent black instead"); - samplerDescriptor->setBorderColor(MTL::SamplerBorderColorTransparentBlack); + _LatteRegisterSetSamplerBorderColor* borderColorReg; + if (shaderType == LatteConst::ShaderType::Vertex) + borderColorReg = LatteGPUState.contextNew.TD_VS_SAMPLER_BORDER_COLOR + stageSamplerIndex; + else if (shaderType == LatteConst::ShaderType::Pixel) + borderColorReg = LatteGPUState.contextNew.TD_PS_SAMPLER_BORDER_COLOR + stageSamplerIndex; + else // geometry + borderColorReg = LatteGPUState.contextNew.TD_GS_SAMPLER_BORDER_COLOR + stageSamplerIndex; + float r = borderColorReg->red.get_channelValue(); + float g = borderColorReg->green.get_channelValue(); + float b = borderColorReg->blue.get_channelValue(); + float a = borderColorReg->alpha.get_channelValue(); + + // Metal doesn't support custom border color + // Let's find the best match + bool opaque = (a == 1.0f); + bool white = (r == 1.0f); + if (opaque) + { + if (white) + borderColor = MTL::SamplerBorderColorOpaqueWhite; + else + borderColor = MTL::SamplerBorderColorOpaqueBlack; + } + else + { + borderColor = MTL::SamplerBorderColorTransparentBlack; + } + + cemuLog_log(LogType::Force, "Custom border color ({}, {}, {}, {}) is not supported on Metal, using {} instead", r, g, b, a, BorderColorToStr(borderColor)); } + samplerDescriptor->setBorderColor(borderColor); samplerState = m_mtlr->GetDevice()->newSamplerState(samplerDescriptor); return samplerState; } -uint64 MetalSamplerCache::CalculateSamplerHash(const LatteContextRegister& lcr, uint32 samplerIndex) +uint64 MetalSamplerCache::CalculateSamplerHash(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, uint32 samplerIndex) { const _LatteRegisterSetSampler* samplerWords = lcr.SQ_TEX_SAMPLER + samplerIndex; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h index 891d7e03..17857f0e 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalSamplerCache.h @@ -2,6 +2,7 @@ #include +#include "HW/Latte/Core/LatteConst.h" #include "HW/Latte/ISA/LatteReg.h" class MetalSamplerCache @@ -10,12 +11,12 @@ public: MetalSamplerCache(class MetalRenderer* metalRenderer) : m_mtlr{metalRenderer} {} ~MetalSamplerCache(); - MTL::SamplerState* GetSamplerState(const LatteContextRegister& lcr, uint32 samplerIndex); + MTL::SamplerState* GetSamplerState(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex); private: class MetalRenderer* m_mtlr; std::map m_samplerCache; - uint64 CalculateSamplerHash(const LatteContextRegister& lcr, uint32 samplerIndex); + uint64 CalculateSamplerHash(const LatteContextRegister& lcr, LatteConst::ShaderType shaderType, uint32 stageSamplerIndex, uint32 samplerIndex); };