From 156120434251d0ae726442206f8b5b41338d700d Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 11 Feb 2015 21:39:43 +0100 Subject: Pica/BlendUnit: Implement separate color/alpha blend equations. --- src/video_core/rasterizer.cpp | 122 ++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 64 deletions(-) (limited to 'src/video_core/rasterizer.cpp') diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b7a7e62a..f96015de 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -5,6 +5,7 @@ #include #include "common/common_types.h" +#include "common/math_util.h" #include "math.h" #include "pica.h" @@ -596,6 +597,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, } auto dest = GetPixel(x >> 4, y >> 4); + Math::Vec4 blend_output = combiner_output; if (registers.output_merger.alphablend_enable) { auto params = registers.output_merger.alpha_blending; @@ -684,81 +686,73 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, } }; + using BlendEquation = decltype(params)::BlendEquation; + static auto EvaluateBlendEquation = [](const Math::Vec4& src, const Math::Vec4& srcfactor, + const Math::Vec4& dest, const Math::Vec4& destfactor, + BlendEquation equation) { + Math::Vec4 result; + + auto src_result = (src * srcfactor).Cast(); + auto dst_result = (dest * destfactor).Cast(); + + switch (equation) { + case BlendEquation::Add: + result = (src_result + dst_result) / 255; + break; + + case BlendEquation::Subtract: + result = (src_result - dst_result) / 255; + break; + + case BlendEquation::ReverseSubtract: + result = (dst_result - src_result) / 255; + break; + + // TODO: How do these two actually work? + // OpenGL doesn't include the blend factors in the min/max computations, + // but is this what the 3DS actually does? + case BlendEquation::Min: + result.r() = std::min(src.r(), dest.r()); + result.g() = std::min(src.g(), dest.g()); + result.b() = std::min(src.b(), dest.b()); + result.a() = std::min(src.a(), dest.a()); + break; + + case BlendEquation::Max: + result.r() = std::max(src.r(), dest.r()); + result.g() = std::max(src.g(), dest.g()); + result.b() = std::max(src.b(), dest.b()); + result.a() = std::max(src.a(), dest.a()); + break; + + default: + LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", equation); + exit(0); + } + + return Math::Vec4(MathUtil::Clamp(result.r(), 0, 255), + MathUtil::Clamp(result.g(), 0, 255), + MathUtil::Clamp(result.b(), 0, 255), + MathUtil::Clamp(result.a(), 0, 255)); + }; + auto srcfactor = Math::MakeVec(LookupFactorRGB(params.factor_source_rgb), LookupFactorA(params.factor_source_a)); auto dstfactor = Math::MakeVec(LookupFactorRGB(params.factor_dest_rgb), LookupFactorA(params.factor_dest_a)); - - auto src_result = (combiner_output * srcfactor).Cast(); - auto dst_result = (dest * dstfactor).Cast(); - - switch (params.blend_equation_rgb) { - case params.Add: - { - auto result = (src_result + dst_result) / 255; - result.r() = std::min(255, result.r()); - result.g() = std::min(255, result.g()); - result.b() = std::min(255, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.Subtract: - { - auto result = (src_result - dst_result) / 255; - result.r() = std::max(0, result.r()); - result.g() = std::max(0, result.g()); - result.b() = std::max(0, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.ReverseSubtract: - { - auto result = (dst_result - src_result) / 255; - result.r() = std::max(0, result.r()); - result.g() = std::max(0, result.g()); - result.b() = std::max(0, result.b()); - combiner_output = result.Cast(); - break; - } - - case params.Min: - { - // TODO: GL spec says to do it without the factors, but is this what the 3DS does? - Math::Vec4 result; - result.r() = std::min(combiner_output.r(),dest.r()); - result.g() = std::min(combiner_output.g(),dest.g()); - result.b() = std::min(combiner_output.b(),dest.b()); - combiner_output = result.Cast(); - break; - } - - case params.Max: - { - // TODO: GL spec says to do it without the factors, but is this what the 3DS does? - Math::Vec4 result; - result.r() = std::max(combiner_output.r(),dest.r()); - result.g() = std::max(combiner_output.g(),dest.g()); - result.b() = std::max(combiner_output.b(),dest.b()); - combiner_output = result.Cast(); - break; - } - default: - LOG_CRITICAL(HW_GPU, "Unknown RGB blend equation %x", params.blend_equation_rgb.Value()); - exit(0); - } + 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); exit(0); } const Math::Vec4 result = { - registers.output_merger.red_enable ? combiner_output.r() : dest.r(), - registers.output_merger.green_enable ? combiner_output.g() : dest.g(), - registers.output_merger.blue_enable ? combiner_output.b() : dest.b(), - registers.output_merger.alpha_enable ? combiner_output.a() : dest.a() + registers.output_merger.red_enable ? blend_output.r() : dest.r(), + registers.output_merger.green_enable ? blend_output.g() : dest.g(), + registers.output_merger.blue_enable ? blend_output.b() : dest.b(), + registers.output_merger.alpha_enable ? blend_output.a() : dest.a() }; DrawPixel(x >> 4, y >> 4, result); -- cgit v1.2.3