Skip to content

Commit 0a7f30c

Browse files
committed
implement texture swizzle
1 parent d64e64e commit 0a7f30c

File tree

7 files changed

+164
-68
lines changed

7 files changed

+164
-68
lines changed

src/Cafe/HW/Latte/Renderer/Metal/CachedFBOMtl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ void CachedFBOMtl::CreateRenderPass()
1515
continue;
1616
}
1717
auto colorAttachment = m_renderPassDescriptor->colorAttachments()->object(i);
18-
colorAttachment->setTexture(textureView->GetTexture());
18+
colorAttachment->setTexture(textureView->GetRGBAView());
1919
colorAttachment->setLoadAction(MTL::LoadActionLoad);
2020
colorAttachment->setStoreAction(MTL::StoreActionStore);
2121
}
@@ -25,7 +25,7 @@ void CachedFBOMtl::CreateRenderPass()
2525
{
2626
auto textureView = static_cast<LatteTextureViewMtl*>(depthBuffer.texture);
2727
auto depthAttachment = m_renderPassDescriptor->depthAttachment();
28-
depthAttachment->setTexture(textureView->GetTexture());
28+
depthAttachment->setTexture(textureView->GetRGBAView());
2929
depthAttachment->setLoadAction(MTL::LoadActionLoad);
3030
depthAttachment->setStoreAction(MTL::StoreActionStore);
3131
}

src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp

Lines changed: 114 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,58 +4,123 @@
44
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
55

66
LatteTextureViewMtl::LatteTextureViewMtl(MetalRenderer* mtlRenderer, LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
7-
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_format(format)
7+
: LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_baseTexture(texture)
88
{
9-
MTL::TextureType textureType;
10-
switch (dim)
11-
{
12-
case Latte::E_DIM::DIM_1D:
13-
textureType = MTL::TextureType1D;
14-
break;
15-
case Latte::E_DIM::DIM_2D:
16-
case Latte::E_DIM::DIM_2D_MSAA:
17-
textureType = MTL::TextureType2D;
18-
break;
19-
case Latte::E_DIM::DIM_2D_ARRAY:
20-
textureType = MTL::TextureType2DArray;
21-
break;
22-
case Latte::E_DIM::DIM_3D:
23-
textureType = MTL::TextureType3D;
24-
break;
25-
case Latte::E_DIM::DIM_CUBEMAP:
26-
textureType = MTL::TextureTypeCube; // TODO: check this
27-
break;
28-
default:
29-
cemu_assert_unimplemented();
30-
textureType = MTL::TextureType2D;
31-
break;
32-
}
33-
34-
uint32 baseLevel = firstMip;
35-
uint32 levelCount = this->numMip;
36-
uint32 baseLayer;
37-
uint32 layerCount;
38-
// TODO: check if base texture is 3D texture as well
39-
if (textureType == MTL::TextureType3D)
40-
{
41-
cemu_assert_debug(firstMip == 0);
42-
cemu_assert_debug(this->numSlice == baseTexture->depth);
43-
baseLayer = 0;
44-
layerCount = 1;
45-
}
46-
else
47-
{
48-
baseLayer = firstSlice;
49-
layerCount = this->numSlice;
50-
}
51-
52-
// TODO: swizzle
53-
54-
auto formatInfo = GetMtlPixelFormatInfo(format, texture->IsDepth());
55-
m_texture = texture->GetTexture()->newTextureView(formatInfo.pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount));
569
}
5710

5811
LatteTextureViewMtl::~LatteTextureViewMtl()
5912
{
60-
m_texture->release();
13+
for (sint32 i = 0; i < std::size(m_viewCache); i++)
14+
{
15+
if (m_viewCache[i].key != INVALID_SWIZZLE)
16+
m_viewCache[i].texture->release();
17+
}
18+
19+
for (auto& [key, texture] : m_fallbackViewCache)
20+
{
21+
texture->release();
22+
}
23+
}
24+
25+
MTL::Texture* LatteTextureViewMtl::GetSwizzledView(uint32 gpuSamplerSwizzle)
26+
{
27+
// Mask out
28+
gpuSamplerSwizzle &= 0x0FFF0000;
29+
30+
if (gpuSamplerSwizzle == RGBA_SWIZZLE)
31+
{
32+
return m_baseTexture->GetTexture();
33+
}
34+
else
35+
{
36+
// First, try to find a view in the cache
37+
38+
// Fast cache
39+
sint32 freeIndex = -1;
40+
for (sint32 i = 0; i < std::size(m_viewCache); i++)
41+
{
42+
if (m_viewCache[i].key == gpuSamplerSwizzle)
43+
{
44+
return m_viewCache[i].texture;
45+
}
46+
else if (m_viewCache[i].key == INVALID_SWIZZLE && freeIndex == -1)
47+
{
48+
freeIndex = i;
49+
}
50+
}
51+
52+
// Fallback cache
53+
auto it = m_fallbackViewCache.find(gpuSamplerSwizzle);
54+
if (it != m_fallbackViewCache.end())
55+
{
56+
return it->second;
57+
}
58+
59+
MTL::Texture* texture = CreateSwizzledView(gpuSamplerSwizzle);
60+
if (freeIndex != -1)
61+
m_viewCache[freeIndex] = {gpuSamplerSwizzle, texture};
62+
else
63+
it->second = texture;
64+
65+
return texture;
66+
}
67+
}
68+
69+
MTL::Texture* LatteTextureViewMtl::CreateSwizzledView(uint32 gpuSamplerSwizzle)
70+
{
71+
uint32 compSelR = (gpuSamplerSwizzle >> 16) & 0x7;
72+
uint32 compSelG = (gpuSamplerSwizzle >> 19) & 0x7;
73+
uint32 compSelB = (gpuSamplerSwizzle >> 22) & 0x7;
74+
uint32 compSelA = (gpuSamplerSwizzle >> 25) & 0x7;
75+
// TODO: adjust
76+
77+
MTL::TextureType textureType;
78+
switch (dim)
79+
{
80+
case Latte::E_DIM::DIM_1D:
81+
textureType = MTL::TextureType1D;
82+
break;
83+
case Latte::E_DIM::DIM_2D:
84+
case Latte::E_DIM::DIM_2D_MSAA:
85+
textureType = MTL::TextureType2D;
86+
break;
87+
case Latte::E_DIM::DIM_2D_ARRAY:
88+
textureType = MTL::TextureType2DArray;
89+
break;
90+
case Latte::E_DIM::DIM_3D:
91+
textureType = MTL::TextureType3D;
92+
break;
93+
case Latte::E_DIM::DIM_CUBEMAP:
94+
textureType = MTL::TextureTypeCube; // TODO: check this
95+
break;
96+
default:
97+
cemu_assert_unimplemented();
98+
textureType = MTL::TextureType2D;
99+
break;
100+
}
101+
102+
uint32 baseLevel = firstMip;
103+
uint32 levelCount = this->numMip;
104+
uint32 baseLayer;
105+
uint32 layerCount;
106+
// TODO: check if base texture is 3D texture as well
107+
if (textureType == MTL::TextureType3D)
108+
{
109+
cemu_assert_debug(firstMip == 0);
110+
cemu_assert_debug(this->numSlice == baseTexture->depth);
111+
baseLayer = 0;
112+
layerCount = 1;
113+
}
114+
else
115+
{
116+
baseLayer = firstSlice;
117+
layerCount = this->numSlice;
118+
}
119+
120+
// TODO: swizzle
121+
122+
auto formatInfo = GetMtlPixelFormatInfo(format, m_baseTexture->IsDepth());
123+
MTL::Texture* texture = m_baseTexture->GetTexture()->newTextureView(formatInfo.pixelFormat, textureType, NS::Range::Make(baseLevel, levelCount), NS::Range::Make(baseLayer, layerCount));
124+
125+
return texture;
61126
}
Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
#pragma once
22

33
#include <Metal/Metal.hpp>
4+
#include <unordered_map>
45

56
#include "Cafe/HW/Latte/Core/LatteTexture.h"
67

8+
#define RGBA_SWIZZLE 0x06880000
9+
#define INVALID_SWIZZLE 0xFFFFFFFF
10+
11+
// TODO: test the swizzle
712
class LatteTextureViewMtl : public LatteTextureView
813
{
914
public:
1015
LatteTextureViewMtl(class MetalRenderer* mtlRenderer, class LatteTextureMtl* texture, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount);
1116
~LatteTextureViewMtl();
1217

13-
MTL::Texture* GetTexture() const {
14-
return m_texture;
15-
}
18+
MTL::Texture* GetSwizzledView(uint32 gpuSamplerSwizzle);
1619

17-
Latte::E_GX2SURFFMT GetFormat() const {
18-
return m_format;
20+
MTL::Texture* GetRGBAView()
21+
{
22+
return GetSwizzledView(RGBA_SWIZZLE);
1923
}
2024

2125
private:
2226
class MetalRenderer* m_mtlr;
2327

24-
MTL::Texture* m_texture;
28+
class LatteTextureMtl* m_baseTexture;
29+
30+
struct {
31+
uint32 key;
32+
MTL::Texture* texture;
33+
} m_viewCache[4] = {{INVALID_SWIZZLE, nullptr}};
34+
std::unordered_map<uint32, MTL::Texture*> m_fallbackViewCache;
2535

26-
Latte::E_GX2SURFFMT m_format;
36+
MTL::Texture* CreateSwizzledView(uint32 gpuSamplerSwizzle);
2737
};

src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,3 +419,20 @@ MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WOR
419419
cemu_assert_debug((uint32)clamp < std::size(MTL_SAMPLER_ADDRESS_MODES));
420420
return MTL_SAMPLER_ADDRESS_MODES[(uint32)clamp];
421421
}
422+
423+
const MTL::TextureSwizzle MTL_TEXTURE_SWIZZLES[] = {
424+
MTL::TextureSwizzleRed,
425+
MTL::TextureSwizzleGreen,
426+
MTL::TextureSwizzleBlue,
427+
MTL::TextureSwizzleAlpha,
428+
MTL::TextureSwizzleZero,
429+
MTL::TextureSwizzleOne,
430+
MTL::TextureSwizzleZero,
431+
MTL::TextureSwizzleZero
432+
};
433+
434+
MTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle)
435+
{
436+
cemu_assert_debug(swizzle < std::size(MTL_TEXTURE_SWIZZLES));
437+
return MTL_TEXTURE_SWIZZLES[swizzle];
438+
}

src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "Cafe/HW/Latte/Renderer/Renderer.h"
99
#include "Metal/MTLDepthStencil.hpp"
1010
#include "Metal/MTLSampler.hpp"
11+
#include "Metal/MTLTexture.hpp"
1112

1213
struct Uvec2 {
1314
uint32 x;
@@ -41,3 +42,5 @@ MTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR
4142
MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func);
4243

4344
MTL::SamplerAddressMode GetMtlSamplerAddressMode(Latte::LATTE_SQ_TEX_SAMPLER_WORD0_0::E_CLAMP clamp);
45+
46+
MTL::TextureSwizzle GetMtlTextureSwizzle(uint32 swizzle);

src/Cafe/HW/Latte/Renderer/Metal/MetalPipelineCache.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
8888
continue;
8989
}
9090
auto colorAttachment = desc->colorAttachments()->object(i);
91-
colorAttachment->setPixelFormat(texture->GetTexture()->pixelFormat());
91+
colorAttachment->setPixelFormat(texture->GetRGBAView()->pixelFormat());
9292

9393
// Blending
9494
const Latte::LATTE_CB_COLOR_CONTROL& colorControlReg = LatteGPUState.contextNew.CB_COLOR_CONTROL;
@@ -127,7 +127,7 @@ MTL::RenderPipelineState* MetalPipelineCache::GetPipelineState(const LatteFetchS
127127
if (activeFBO->depthBuffer.texture)
128128
{
129129
auto texture = static_cast<LatteTextureViewMtl*>(activeFBO->depthBuffer.texture);
130-
desc->setDepthAttachmentPixelFormat(texture->GetTexture()->pixelFormat());
130+
desc->setDepthAttachmentPixelFormat(texture->GetRGBAView()->pixelFormat());
131131
// TODO: stencil pixel format
132132
}
133133

src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput
167167
if (!AcquireNextDrawable())
168168
return;
169169

170-
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetTexture();
170+
MTL::Texture* presentTexture = static_cast<LatteTextureViewMtl*>(texView)->GetRGBAView();
171171

172172
// Create render pass
173173
MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init();
@@ -550,13 +550,13 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32
550550
auto colorTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->colorBuffer[i].texture);
551551
if (colorTexture)
552552
{
553-
colorRenderTargets[i] = colorTexture->GetTexture();
553+
colorRenderTargets[i] = colorTexture->GetRGBAView();
554554
}
555555
}
556556
auto depthTexture = static_cast<LatteTextureViewMtl*>(m_state.activeFBO->depthBuffer.texture);
557557
if (depthTexture)
558558
{
559-
depthRenderTarget = depthTexture->GetTexture();
559+
depthRenderTarget = depthTexture->GetRGBAView();
560560
}
561561
auto renderCommandEncoder = GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, depthRenderTarget);
562562

@@ -919,9 +919,9 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
919919
auto clampY = samplerWords->WORD0.get_CLAMP_Y();
920920
auto clampZ = samplerWords->WORD0.get_CLAMP_Z();
921921

922-
samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampX));
923-
samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampY));
924-
samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampZ));
922+
samplerDescriptor->setSAddressMode(GetMtlSamplerAddressMode(clampX));
923+
samplerDescriptor->setTAddressMode(GetMtlSamplerAddressMode(clampY));
924+
samplerDescriptor->setRAddressMode(GetMtlSamplerAddressMode(clampZ));
925925

926926
auto maxAniso = samplerWords->WORD0.get_MAX_ANISO_RATIO();
927927

@@ -980,16 +980,17 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE
980980
sampler->release();
981981
}
982982

983+
MTL::Texture* mtlTexture = textureView->GetSwizzledView(word4);
983984
switch (shader->shaderType)
984985
{
985986
case LatteConst::ShaderType::Vertex:
986987
{
987-
renderCommandEncoder->setVertexTexture(textureView->GetTexture(), binding);
988+
renderCommandEncoder->setVertexTexture(mtlTexture, binding);
988989
break;
989990
}
990991
case LatteConst::ShaderType::Pixel:
991992
{
992-
renderCommandEncoder->setFragmentTexture(textureView->GetTexture(), binding);
993+
renderCommandEncoder->setFragmentTexture(mtlTexture, binding);
993994
break;
994995
}
995996
default:

0 commit comments

Comments
 (0)