implement sampler states

This commit is contained in:
Samuliak 2024-08-03 19:58:40 +02:00
parent d2edc41680
commit ce6d4cacd1
3 changed files with 127 additions and 4 deletions

View File

@ -1,6 +1,7 @@
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
#include "Common/precompiled.h"
#include "Metal/MTLDepthStencil.hpp"
#include "Metal/MTLSampler.hpp"
std::map<Latte::E_GX2SURFFMT, MtlPixelFormatInfo> MTL_COLOR_FORMAT_TABLE = {
{Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatRG8Unorm, 2}}, // TODO: correct?
@ -272,3 +273,21 @@ MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func)
cemu_assert_debug((uint32)func < std::size(MTL_COMPARE_FUNCTIONS));
return MTL_COMPARE_FUNCTIONS[(uint32)func];
}
// TODO: clamp to border color? (should be fine though)
const MTL::SamplerAddressMode MTL_SAMPLER_ADDRESS_MODES[] = {
MTL::SamplerAddressModeRepeat, // WRAP
MTL::SamplerAddressModeMirrorRepeat, // MIRROR
MTL::SamplerAddressModeClampToEdge, // CLAMP_LAST_TEXEL
MTL::SamplerAddressModeMirrorClampToEdge, // MIRROR_ONCE_LAST_TEXEL
MTL::SamplerAddressModeClampToEdge, // unsupported HALF_BORDER
MTL::SamplerAddressModeClampToBorderColor, // unsupported MIRROR_ONCE_HALF_BORDER
MTL::SamplerAddressModeClampToBorderColor, // CLAMP_BORDER
MTL::SamplerAddressModeClampToBorderColor // MIRROR_ONCE_BORDER
};
MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp)
{
cemu_assert_debug((uint32)clamp < std::size(MTL_SAMPLER_ADDRESS_MODES));
return MTL_SAMPLER_ADDRESS_MODES[(uint32)clamp];
}

View File

@ -7,6 +7,7 @@
//#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Metal/MTLDepthStencil.hpp"
#include "Metal/MTLSampler.hpp"
struct Uvec2 {
uint32 x;
@ -36,3 +37,5 @@ MTL::BlendOperation GetMtlBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC
MTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR factor);
MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func);
MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp);

View File

@ -15,8 +15,8 @@
#include "Cafe/HW/Latte/Core/LatteIndices.h"
#include "Cemu/Logging/CemuDebugLogging.h"
#include "HW/Latte/Core/Latte.h"
#include "HW/Latte/ISA/LatteReg.h"
#include "gui/guiWrapper.h"
#include <stdexcept>
extern bool hasValidFramebufferAttached;
@ -863,7 +863,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
continue;
}
//LatteTexture* baseTexture = textureView->baseTexture;
LatteTexture* baseTexture = textureView->baseTexture;
// get texture register word 0
uint32 word4 = LatteGPUState.contextRegister[texUnitRegIndex + 4];
@ -878,8 +878,108 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
uint32 stageSamplerIndex = shader->textureUnitSamplerAssignment[relative_textureUnit];
if (stageSamplerIndex != LATTE_DECOMPILER_SAMPLER_NONE)
{
// TODO: bind the actual sampler
MTL::SamplerState* sampler = m_nearestSampler;
uint32 samplerIndex = stageSamplerIndex + LatteDecompiler_getTextureSamplerBaseIndex(shader->shaderType);
const _LatteRegisterSetSampler* samplerWords = LatteGPUState.contextNew.SQ_TEX_SAMPLER + samplerIndex;
// TODO: cache this instead
MTL::SamplerDescriptor* samplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
// lod
uint32 iMinLOD = samplerWords->WORD1.get_MIN_LOD();
uint32 iMaxLOD = samplerWords->WORD1.get_MAX_LOD();
sint32 iLodBias = samplerWords->WORD1.get_LOD_BIAS();
// apply relative lod bias from graphic pack
if (baseTexture->overwriteInfo.hasRelativeLodBias)
iLodBias += baseTexture->overwriteInfo.relativeLodBias;
// apply absolute lod bias from graphic pack
if (baseTexture->overwriteInfo.hasLodBias)
iLodBias = baseTexture->overwriteInfo.lodBias;
auto filterMip = samplerWords->WORD0.get_MIP_FILTER();
if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::NONE)
{
samplerDescriptor->setMipFilter(MTL::SamplerMipFilterNearest);
samplerDescriptor->setLodMinClamp(0.0f);
samplerDescriptor->setLodMaxClamp(0.25f);
}
else if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::POINT)
{
samplerDescriptor->setMipFilter(MTL::SamplerMipFilterNearest);
samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);
samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);
}
else if (filterMip == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_Z_FILTER::LINEAR)
{
samplerDescriptor->setMipFilter(MTL::SamplerMipFilterLinear);
samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);
samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);
}
else
{
// fallback for invalid constants
samplerDescriptor->setMipFilter(MTL::SamplerMipFilterLinear);
samplerDescriptor->setLodMinClamp((float)iMinLOD / 64.0f);
samplerDescriptor->setLodMaxClamp((float)iMaxLOD / 64.0f);
}
auto filterMin = samplerWords->WORD0.get_XY_MIN_FILTER();
cemu_assert_debug(filterMin != Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::BICUBIC); // todo
samplerDescriptor->setMinFilter((filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? MTL::SamplerMinMagFilterNearest : MTL::SamplerMinMagFilterLinear);
auto filterMag = samplerWords->WORD0.get_XY_MAG_FILTER();
samplerDescriptor->setMagFilter((filterMag == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::POINT || filterMin == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_XY_FILTER::ANISO_POINT) ? MTL::SamplerMinMagFilterNearest : MTL::SamplerMinMagFilterLinear);
auto filterZ = samplerWords->WORD0.get_Z_FILTER();
// todo: z-filter for texture array samplers is customizable for GPU7 but OpenGL/Vulkan doesn't expose this functionality?
auto clampX = samplerWords->WORD0.get_CLAMP_X();
auto clampY = samplerWords->WORD0.get_CLAMP_Y();
auto clampZ = samplerWords->WORD0.get_CLAMP_Z();
samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampX));
samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampY));
samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampZ));
auto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO();
if (baseTexture->overwriteInfo.anisotropicLevel >= 0)
maxAniso = baseTexture->overwriteInfo.anisotropicLevel;
if (maxAniso > 0)
{
samplerDescriptor->setMaxAnisotropy(1 << maxAniso);
}
// TODO: set lod bias
//samplerInfo.mipLodBias = (float)iLodBias / 64.0f;
// depth compare
uint8 depthCompareMode = shader->textureUsesDepthCompare[relative_textureUnit] ? 1 : 0;
if (depthCompareMode == 1)
{
// TODO: is it okay to just cast?
samplerDescriptor->setCompareFunction(GetMtlCompareFunc((Latte::E_COMPAREFUNC)samplerWords->WORD0.get_DEPTH_COMPARE_FUNCTION()));
}
// border
auto borderType = samplerWords->WORD0.get_BORDER_COLOR_TYPE();
if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::TRANSPARENT_BLACK)
samplerDescriptor->setBorderColor(MTL::SamplerBorderColorTransparentBlack);
else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_BLACK)
samplerDescriptor->setBorderColor(MTL::SamplerBorderColorOpaqueBlack);
else if (borderType == Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_BORDER_COLOR_TYPE::OPAQUE_WHITE)
samplerDescriptor->setBorderColor(MTL::SamplerBorderColorOpaqueWhite);
else
{
// Metal doesn't support custom border color
samplerDescriptor->setBorderColor(MTL::SamplerBorderColorOpaqueBlack);
}
MTL::SamplerState* sampler = m_device->newSamplerState(samplerDescriptor);
samplerDescriptor->release();
switch (shader->shaderType)
{
case LatteConst::ShaderType::Vertex:
@ -895,6 +995,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
default:
UNREACHABLE;
}
sampler->release();
}
switch (shader->shaderType)