diff --git a/include/renderer_mtl/mtl_pipeline_cache.hpp b/include/renderer_mtl/mtl_pipeline_cache.hpp index 785d0d4a..d6a75c71 100644 --- a/include/renderer_mtl/mtl_pipeline_cache.hpp +++ b/include/renderer_mtl/mtl_pipeline_cache.hpp @@ -7,8 +7,13 @@ using namespace PICA; namespace Metal { struct PipelineHash { + // Formats ColorFmt colorFmt; DepthFmt depthFmt; + + // Blending + bool blendEnabled; + u32 blendControl; }; // Bind the vertex buffer to binding 30 so that it doesn't occupy the lower indices @@ -34,7 +39,7 @@ public: } MTL::RenderPipelineState* get(PipelineHash hash) { - u8 intHash = (u8)hash.colorFmt << 4 | (u8)hash.depthFmt; + u64 intHash = ((u64)hash.colorFmt << 36) | ((u64)hash.depthFmt << 33) | ((u64)hash.blendEnabled << 32) | (u64)hash.blendControl; auto& pipeline = pipelineCache[intHash]; if (!pipeline) { MTL::RenderPipelineDescriptor* desc = MTL::RenderPipelineDescriptor::alloc()->init(); @@ -44,11 +49,24 @@ public: auto colorAttachment = desc->colorAttachments()->object(0); colorAttachment->setPixelFormat(toMTLPixelFormatColor(hash.colorFmt)); - colorAttachment->setBlendingEnabled(true); - colorAttachment->setSourceRGBBlendFactor(MTL::BlendFactorSourceAlpha); - colorAttachment->setDestinationRGBBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); - colorAttachment->setSourceAlphaBlendFactor(MTL::BlendFactorSourceAlpha); - colorAttachment->setDestinationAlphaBlendFactor(MTL::BlendFactorOneMinusSourceAlpha); + if (hash.blendEnabled) { + const u8 rgbEquation = hash.blendControl & 0x7; + const u8 alphaEquation = Helpers::getBits<8, 3>(hash.blendControl); + + // Get blending functions + const u8 rgbSourceFunc = Helpers::getBits<16, 4>(hash.blendControl); + const u8 rgbDestFunc = Helpers::getBits<20, 4>(hash.blendControl); + const u8 alphaSourceFunc = Helpers::getBits<24, 4>(hash.blendControl); + const u8 alphaDestFunc = Helpers::getBits<28, 4>(hash.blendControl); + + colorAttachment->setBlendingEnabled(true); + colorAttachment->setRgbBlendOperation(toMTLBlendOperation(rgbEquation)); + colorAttachment->setAlphaBlendOperation(toMTLBlendOperation(alphaEquation)); + colorAttachment->setSourceRGBBlendFactor(toMTLBlendFactor(rgbSourceFunc)); + colorAttachment->setDestinationRGBBlendFactor(toMTLBlendFactor(rgbDestFunc)); + colorAttachment->setSourceAlphaBlendFactor(toMTLBlendFactor(alphaSourceFunc)); + colorAttachment->setDestinationAlphaBlendFactor(toMTLBlendFactor(alphaDestFunc)); + } desc->setDepthAttachmentPixelFormat(toMTLPixelFormatDepth(hash.depthFmt)); @@ -72,7 +90,7 @@ public: } private: - std::unordered_map pipelineCache; + std::unordered_map pipelineCache; MTL::Device* device; MTL::Function* vertexFunction; diff --git a/include/renderer_mtl/pica_to_mtl.hpp b/include/renderer_mtl/pica_to_mtl.hpp index 8f721b78..c97bea91 100644 --- a/include/renderer_mtl/pica_to_mtl.hpp +++ b/include/renderer_mtl/pica_to_mtl.hpp @@ -41,4 +41,44 @@ inline MTL::CompareFunction toMTLCompareFunc(u8 func) { return MTL::CompareFunctionAlways; } +inline MTL::BlendOperation toMTLBlendOperation(u8 op) { + switch (op) { + case 0: return MTL::BlendOperationAdd; + case 1: return MTL::BlendOperationSubtract; + case 2: return MTL::BlendOperationReverseSubtract; + case 3: return MTL::BlendOperationMin; + case 4: return MTL::BlendOperationMax; + case 5: return MTL::BlendOperationAdd; // Unused (same as 0) + case 6: return MTL::BlendOperationAdd; // Unused (same as 0) + case 7: return MTL::BlendOperationAdd; // Unused (same as 0) + default: panic("Unknown blend operation %u", op); + } + + return MTL::BlendOperationAdd; +} + +inline MTL::BlendFactor toMTLBlendFactor(u8 factor) { + switch (factor) { + case 0: return MTL::BlendFactorZero; + case 1: return MTL::BlendFactorOne; + case 2: return MTL::BlendFactorSourceColor; + case 3: return MTL::BlendFactorOneMinusSourceColor; + case 4: return MTL::BlendFactorDestinationColor; + case 5: return MTL::BlendFactorOneMinusDestinationColor; + case 6: return MTL::BlendFactorSourceAlpha; + case 7: return MTL::BlendFactorOneMinusSourceAlpha; + case 8: return MTL::BlendFactorDestinationAlpha; + case 9: return MTL::BlendFactorOneMinusDestinationAlpha; + case 10: return MTL::BlendFactorBlendColor; + case 11: return MTL::BlendFactorOneMinusBlendColor; + case 12: return MTL::BlendFactorBlendAlpha; + case 13: return MTL::BlendFactorOneMinusBlendAlpha; + case 14: return MTL::BlendFactorSourceAlphaSaturated; + case 15: return MTL::BlendFactorOne; // Undocumented + default: panic("Unknown blend factor %u", factor); + } + + return MTL::BlendFactorOne; +} + } // namespace PICA diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index cedc0d16..b9ae1b05 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -329,6 +329,7 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::span(depthControl); const u8 depthFunc = Helpers::getBits<4, 3>(depthControl); const u8 colorMask = Helpers::getBits<8, 4>(depthControl); + // TODO: color mask // gl.setColourMask(colorMask & 0x1, colorMask & 0x2, colorMask & 0x4, colorMask & 0x8); const u32 stencilConfig = regs[PICA::InternalRegs::StencilTest]; @@ -364,11 +365,25 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spansetStoreAction(MTL::StoreActionStore); } - // Pipeline + // -------- Pipeline -------- Metal::PipelineHash pipelineHash{colorRenderTarget->format, DepthFmt::Unknown1}; if (depthStencilRenderTarget) { pipelineHash.depthFmt = depthStencilRenderTarget->format; } + + // Blending + pipelineHash.blendEnabled = (regs[PICA::InternalRegs::ColourOperation] & (1 << 8)) != 0; + + if (pipelineHash.blendEnabled) { + pipelineHash.blendControl = regs[PICA::InternalRegs::BlendFunc]; + // TODO: constant color + //pipelineHash.constantColor = regs[PICA::InternalRegs::BlendColour]; + //const u8 r = pipelineHash.constantColor & 0xff; + //const u8 g = Helpers::getBits<8, 8>(pipelineHash.constantColor); + //const u8 b = Helpers::getBits<16, 8>(pipelineHash.constantColor); + //const u8 a = Helpers::getBits<24, 8>(pipelineHash.constantColor); + } + MTL::RenderPipelineState* pipeline = drawPipelineCache.get(pipelineHash); // Depth stencil state