mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-01-07 07:38:14 +01:00
implement texture swizzle
This commit is contained in:
parent
d64e64e5ef
commit
0a7f30c6a4
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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];
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user