From 46981d7b0368d59a05f1b92fdc4293267c688b3b Mon Sep 17 00:00:00 2001 From: Samuliak Date: Fri, 26 Jul 2024 08:51:27 +0200 Subject: [PATCH] implement pixel formats and texture copy --- src/Cafe/CMakeLists.txt | 3 + .../Latte/Renderer/Metal/LatteTextureMtl.cpp | 15 ++- .../HW/Latte/Renderer/Metal/LatteTextureMtl.h | 7 ++ .../Renderer/Metal/LatteTextureViewMtl.cpp | 2 +- .../Renderer/Metal/LatteTextureViewMtl.h | 6 ++ .../HW/Latte/Renderer/Metal/LatteToMtl.cpp | 97 +++++++++++++++++++ src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h | 22 +++++ .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 18 ++-- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 2 + 9 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp create mode 100644 src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index 379b9857..d4446652 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -524,6 +524,7 @@ if(APPLE) target_sources(CemuCafe PRIVATE HW/Latte/Renderer/Vulkan/CocoaSurface.mm HW/Latte/Renderer/MetalView.mm + HW/Latte/Renderer/MetalView.h ) endif() @@ -535,6 +536,8 @@ if(ENABLE_METAL) HW/Latte/Renderer/Metal/MetalCppImpl.cpp HW/Latte/Renderer/Metal/MetalLayer.mm HW/Latte/Renderer/Metal/MetalLayer.h + HW/Latte/Renderer/Metal/LatteToMtl.cpp + HW/Latte/Renderer/Metal/LatteToMtl.h HW/Latte/Renderer/Metal/LatteTextureMtl.cpp HW/Latte/Renderer/Metal/LatteTextureMtl.h HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp index 4e053821..1b140590 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.cpp @@ -1,12 +1,15 @@ #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) + : LatteTexture(dim, physAddress, physMipAddress, format, width, height, depth, pitch, mipLevels, swizzle, tileMode, isDepth), m_mtlr(mtlRenderer), m_format(format) { MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init(); + desc->setStorageMode(MTL::StorageModeShared); // TODO: use private? + sint32 effectiveBaseWidth = width; sint32 effectiveBaseHeight = height; sint32 effectiveBaseDepth = depth; @@ -31,17 +34,13 @@ LatteTextureMtl::LatteTextureMtl(class MetalRenderer* mtlRenderer, Latte::E_DIM desc->setArrayLength(effectiveBaseDepth); } - // TODO: uncomment - //MetalRenderer::FormatInfoMTL texFormatInfo; - //mtlRenderer->GetTextureFormatInfoMTL(format, isDepth, dim, effectiveBaseWidth, effectiveBaseHeight, &texFormatInfo); - //cemu_assert_debug(hasStencil == ((texFormatInfo.vkImageAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)); - //imageInfo.format = texFormatInfo.mtlPixelFormat; - desc->setPixelFormat(MTL::PixelFormatRGBA8Unorm); + auto formatInfo = GetMtlPixelFormatInfo(format); + desc->setPixelFormat(formatInfo.pixelFormat); // TODO: is write needed? MTL::TextureUsage usage = MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite; // TODO: add more conditions - if (Latte::IsCompressedFormat(format) == false) + if (!Latte::IsCompressedFormat(format)) { usage |= MTL::TextureUsageRenderTarget; } diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h index c659e919..cc08d469 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h @@ -3,6 +3,7 @@ #include #include "Cafe/HW/Latte/Core/LatteTexture.h" +#include "HW/Latte/ISA/LatteReg.h" #include "util/ChunkedHeap/ChunkedHeap.h" class LatteTextureMtl : public LatteTexture @@ -16,6 +17,10 @@ public: return m_texture; } + Latte::E_GX2SURFFMT GetFormat() const { + return m_format; + } + void AllocateOnHost() override; protected: @@ -33,4 +38,6 @@ private: class MetalRenderer* m_mtlr; MTL::Texture* m_texture; + + Latte::E_GX2SURFFMT m_format; }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp index 3a93e76d..c8df8cf6 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.cpp @@ -3,7 +3,7 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.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) + : LatteTextureView(texture, firstMip, mipCount, firstSlice, sliceCount, dim, format), m_mtlr(mtlRenderer), m_format(format) { // TODO: don't hardcode the format MTL::PixelFormat pixelFormat = MTL::PixelFormatRGBA8Unorm; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h index c5a21b12..7df74b4f 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteTextureViewMtl.h @@ -14,8 +14,14 @@ public: return m_texture; } + Latte::E_GX2SURFFMT GetFormat() const { + return m_format; + } + private: class MetalRenderer* m_mtlr; MTL::Texture* m_texture; + + Latte::E_GX2SURFFMT m_format; }; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp new file mode 100644 index 00000000..a1d398bd --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp @@ -0,0 +1,97 @@ +#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" +#include "Common/precompiled.h" + +std::map MTL_FORMAT_TABLE = {{ + {Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R5_G6_B5_UNORM, {MTL::PixelFormatB5G6R5Unorm, 2}}, // TODO: correct? + {Latte::E_GX2SURFFMT::R5_G5_B5_A1_UNORM, {MTL::PixelFormatBGR5A1Unorm, 2}}, // TODO: correct? + {Latte::E_GX2SURFFMT::R4_G4_B4_A4_UNORM, {MTL::PixelFormatABGR4Unorm, 2}}, // TODO: correct? + {Latte::E_GX2SURFFMT::A1_B5_G5_R5_UNORM, {MTL::PixelFormatA1BGR5Unorm, 2}}, + {Latte::E_GX2SURFFMT::R8_UNORM, {MTL::PixelFormatR8Unorm, 1}}, + {Latte::E_GX2SURFFMT::R8_SNORM, {MTL::PixelFormatR8Snorm, 1}}, + {Latte::E_GX2SURFFMT::R8_UINT, {MTL::PixelFormatR8Uint, 1}}, + {Latte::E_GX2SURFFMT::R8_SINT, {MTL::PixelFormatR8Sint, 1}}, + {Latte::E_GX2SURFFMT::R8_G8_UNORM, {MTL::PixelFormatRG8Unorm, 2}}, + {Latte::E_GX2SURFFMT::R8_G8_SNORM, {MTL::PixelFormatRG8Snorm, 2}}, + {Latte::E_GX2SURFFMT::R8_G8_UINT, {MTL::PixelFormatRG8Uint, 2}}, + {Latte::E_GX2SURFFMT::R8_G8_SINT, {MTL::PixelFormatRG8Sint, 2}}, + {Latte::E_GX2SURFFMT::R8_G8_B8_A8_UNORM, {MTL::PixelFormatRGBA8Unorm, 4}}, + {Latte::E_GX2SURFFMT::R8_G8_B8_A8_SNORM, {MTL::PixelFormatRGBA8Snorm, 4}}, + {Latte::E_GX2SURFFMT::R8_G8_B8_A8_UINT, {MTL::PixelFormatRGBA8Uint, 4}}, + {Latte::E_GX2SURFFMT::R8_G8_B8_A8_SINT, {MTL::PixelFormatRGBA8Sint, 4}}, + {Latte::E_GX2SURFFMT::R8_G8_B8_A8_SRGB, {MTL::PixelFormatRGBA8Unorm_sRGB, 4}}, + {Latte::E_GX2SURFFMT::R10_G10_B10_A2_UNORM, {MTL::PixelFormatRGB10A2Unorm, 4}}, + {Latte::E_GX2SURFFMT::R10_G10_B10_A2_SNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R10_G10_B10_A2_UINT, {MTL::PixelFormatRGB10A2Uint, 4}}, + {Latte::E_GX2SURFFMT::R10_G10_B10_A2_SINT, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R10_G10_B10_A2_SRGB, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::A2_B10_G10_R10_UNORM, {MTL::PixelFormatBGR10A2Unorm, 4}}, // TODO: correct? + {Latte::E_GX2SURFFMT::A2_B10_G10_R10_UINT, {MTL::PixelFormatRGB10A2Uint, 4}}, // TODO: correct? + {Latte::E_GX2SURFFMT::R16_UNORM, {MTL::PixelFormatR16Unorm, 2}}, + {Latte::E_GX2SURFFMT::R16_SNORM, {MTL::PixelFormatR16Snorm, 2}}, + {Latte::E_GX2SURFFMT::R16_UINT, {MTL::PixelFormatR16Uint, 2}}, + {Latte::E_GX2SURFFMT::R16_SINT, {MTL::PixelFormatR16Sint, 2}}, + {Latte::E_GX2SURFFMT::R16_FLOAT, {MTL::PixelFormatR16Float, 2}}, + {Latte::E_GX2SURFFMT::R16_G16_UNORM, {MTL::PixelFormatRG16Unorm, 4}}, + {Latte::E_GX2SURFFMT::R16_G16_SNORM, {MTL::PixelFormatRG16Snorm, 4}}, + {Latte::E_GX2SURFFMT::R16_G16_UINT, {MTL::PixelFormatRG16Uint, 4}}, + {Latte::E_GX2SURFFMT::R16_G16_SINT, {MTL::PixelFormatRG16Sint, 4}}, + {Latte::E_GX2SURFFMT::R16_G16_FLOAT, {MTL::PixelFormatRG16Float, 4}}, + {Latte::E_GX2SURFFMT::R16_G16_B16_A16_UNORM, {MTL::PixelFormatRGBA16Unorm, 8}}, + {Latte::E_GX2SURFFMT::R16_G16_B16_A16_SNORM, {MTL::PixelFormatRGBA16Snorm, 8}}, + {Latte::E_GX2SURFFMT::R16_G16_B16_A16_UINT, {MTL::PixelFormatRGBA16Uint, 8}}, + {Latte::E_GX2SURFFMT::R16_G16_B16_A16_SINT, {MTL::PixelFormatRGBA16Sint, 8}}, + {Latte::E_GX2SURFFMT::R16_G16_B16_A16_FLOAT, {MTL::PixelFormatRGBA16Float, 8}}, + {Latte::E_GX2SURFFMT::R24_X8_UNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R24_X8_FLOAT, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::X24_G8_UINT, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R32_X8_FLOAT, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::X32_G8_UINT_X24, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::R11_G11_B10_FLOAT, {MTL::PixelFormatRG11B10Float, 4}}, + {Latte::E_GX2SURFFMT::R32_UINT, {MTL::PixelFormatR32Uint, 4}}, + {Latte::E_GX2SURFFMT::R32_SINT, {MTL::PixelFormatR32Sint, 4}}, + {Latte::E_GX2SURFFMT::R32_FLOAT, {MTL::PixelFormatR32Float, 4}}, + {Latte::E_GX2SURFFMT::R32_G32_UINT, {MTL::PixelFormatRG32Uint, 8}}, + {Latte::E_GX2SURFFMT::R32_G32_SINT, {MTL::PixelFormatRG32Sint, 8}}, + {Latte::E_GX2SURFFMT::R32_G32_FLOAT, {MTL::PixelFormatRG32Float, 8}}, + {Latte::E_GX2SURFFMT::R32_G32_B32_A32_UINT, {MTL::PixelFormatRGBA32Uint, 16}}, + {Latte::E_GX2SURFFMT::R32_G32_B32_A32_SINT, {MTL::PixelFormatRGBA32Sint, 16}}, + {Latte::E_GX2SURFFMT::R32_G32_B32_A32_FLOAT, {MTL::PixelFormatRGBA32Float, 16}}, + {Latte::E_GX2SURFFMT::D24_S8_UNORM, {MTL::PixelFormatDepth24Unorm_Stencil8, 4}}, // TODO: not supported on Apple sillicon, maybe find something else + {Latte::E_GX2SURFFMT::D24_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 4}}, // TODO: correct? + {Latte::E_GX2SURFFMT::D32_S8_FLOAT, {MTL::PixelFormatDepth32Float_Stencil8, 5}}, + {Latte::E_GX2SURFFMT::D16_UNORM, {MTL::PixelFormatDepth16Unorm, 2}}, + {Latte::E_GX2SURFFMT::D32_FLOAT, {MTL::PixelFormatDepth32Float, 4}}, + {Latte::E_GX2SURFFMT::BC1_UNORM, {MTL::PixelFormatBC1_RGBA, 8, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC1_SRGB, {MTL::PixelFormatBC1_RGBA_sRGB, 8, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC2_UNORM, {MTL::PixelFormatBC2_RGBA, 16, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC2_SRGB, {MTL::PixelFormatBC2_RGBA_sRGB, 16, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC3_UNORM, {MTL::PixelFormatBC3_RGBA, 16, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC3_SRGB, {MTL::PixelFormatBC3_RGBA_sRGB, 16, {4, 4}}}, // TODO: correct? + {Latte::E_GX2SURFFMT::BC4_UNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::BC4_SNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::BC5_UNORM, {MTL::PixelFormatInvalid, 0}}, // TODO + {Latte::E_GX2SURFFMT::BC5_SNORM, {MTL::PixelFormatInvalid, 0}}, // TODO +}}; + +const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format) { + cemu_assert_debug(static_cast(format) < MTL_FORMAT_TABLE.size()); + + return MTL_FORMAT_TABLE[format]; +} + +inline uint32 CeilDivide(uint32 a, uint32 b) { + return (a + b - 1) / b; +} + +size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, uint32 width) { + const auto& formatInfo = GetMtlPixelFormatInfo(format); + + return CeilDivide(width, formatInfo.blockTexelSize.x) * formatInfo.bytesPerBlock; +} + +size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, uint32 height, size_t bytesPerRow) { + const auto& formatInfo = GetMtlPixelFormatInfo(format); + + return CeilDivide(height, formatInfo.blockTexelSize.y) * bytesPerRow; +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h new file mode 100644 index 00000000..f8b1ee03 --- /dev/null +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "HW/Latte/ISA/LatteReg.h" + +struct Uvec2 { + uint32 x; + uint32 y; +}; + +struct MtlPixelFormatInfo { + MTL::PixelFormat pixelFormat; + size_t bytesPerBlock; + Uvec2 blockTexelSize = {1, 1}; +}; + +const MtlPixelFormatInfo GetMtlPixelFormatInfo(Latte::E_GX2SURFFMT format); + +size_t GetMtlTextureBytesPerRow(Latte::E_GX2SURFFMT format, uint32 width); + +size_t GetMtlTextureBytesPerImage(Latte::E_GX2SURFFMT format, uint32 height, size_t bytesPerRow); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index cdd3b05c..c49035dd 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -1,6 +1,7 @@ #include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h" #include "Cafe/HW/Latte/Renderer/Metal/MetalLayer.h" #include "Cafe/HW/Latte/Renderer/Metal/LatteTextureMtl.h" +#include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" #include "gui/guiWrapper.h" @@ -69,11 +70,11 @@ void MetalRenderer::SwapBuffers(bool swapTV, bool swapDRC) return; } - MTL::CommandBuffer* commandBuffer = m_commandQueue->commandBuffer(); - commandBuffer->presentDrawable(drawable); - commandBuffer->commit(); + m_commandBuffer->presentDrawable(drawable); + m_commandBuffer->commit(); - commandBuffer->release(); + m_commandBuffer->release(); + m_commandBuffer = nullptr; } void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutputShader* shader, bool useLinearTexFilter, @@ -85,8 +86,9 @@ void MetalRenderer::DrawBackbufferQuad(LatteTextureView* texView, RendererOutput bool MetalRenderer::BeginFrame(bool mainWindow) { - cemuLog_logDebug(LogType::Force, "not implemented"); + m_commandBuffer = m_commandQueue->commandBuffer(); + // TODO return false; } @@ -158,7 +160,11 @@ void MetalRenderer::texture_clearSlice(LatteTexture* hostTexture, sint32 sliceIn void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, sint32 height, sint32 depth, void* pixelData, sint32 sliceIndex, sint32 mipIndex, uint32 compressedImageSize) { - cemuLog_logDebug(LogType::Force, "not implemented"); + auto mtlTexture = (LatteTextureMtl*)hostTexture; + + size_t bytesPerRow = GetMtlTextureBytesPerRow(mtlTexture->GetFormat(), width); + size_t bytesPerImage = GetMtlTextureBytesPerImage(mtlTexture->GetFormat(), height, bytesPerRow); + mtlTexture->GetTexture()->replaceRegion(MTL::Region(0, 0, width, height), mipIndex, sliceIndex, pixelData, bytesPerRow, bytesPerImage); } void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index 4cc06f57..49e11be9 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -159,4 +159,6 @@ private: // Metal objects MTL::Device* m_device; MTL::CommandQueue* m_commandQueue; + + MTL::CommandBuffer* m_commandBuffer = nullptr; };