implement texture swizzle

This commit is contained in:
Samuliak 2024-08-06 10:23:57 +02:00
parent d64e64e5ef
commit 0a7f30c6a4
7 changed files with 164 additions and 68 deletions

View File

@ -15,7 +15,7 @@ void CachedFBOMtl::CreateRenderPass()
continue;
}
auto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(i);
colorAttachment->setTexture(textureView->GetTexture());
colorAttachment->setTexture(textureView->GetRGBAView());
colorAttachment->setLoadAction(MTL::LoadActionLoad);
colorAttachment->setStoreAction(MTL::StoreActionStore);
}
@ -25,7 +25,7 @@ void CachedFBOMtl::CreateRenderPass()
{
auto textureView = static_cast<LatteTextureViewMtl*>(depthBuffer.texture);
auto depthAttachment = m_renderPassDescriptor->depthAttachment();
depthAttachment->setTexture(textureView->GetTexture());
depthAttachment->setTexture(textureView->GetRGBAView());
depthAttachment->setLoadAction(MTL::LoadActionLoad);
depthAttachment->setStoreAction(MTL::StoreActionStore);
}

View File

@ -4,58 +4,123 @@
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
LatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_format(format)
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_baseTexture(texture)
{
MTL::TextureType textureType;
switch (dim)
{
case Latte::E_DIM::DIM_1D:
textureType = MTL::TextureType1D;
break;
case Latte::E_DIM::DIM_2D:
case Latte::E_DIM::DIM_2D_MSAA:
textureType = MTL::TextureType2D;
break;
case Latte::E_DIM::DIM_2D_ARRAY:
textureType = MTL::TextureType2DArray;
break;
case Latte::E_DIM::DIM_3D:
textureType = MTL::TextureType3D;
break;
case Latte::E_DIM::DIM_CUBEMAP:
textureType = MTL::TextureTypeCube; // TODO: check this
break;
default:
cemu_assert_unimplemented();
textureType = MTL::TextureType2D;
break;
}
uint32 baseLevel = firstMip;
uint32 levelCount = this->numMip;
uint32 baseLayer;
uint32 layerCount;
// TODO: check if base texture is 3D texture as well
if (textureType == MTL::TextureType3D)
{
cemu_assert_debug(firstMip == 0);
cemu_assert_debug(this->numSlice == baseTexture->depth);
baseLayer = 0;
layerCount = 1;
}
else
{
baseLayer = firstSlice;
layerCount = this->numSlice;
}
// TODO: swizzle
auto formatInfo = GetMtlPixelFormatInfo(format, texture->IsDepth());
m_texture = texture->GetTexture()->newTextureView(formatInfo.pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount));
}
LatteTextureViewMtl::~LatteTextureViewMtl()
{
m_texture->release();
for (sint32 i = 0; i < std::size(m_viewCache); i++)
{
if (m_viewCache[i].key != INVALID_SWIZZLE)
m_viewCache[i].texture->release();
}
for (auto& [key, texture] : m_fallbackViewCache)
{
texture->release();
}
}
MTL::Texture* LatteTextureViewMtl::GetSwizzledView(uint32 gpuSamplerSwizzle)
{
// Mask out
gpuSamplerSwizzle &= 0x0FFF0000;
if (gpuSamplerSwizzle == RGBA_SWIZZLE)
{
return m_baseTexture->GetTexture();
}
else
{
// First, try to find a view in the cache
// Fast cache
sint32 freeIndex = -1;
for (sint32 i = 0; i < std::size(m_viewCache); i++)
{
if (m_viewCache[i].key == gpuSamplerSwizzle)
{
return m_viewCache[i].texture;
}
else if (m_viewCache[i].key == INVALID_SWIZZLE && freeIndex == -1)
{
freeIndex = i;
}
}
// Fallback cache
auto it = m_fallbackViewCache.find(gpuSamplerSwizzle);
if (it != m_fallbackViewCache.end())
{
return it->second;
}
MTL::Texture* texture = CreateSwizzledView(gpuSamplerSwizzle);
if (freeIndex != -1)
m_viewCache[freeIndex] = {gpuSamplerSwizzle, texture};
else
it->second = texture;
return texture;
}
}
MTL::Texture* LatteTextureViewMtl::CreateSwizzledView(uint32 gpuSamplerSwizzle)
{
uint32 compSelR = (gpuSamplerSwizzle >> 16) & 0x7;
uint32 compSelG = (gpuSamplerSwizzle >> 19) & 0x7;
uint32 compSelB = (gpuSamplerSwizzle >> 22) & 0x7;
uint32 compSelA = (gpuSamplerSwizzle >> 25) & 0x7;
// TODO: adjust
MTL::TextureType textureType;
switch (dim)
{
case Latte::E_DIM::DIM_1D:
textureType = MTL::TextureType1D;
break;
case Latte::E_DIM::DIM_2D:
case Latte::E_DIM::DIM_2D_MSAA:
textureType = MTL::TextureType2D;
break;
case Latte::E_DIM::DIM_2D_ARRAY:
textureType = MTL::TextureType2DArray;
break;
case Latte::E_DIM::DIM_3D:
textureType = MTL::TextureType3D;
break;
case Latte::E_DIM::DIM_CUBEMAP:
textureType = MTL::TextureTypeCube; // TODO: check this
break;
default:
cemu_assert_unimplemented();
textureType = MTL::TextureType2D;
break;
}
uint32 baseLevel = firstMip;
uint32 levelCount = this->numMip;
uint32 baseLayer;
uint32 layerCount;
// TODO: check if base texture is 3D texture as well
if (textureType == MTL::TextureType3D)
{
cemu_assert_debug(firstMip == 0);
cemu_assert_debug(this->numSlice == baseTexture->depth);
baseLayer = 0;
layerCount = 1;
}
else
{
baseLayer = firstSlice;
layerCount = this->numSlice;
}
// TODO: swizzle
auto formatInfo = GetMtlPixelFormatInfo(format, m_baseTexture->IsDepth());
MTL::Texture* texture = m_baseTexture->GetTexture()->newTextureView(formatInfo.pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount));
return texture;
}

View File

@ -1,27 +1,37 @@
#pragma once
#include <Metal/Metal.hpp>
#include <unordered_map>
#include "Cafe/HW/Latte/Core/LatteTexture.h"
#define RGBA_SWIZZLE 0x06880000
#define INVALID_SWIZZLE 0xFFFFFFFF
// TODO: test the swizzle
class LatteTextureViewMtl : public LatteTextureView
{
public:
LatteTextureViewMtl(class MetalRenderer* mtlRenderer, class LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount);
~LatteTextureViewMtl();
MTL::Texture* GetTexture() const {
return m_texture;
}
MTL::Texture* GetSwizzledView(uint32 gpuSamplerSwizzle);
Latte::E_GX2SURFFMT GetFormat() const {
return m_format;
MTL::Texture* GetRGBAView()
{
return GetSwizzledView(RGBA_SWIZZLE);
}
private:
class MetalRenderer* m_mtlr;
MTL::Texture* m_texture;
class LatteTextureMtl* m_baseTexture;
Latte::E_GX2SURFFMT m_format;
struct {
uint32 key;
MTL::Texture* texture;
} m_viewCache[4] = {{INVALID_SWIZZLE, nullptr}};
std::unordered_map<uint32, MTL::Texture*> m_fallbackViewCache;
MTL::Texture* CreateSwizzledView(uint32 gpuSamplerSwizzle);
};

View File

@ -419,3 +419,20 @@ MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WOR
cemu_assert_debug((uint32)clamp < std::size(MTL_SAMPLER_ADDRESS_MODES));
return MTL_SAMPLER_ADDRESS_MODES[(uint32)clamp];
}
const MTL::TextureSwizzle MTL_TEXTURE_SWIZZLES[] = {
MTL::TextureSwizzleRed,
MTL::TextureSwizzleGreen,
MTL::TextureSwizzleBlue,
MTL::TextureSwizzleAlpha,
MTL::TextureSwizzleZero,
MTL::TextureSwizzleOne,
MTL::TextureSwizzleZero,
MTL::TextureSwizzleZero
};
MTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle)
{
cemu_assert_debug(swizzle < std::size(MTL_TEXTURE_SWIZZLES));
return MTL_TEXTURE_SWIZZLES[swizzle];
}

View File

@ -8,6 +8,7 @@
#include "Cafe/HW/Latte/Renderer/Renderer.h"
#include "Metal/MTLDepthStencil.hpp"
#include "Metal/MTLSampler.hpp"
#include "Metal/MTLTexture.hpp"
struct Uvec2 {
uint32 x;
@ -41,3 +42,5 @@ MTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR
MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func);
MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp);
MTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle);

View File

@ -88,7 +88,7 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
continue;
}
auto colorAttachment = desc->colorAttachments()->object(i);
colorAttachment->setPixelFormat(texture->GetTexture()->pixelFormat());
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
// Blending
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = LatteGPUState.contextNew.CB_COLOR_CONTROL;
@ -127,7 +127,7 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
if (activeFBO->depthBuffer.texture)
{
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
desc->setDepthAttachmentPixelFormat(texture->GetTexture()->pixelFormat());
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
// TODO: stencil pixel format
}

View File

@ -167,7 +167,7 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
if (!AcquireNextDrawable())
return;
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetTexture();
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView();
// Create render pass
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
@ -550,13 +550,13 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
auto colorTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->colorBuffer[i].texture);
if (colorTexture)
{
colorRenderTargets[i] = colorTexture->GetTexture();
colorRenderTargets[i] = colorTexture->GetRGBAView();
}
}
auto depthTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->depthBuffer.texture);
if (depthTexture)
{
depthRenderTarget = depthTexture->GetTexture();
depthRenderTarget = depthTexture->GetRGBAView();
}
auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, depthRenderTarget);
@ -919,9 +919,9 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
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));
samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampX));
samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampY));
samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampZ));
auto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO();
@ -980,16 +980,17 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
sampler->release();
}
MTL::Texture* mtlTexture = textureView->GetSwizzledView(word4);
switch (shader->shaderType)
{
case LatteConst::ShaderType::Vertex:
{
renderCommandEncoder->setVertexTexture(textureView->GetTexture(), binding);
renderCommandEncoder->setVertexTexture(mtlTexture, binding);
break;
}
case LatteConst::ShaderType::Pixel:
{
renderCommandEncoder->setFragmentTexture(textureView->GetTexture(), binding);
renderCommandEncoder->setFragmentTexture(mtlTexture, binding);
break;
}
default: