diff --git a/src/video_core/math.h b/src/video_core/math.h index f9a822658..f746c4aed 100644 --- a/src/video_core/math.h +++ b/src/video_core/math.h @@ -423,6 +423,27 @@ public: { return x*x + y*y + z*z + w*w; } + + // Needed for logic ops + Vec4 operator ~() const + { + return MakeVec(~x,~y,~z,~w); + } + + Vec4 operator &(const Vec4& other) const + { + return MakeVec(x&other.x, y&other.y, z&other.z, w&other.w); + } + + Vec4 operator |(const Vec4& other) const + { + return MakeVec(x|other.x, y|other.y, z|other.z, w|other.w); + } + + Vec4 operator ^(const Vec4& other) const + { + return MakeVec(x^other.x, y^other.y, z^other.z, w^other.w); + } // Only implemented for T=float float Length() const; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index d03b811d3..250685913 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -374,7 +374,22 @@ struct Regs { union { enum Op { + 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, }; BitField<0, 4, Op> op; diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 24dc37856..17060b280 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -778,8 +778,87 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); } else { - LOG_CRITICAL(HW_GPU, "logic op: %x", registers.output_merger.logic_op); - UNIMPLEMENTED(); + auto params = registers.output_merger.logic_op; + + using LogicOp = decltype(params)::Op; + + auto EvaluateLogicOp = [&](const Math::Vec4& src, const Math::Vec4& dest + LogicOp op) -> Math::Vec4 { + Math::Vec4 result; + + switch(op) { + case LogicOp::Clear: + result = Math::Vec4(0,0,0,0); + break; + + case LogicOp::And: + result = src & dest; + break; + + case LogicOp::AndReverse: + result = src & ~dest; + break; + + case LogicOp::Copy: + result = src; + break; + + case LogicOp::Set: + result = Math::Vec4(1,1,1,1); + break; + + case LogicOp::CopyInverted: + result = ~src; + break; + + case LogicOp::NoOp: + result = dest; + break; + + case LogicOp::Invert: + result = ~dest; + break; + + case LogicOp::Nand: + result = ~(src & dest); + break; + + case LogicOp::Or: + result = src | dest; + break; + + case LogicOp::Nor: + result = ~(src | dest); + break; + + case LogicOp::Xor: + result = src ^ dest; + break; + + case LogicOp::Equiv: + result = ~(src ^ dest); + break; + + case LogicOp::AndInverted: + result = ~src & dest; + break; + + case LogicOp::OrReverse: + result = src | ~dest; + break; + + case LogicOp::OrInverted: + result = ~src | dest; + break; + default: + LOG_CRITICAL(HW_GPU, "Unknown logic op %x", op); + UNIMPLEMENTED(); + } + + return result; + }; + + blend_output = EvaluateLogicOp(combiner_output, dest, params.op); } const Math::Vec4 result = {