From e2b63a2dd7ed1b2714daf5ff94f7603111ce78c6 Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Sat, 2 Apr 2016 03:26:10 +0200
Subject: [PATCH] Rasterizer: Allow all blend factors for alpha blend-func

---
 src/video_core/rasterizer.cpp | 105 +++++++++++++++-------------------
 1 file changed, 45 insertions(+), 60 deletions(-)

diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 5b9ed7c641..0434ad05a6 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -923,60 +923,16 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
             if (output_merger.alphablend_enable) {
                 auto params = output_merger.alpha_blending;
 
-                auto LookupFactorRGB = [&](Regs::BlendFactor factor) -> Math::Vec3<u8> {
-                    switch (factor) {
-                    case Regs::BlendFactor::Zero :
-                        return Math::Vec3<u8>(0, 0, 0);
+                auto LookupFactor = [&](unsigned channel, Regs::BlendFactor factor) -> u8 {
+                    DEBUG_ASSERT(channel < 4);
 
-                    case Regs::BlendFactor::One :
-                        return Math::Vec3<u8>(255, 255, 255);
+                    const Math::Vec4<u8> blend_const = {
+                        static_cast<u8>(output_merger.blend_const.r),
+                        static_cast<u8>(output_merger.blend_const.g),
+                        static_cast<u8>(output_merger.blend_const.b),
+                        static_cast<u8>(output_merger.blend_const.a)
+                    };
 
-                    case Regs::BlendFactor::SourceColor:
-                        return combiner_output.rgb();
-
-                    case Regs::BlendFactor::OneMinusSourceColor:
-                        return Math::Vec3<u8>(255 - combiner_output.r(), 255 - combiner_output.g(), 255 - combiner_output.b());
-
-                    case Regs::BlendFactor::DestColor:
-                        return dest.rgb();
-
-                    case Regs::BlendFactor::OneMinusDestColor:
-                        return Math::Vec3<u8>(255 - dest.r(), 255 - dest.g(), 255 - dest.b());
-
-                    case Regs::BlendFactor::SourceAlpha:
-                        return Math::Vec3<u8>(combiner_output.a(), combiner_output.a(), combiner_output.a());
-
-                    case Regs::BlendFactor::OneMinusSourceAlpha:
-                        return Math::Vec3<u8>(255 - combiner_output.a(), 255 - combiner_output.a(), 255 - combiner_output.a());
-
-                    case Regs::BlendFactor::DestAlpha:
-                        return Math::Vec3<u8>(dest.a(), dest.a(), dest.a());
-
-                    case Regs::BlendFactor::OneMinusDestAlpha:
-                        return Math::Vec3<u8>(255 - dest.a(), 255 - dest.a(), 255 - dest.a());
-
-                    case Regs::BlendFactor::ConstantColor:
-                        return Math::Vec3<u8>(output_merger.blend_const.r, output_merger.blend_const.g, output_merger.blend_const.b);
-
-                    case Regs::BlendFactor::OneMinusConstantColor:
-                        return Math::Vec3<u8>(255 - output_merger.blend_const.r, 255 - output_merger.blend_const.g, 255 - output_merger.blend_const.b);
-
-                    case Regs::BlendFactor::ConstantAlpha:
-                        return Math::Vec3<u8>(output_merger.blend_const.a, output_merger.blend_const.a, output_merger.blend_const.a);
-
-                    case Regs::BlendFactor::OneMinusConstantAlpha:
-                        return Math::Vec3<u8>(255 - output_merger.blend_const.a, 255 - output_merger.blend_const.a, 255 - output_merger.blend_const.a);
-
-                    default:
-                        LOG_CRITICAL(HW_GPU, "Unknown color blend factor %x", factor);
-                        UNIMPLEMENTED();
-                        break;
-                    }
-
-                    return {};
-                };
-
-                auto LookupFactorA = [&](Regs::BlendFactor factor) -> u8 {
                     switch (factor) {
                     case Regs::BlendFactor::Zero:
                         return 0;
@@ -984,6 +940,18 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
                     case Regs::BlendFactor::One:
                         return 255;
 
+                    case Regs::BlendFactor::SourceColor:
+                        return combiner_output[channel];
+
+                    case Regs::BlendFactor::OneMinusSourceColor:
+                        return 255 - combiner_output[channel];
+
+                    case Regs::BlendFactor::DestColor:
+                        return dest[channel];
+
+                    case Regs::BlendFactor::OneMinusDestColor:
+                        return 255 - dest[channel];
+
                     case Regs::BlendFactor::SourceAlpha:
                         return combiner_output.a();
 
@@ -996,19 +964,31 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
                     case Regs::BlendFactor::OneMinusDestAlpha:
                         return 255 - dest.a();
 
+                    case Regs::BlendFactor::ConstantColor:
+                        return blend_const[channel];
+
+                    case Regs::BlendFactor::OneMinusConstantColor:
+                        return 255 - blend_const[channel];
+
                     case Regs::BlendFactor::ConstantAlpha:
-                        return output_merger.blend_const.a;
+                        return blend_const.a();
 
                     case Regs::BlendFactor::OneMinusConstantAlpha:
-                        return 255 - output_merger.blend_const.a;
+                        return 255 - blend_const.a();
+
+                    case Regs::BlendFactor::SourceAlphaSaturate:
+                        // Returns 1.0 for the alpha channel
+                        if (channel == 3)
+                            return 255;
+                        return std::min(combiner_output.a(), static_cast<u8>(255 - dest.a()));
 
                     default:
-                        LOG_CRITICAL(HW_GPU, "Unknown alpha blend factor %x", factor);
+                        LOG_CRITICAL(HW_GPU, "Unknown blend factor %x", factor);
                         UNIMPLEMENTED();
                         break;
                     }
 
-                    return {};
+                    return combiner_output[channel];
                 };
 
                 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
@@ -1060,10 +1040,15 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0,
                                     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 srcfactor = Math::MakeVec(LookupFactor(0, params.factor_source_rgb),
+                                               LookupFactor(1, params.factor_source_rgb),
+                                               LookupFactor(2, params.factor_source_rgb),
+                                               LookupFactor(3, params.factor_source_a));
+
+                auto dstfactor = Math::MakeVec(LookupFactor(0, params.factor_dest_rgb),
+                                               LookupFactor(1, params.factor_dest_rgb),
+                                               LookupFactor(2, params.factor_dest_rgb),
+                                               LookupFactor(3, params.factor_dest_a));
 
                 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();