Files
Cemu/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp
T
2025-12-06 17:14:25 +01:00

108 lines
3.6 KiB
C++

#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h"
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h"
LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM dim, MPTR physAddress, MPTR physMipAddress, Latte::E_GX2SURFFMT format, uint32 width, uint32 height, uint32 depth, uint32 pitch, uint32 mipLevels, uint32 swizzle,
Latte::E_HWTILEMODE tileMode, bool isDepth)
: LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer)
{
NS_STACK_SCOPED MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init();
desc->setStorageMode(MTL::StorageModePrivate);
//desc->setCpuCacheMode(MTL::CPUCacheModeWriteCombined);
sint32 effectiveBaseWidth = width;
sint32 effectiveBaseHeight = height;
sint32 effectiveBaseDepth = depth;
if (overwriteInfo.hasResolutionOverwrite)
{
effectiveBaseWidth = overwriteInfo.width;
effectiveBaseHeight = overwriteInfo.height;
effectiveBaseDepth = overwriteInfo.depth;
}
effectiveBaseWidth = std::max(1, effectiveBaseWidth);
effectiveBaseHeight = std::max(1, effectiveBaseHeight);
effectiveBaseDepth = std::max(1, effectiveBaseDepth);
MTL::TextureType textureType;
switch (dim)
{
case Latte::E_DIM::DIM_1D:
textureType = MTL::TextureType1D;
effectiveBaseHeight = 1;
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:
cemu_assert_debug(effectiveBaseDepth % 6 == 0 && "cubemaps must have an array length multiple of 6");
textureType = MTL::TextureTypeCubeArray;
break;
default:
cemu_assert_unimplemented();
textureType = MTL::TextureType2D;
break;
}
desc->setTextureType(textureType);
// Clamp mip levels
mipLevels = std::min(mipLevels, (uint32)maxPossibleMipLevels);
mipLevels = std::max(mipLevels, (uint32)1);
desc->setWidth(effectiveBaseWidth);
desc->setHeight(effectiveBaseHeight);
desc->setMipmapLevelCount(mipLevels);
if (textureType == MTL::TextureType3D)
{
desc->setDepth(effectiveBaseDepth);
}
else if (textureType == MTL::TextureTypeCubeArray)
{
desc->setArrayLength(effectiveBaseDepth / 6);
}
else if (textureType == MTL::TextureType2DArray)
{
desc->setArrayLength(effectiveBaseDepth);
}
auto pixelFormat = GetMtlPixelFormat(format, isDepth);
desc->setPixelFormat(pixelFormat);
MTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsagePixelFormatView;
if (FormatIsRenderable(format))
usage |= MTL::TextureUsageRenderTarget;
desc->setUsage(usage);
m_texture = mtlRenderer->GetDevice()->newTexture(desc);
}
LatteTextureMtl::~LatteTextureMtl()
{
m_texture->release();
}
LatteTextureView* LatteTextureMtl::CreateView(Latte::E_DIM dim, Latte::E_GX2SURFFMT format, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount)
{
cemu_assert_debug(mipCount > 0);
cemu_assert_debug(sliceCount > 0);
cemu_assert_debug((firstMip + mipCount) <= this->mipLevels);
cemu_assert_debug((firstSlice + sliceCount) <= this->depth);
return new LatteTextureViewMtl(m_mtlr, this, dim, format, firstMip, mipCount, firstSlice, sliceCount);
}
// TODO: lazy allocation?
void LatteTextureMtl::AllocateOnHost()
{
// The texture is already allocated
}