emulate logic op in the shader

This commit is contained in:
Samuliak 2024-07-03 20:52:05 +02:00
parent dfe38a757c
commit 27c74d8974
2 changed files with 51 additions and 3 deletions

View file

@ -353,9 +353,10 @@ void RendererMTL::drawVertices(PICA::PrimType primType, std::span<const PICA::Ve
pipelineHash.depthFmt = depthStencilRenderTarget->format;
}
// 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<const PICA::Ve
//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);
} 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::span<const PICA::Ve
bindTexturesToSlots(renderCommandEncoder);
renderCommandEncoder->setVertexBytes(&regs[0x48], 0x200 - 0x48, 0);
renderCommandEncoder->setFragmentBytes(&regs[0x48], 0x200 - 0x48, 0);
renderCommandEncoder->setFragmentBytes(&logicOp, sizeof(logicOp), 2);
renderCommandEncoder->drawPrimitives(toMTLPrimitiveType(primType), NS::UInteger(0), NS::UInteger(vertices.size()));
}

View file

@ -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<uint4>(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<uint4>(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<float4>(performLogicOpU(logicOp, as_type<uint4>(s), as_type<uint4>(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<float> tex0 [[texture(0)]], texture2d<float> tex1 [[texture(1)]], texture2d<float> 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);
}