diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp index 049482c6..40eacdf5 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.cpp @@ -1,4 +1,6 @@ #include "Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h" +#include "Common/precompiled.h" +#include "Metal/MTLDepthStencil.hpp" std::map MTL_COLOR_FORMAT_TABLE = { {Latte::E_GX2SURFFMT::R4_G4_UNORM, {MTL::PixelFormatRG8Unorm, 2}}, // TODO: correct? @@ -252,3 +254,21 @@ MTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR cemu_assert_debug((uint32)factor < std::size(MTL_BLEND_FACTORS)); return MTL_BLEND_FACTORS[(uint32)factor]; } + +const MTL::CompareFunction MTL_COMPARE_FUNCTIONS[8] = +{ + MTL::CompareFunctionNever, + MTL::CompareFunctionLess, + MTL::CompareFunctionEqual, + MTL::CompareFunctionLessEqual, + MTL::CompareFunctionGreater, + MTL::CompareFunctionNotEqual, + MTL::CompareFunctionGreaterEqual, + MTL::CompareFunctionAlways +}; + +MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func) +{ + cemu_assert_debug((uint32)func < std::size(MTL_COMPARE_FUNCTIONS)); + return MTL_COMPARE_FUNCTIONS[(uint32)func]; +} diff --git a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h index 54e0de32..ed99098d 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/LatteToMtl.h @@ -6,6 +6,7 @@ #include "Cafe/HW/Latte/Core/LatteConst.h" //#include "Cafe/HW/Latte/Core/FetchShader.h" #include "Cafe/HW/Latte/Renderer/Renderer.h" +#include "Metal/MTLDepthStencil.hpp" struct Uvec2 { uint32 x; @@ -33,3 +34,5 @@ MTL::IndexType GetMtlIndexType(Renderer::INDEX_TYPE indexType); MTL::BlendOperation GetMtlBlendOp(Latte::LATTE_CB_BLENDN_CONTROL::E_COMBINEFUNC combineFunc); MTL::BlendFactor GetMtlBlendFactor(Latte::LATTE_CB_BLENDN_CONTROL::E_BLENDFACTOR factor); + +MTL::CompareFunction GetMtlCompareFunc(Latte::E_COMPAREFUNC func); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index 54bf1fee..aeedcd82 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -13,7 +13,9 @@ #include "Cafe/HW/Latte/Core/LatteIndices.h" #include "Cemu/Logging/CemuDebugLogging.h" #include "Foundation/NSTypes.hpp" +#include "Metal/MTLDepthStencil.hpp" #include "Metal/MTLRenderCommandEncoder.hpp" +#include "Metal/MTLRenderPass.hpp" #include "gui/guiWrapper.h" extern bool hasValidFramebufferAttached; @@ -377,14 +379,48 @@ void MetalRenderer::texture_loadSlice(LatteTexture* hostTexture, sint32 width, s mtlTexture->GetTexture()->replaceRegion(MTL::Region(0, 0, width, height), mipIndex, sliceIndex, pixelData, bytesPerRow, bytesPerImage); } +// TODO: use sliceIndex and mipIndex void MetalRenderer::texture_clearColorSlice(LatteTexture* hostTexture, sint32 sliceIndex, sint32 mipIndex, float r, float g, float b, float a) { - debug_printf("MetalRenderer::texture_clearColorSlice not implemented\n"); + auto mtlTexture = static_cast(hostTexture)->GetTexture(); + + MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + auto colorAttachment = renderPassDescriptor->colorAttachments()->object(0); + colorAttachment->setTexture(mtlTexture); + colorAttachment->setClearColor(MTL::ClearColor(r, g, b, a)); + colorAttachment->setLoadAction(MTL::LoadActionClear); + colorAttachment->setStoreAction(MTL::StoreActionStore); + + MTL::Texture* colorRenderTargets[8] = {nullptr}; + colorRenderTargets[0] = mtlTexture; + GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, nullptr); } +// TODO: use sliceIndex and mipIndex void MetalRenderer::texture_clearDepthSlice(LatteTexture* hostTexture, uint32 sliceIndex, sint32 mipIndex, bool clearDepth, bool clearStencil, float depthValue, uint32 stencilValue) { - debug_printf("MetalRenderer::texture_clearDepthSlice not implemented\n"); + auto mtlTexture = static_cast(hostTexture)->GetTexture(); + + MTL::RenderPassDescriptor* renderPassDescriptor = MTL::RenderPassDescriptor::alloc()->init(); + if (clearDepth) + { + auto depthAttachment = renderPassDescriptor->depthAttachment(); + depthAttachment->setTexture(mtlTexture); + depthAttachment->setClearDepth(depthValue); + depthAttachment->setLoadAction(MTL::LoadActionClear); + depthAttachment->setStoreAction(MTL::StoreActionStore); + } + if (clearStencil) + { + auto stencilAttachment = renderPassDescriptor->stencilAttachment(); + stencilAttachment->setTexture(mtlTexture); + stencilAttachment->setClearStencil(stencilValue); + stencilAttachment->setLoadAction(MTL::LoadActionClear); + stencilAttachment->setStoreAction(MTL::StoreActionStore); + } + + MTL::Texture* colorRenderTargets[8] = {nullptr}; + GetRenderCommandEncoder(renderPassDescriptor, colorRenderTargets, mtlTexture); } LatteTexture* MetalRenderer::texture_createTextureEx(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) @@ -683,6 +719,87 @@ void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 } renderCommandEncoder->setRenderPipelineState(renderPipelineState); + // Depth stencil state + bool depthEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_ENABLE(); + auto depthFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_FUNC(); + bool depthWriteEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_Z_WRITE_ENABLE(); + + MTL::DepthStencilDescriptor* depthStencilDescriptor = MTL::DepthStencilDescriptor::alloc()->init(); + depthStencilDescriptor->setDepthWriteEnabled(depthWriteEnable); + + auto depthCompareFunc = GetMtlCompareFunc(depthFunc); + if (!depthEnable) + { + depthCompareFunc = MTL::CompareFunctionAlways; + } + depthStencilDescriptor->setDepthCompareFunction(depthCompareFunc); + + // TODO: stencil state + /* + // get stencil control parameters + bool stencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ENABLE(); + bool backStencilEnable = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_BACK_STENCIL_ENABLE(); + auto frontStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_F(); + auto frontStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_F(); + auto frontStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_F(); + auto frontStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_F(); + auto backStencilFunc = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FUNC_B(); + auto backStencilZPass = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZPASS_B(); + auto backStencilZFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_ZFAIL_B(); + auto backStencilFail = LatteGPUState.contextNew.DB_DEPTH_CONTROL.get_STENCIL_FAIL_B(); + // get stencil control parameters + uint32 stencilCompareMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILMASK_F(); + uint32 stencilWriteMaskFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILWRITEMASK_F(); + uint32 stencilRefFront = LatteGPUState.contextNew.DB_STENCILREFMASK.get_STENCILREF_F(); + uint32 stencilCompareMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILMASK_B(); + uint32 stencilWriteMaskBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILWRITEMASK_B(); + uint32 stencilRefBack = LatteGPUState.contextNew.DB_STENCILREFMASK_BF.get_STENCILREF_B(); + + static const VkStencilOp stencilOpTable[8] = { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_INCREMENT_AND_CLAMP, + VK_STENCIL_OP_DECREMENT_AND_CLAMP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_INCREMENT_AND_WRAP, + VK_STENCIL_OP_DECREMENT_AND_WRAP + }; + + depthStencilState.stencilTestEnable = stencilEnable ? VK_TRUE : VK_FALSE; + + depthStencilState.front.reference = stencilRefFront; + depthStencilState.front.compareMask = stencilCompareMaskFront; + depthStencilState.front.writeMask = stencilWriteMaskBack; + depthStencilState.front.compareOp = vkDepthCompareTable[(size_t)frontStencilFunc]; + depthStencilState.front.depthFailOp = stencilOpTable[(size_t)frontStencilZFail]; + depthStencilState.front.failOp = stencilOpTable[(size_t)frontStencilFail]; + depthStencilState.front.passOp = stencilOpTable[(size_t)frontStencilZPass]; + + if (backStencilEnable) + { + depthStencilState.back.reference = stencilRefBack; + depthStencilState.back.compareMask = stencilCompareMaskBack; + depthStencilState.back.writeMask = stencilWriteMaskBack; + depthStencilState.back.compareOp = vkDepthCompareTable[(size_t)backStencilFunc]; + depthStencilState.back.depthFailOp = stencilOpTable[(size_t)backStencilZFail]; + depthStencilState.back.failOp = stencilOpTable[(size_t)backStencilFail]; + depthStencilState.back.passOp = stencilOpTable[(size_t)backStencilZPass]; + } + else + { + depthStencilState.back.reference = stencilRefFront; + depthStencilState.back.compareMask = stencilCompareMaskFront; + depthStencilState.back.writeMask = stencilWriteMaskFront; + depthStencilState.back.compareOp = vkDepthCompareTable[(size_t)frontStencilFunc]; + depthStencilState.back.depthFailOp = stencilOpTable[(size_t)frontStencilZFail]; + depthStencilState.back.failOp = stencilOpTable[(size_t)frontStencilFail]; + depthStencilState.back.passOp = stencilOpTable[(size_t)frontStencilZPass]; + } + */ + MTL::DepthStencilState* depthStencilState = m_device->newDepthStencilState(depthStencilDescriptor); + renderCommandEncoder->setDepthStencilState(depthStencilState); + // Primitive type const LattePrimitiveMode primitiveMode = static_cast(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); auto mtlPrimitiveType = GetMtlPrimitiveType(primitiveMode); @@ -840,8 +957,8 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE UNREACHABLE; } - //if (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0) - //{ + if (shader->resourceMapping.uniformVarsBufferBindingPoint >= 0) + { if (shader->uniform.list_ufTexRescale.empty() == false) { for (auto& entry : shader->uniform.list_ufTexRescale) @@ -915,7 +1032,7 @@ void MetalRenderer::BindStageResources(MTL::RenderCommandEncoder* renderCommandE default: UNREACHABLE; } - //} + } // Uniform buffers for (sint32 i = 0; i < LATTE_NUM_MAX_UNIFORM_BUFFERS; i++)