From 27c74d89746d582829c1038ca84dd5d22f089e38 Mon Sep 17 00:00:00 2001 From: Samuliak Date: Wed, 3 Jul 2024 20:52:05 +0200 Subject: [PATCH] emulate logic op in the shader --- src/core/renderer_mtl/renderer_mtl.cpp | 6 +++- src/host_shaders/metal_shaders.metal | 48 ++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/core/renderer_mtl/renderer_mtl.cpp b/src/core/renderer_mtl/renderer_mtl.cpp index e42689de..98ba3cbf 100644 --- a/src/core/renderer_mtl/renderer_mtl.cpp +++ b/src/core/renderer_mtl/renderer_mtl.cpp @@ -353,9 +353,10 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spanformat; } - // Blending + // Blending and logic op pipelineHash.blendEnabled = (regs[PICA::InternalRegs::ColourOperation] & (1 << 8)) != 0; + u8 logicOp = 3; // Copy, which doesn't do anything if (pipelineHash.blendEnabled) { pipelineHash.blendControl = regs[PICA::InternalRegs::BlendFunc]; // TODO: constant color @@ -364,6 +365,8 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::span(pipelineHash.constantColor); //const u8 b = Helpers::getBits<16, 8>(pipelineHash.constantColor); //const u8 a = Helpers::getBits<24, 8>(pipelineHash.constantColor); + } else { + logicOp = Helpers::getBits<0, 4>(regs[PICA::InternalRegs::LogicOp]); } MTL::RenderPipelineState* pipeline = drawPipelineCache.get(pipelineHash); @@ -406,6 +409,7 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::spansetVertexBytes(®s[0x48], 0x200 - 0x48, 0); renderCommandEncoder->setFragmentBytes(®s[0x48], 0x200 - 0x48, 0); + renderCommandEncoder->setFragmentBytes(&logicOp, sizeof(logicOp), 2); renderCommandEncoder->drawPrimitives(toMTLPrimitiveType(primType), NS::UInteger(0), NS::UInteger(vertices.size())); } diff --git a/src/host_shaders/metal_shaders.metal b/src/host_shaders/metal_shaders.metal index 2947e827..abf26948 100644 --- a/src/host_shaders/metal_shaders.metal +++ b/src/host_shaders/metal_shaders.metal @@ -247,7 +247,51 @@ struct FragTEV { } }; -fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]], +enum class LogicOp : uint8_t { + Clear = 0, + And = 1, + AndReverse = 2, + Copy = 3, + Set = 4, + CopyInverted = 5, + NoOp = 6, + Invert = 7, + Nand = 8, + Or = 9, + Nor = 10, + Xor = 11, + Equiv = 12, + AndInverted = 13, + OrReverse = 14, + OrInverted = 15 +}; + +uint4 performLogicOpU(LogicOp logicOp, uint4 s, uint4 d) { + switch (logicOp) { + case LogicOp::Clear: return as_type(float4(0.0)); + case LogicOp::And: return s & d; + case LogicOp::AndReverse: return s & ~d; + case LogicOp::Copy: return s; + case LogicOp::Set: return as_type(float4(1.0)); + case LogicOp::CopyInverted: return ~s; + case LogicOp::NoOp: return d; + case LogicOp::Invert: return ~d; + case LogicOp::Nand: return ~(s & d); + case LogicOp::Or: return s | d; + case LogicOp::Nor: return ~(s | d); + case LogicOp::Xor: return s ^ d; + case LogicOp::Equiv: return ~(s ^ d); + case LogicOp::AndInverted: return ~s & d; + case LogicOp::OrReverse: return s | ~d; + case LogicOp::OrInverted: return ~s | d; + } +} + +float4 performLogicOp(LogicOp logicOp, float4 s, float4 d) { + return as_type(performLogicOpU(logicOp, as_type(s), as_type(d))); +} + +fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], float4 prevColor [[color(0)]], constant PicaRegs& picaRegs [[buffer(0)]], constant FragTEV& tev [[buffer(1)]], constant LogicOp& logicOp [[buffer(2)]], texture2d tex0 [[texture(0)]], texture2d tex1 [[texture(1)]], texture2d tex2 [[texture(2)]], sampler samplr0 [[sampler(0)]], sampler samplr1 [[sampler(1)]], sampler samplr2 [[sampler(2)]]) { Globals globals; @@ -284,5 +328,5 @@ fragment float4 fragmentDraw(DrawVertexOut in [[stage_in]], constant PicaRegs& p } } - return globals.tevSources[15]; + return performLogicOp(logicOp, globals.tevSources[15], prevColor); }