Add blend optimization helpers and use to convert rect draws to clears.

R=robertphillips@google.com, jvanverth@google.com

Author: bsalomon@google.com

Review URL: https://chromiumcodereview.appspot.com/22558003

git-svn-id: http://skia.googlecode.com/svn/trunk@10723 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp
new file mode 100644
index 0000000..c0621a9
--- /dev/null
+++ b/src/gpu/GrBlend.cpp
@@ -0,0 +1,154 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBlend.h"
+
+static inline GrBlendCoeff swap_coeff_src_dst(GrBlendCoeff coeff) {
+    switch (coeff) {
+        case kDC_GrBlendCoeff:
+            return kSC_GrBlendCoeff;
+        case kIDC_GrBlendCoeff:
+            return kISC_GrBlendCoeff;
+        case kDA_GrBlendCoeff:
+            return kSA_GrBlendCoeff;
+        case kIDA_GrBlendCoeff:
+            return kISA_GrBlendCoeff;
+        case kSC_GrBlendCoeff:
+            return kDC_GrBlendCoeff;
+        case kISC_GrBlendCoeff:
+            return kIDC_GrBlendCoeff;
+        case kSA_GrBlendCoeff:
+            return kDA_GrBlendCoeff;
+        case kISA_GrBlendCoeff:
+            return kIDA_GrBlendCoeff;
+        default:
+            return coeff;
+    }
+}
+
+static inline unsigned saturated_add(unsigned a, unsigned b) {
+    SkASSERT(a <= 255);
+    SkASSERT(b <= 255);
+    unsigned sum = a + b;
+    if (sum > 255) {
+        sum = 255;
+    }
+    return sum;
+}
+
+static GrColor add_colors(GrColor src, GrColor dst) {
+    unsigned r = saturated_add(GrColorUnpackR(src), GrColorUnpackR(dst));
+    unsigned g = saturated_add(GrColorUnpackG(src), GrColorUnpackG(dst));
+    unsigned b = saturated_add(GrColorUnpackB(src), GrColorUnpackB(dst));
+    unsigned a = saturated_add(GrColorUnpackA(src), GrColorUnpackA(dst));
+    return GrColorPackRGBA(r, g, b, a);
+}
+
+static inline bool valid_color(uint32_t compFlags) {
+     return (kRGBA_GrColorComponentFlags & compFlags) == kRGBA_GrColorComponentFlags;
+}
+
+static GrColor simplify_blend_term(GrBlendCoeff* srcCoeff,
+                                   GrColor srcColor, uint32_t srcCompFlags,
+                                   GrColor dstColor, uint32_t dstCompFlags,
+                                   GrColor constantColor) {
+
+    GrAssert(!GrBlendCoeffRefsSrc(*srcCoeff));
+    GrAssert(NULL != srcCoeff);
+
+    // Check whether srcCoeff can be reduced to kOne or kZero based on known color inputs.
+    // We could pick out the coeff r,g,b,a values here and use them to compute the blend term color,
+    // if possible, below but that is not implemented now.
+    switch (*srcCoeff) {
+        case kIDC_GrBlendCoeff:
+            dstColor = ~dstColor; // fallthrough
+        case kDC_GrBlendCoeff:
+            if (valid_color(dstCompFlags)) {
+                if (0xffffffff == dstColor) {
+                    *srcCoeff = kOne_GrBlendCoeff;
+                } else if (0 == dstColor) {
+                    *srcCoeff = kZero_GrBlendCoeff;
+                }
+            }
+            break;
+
+        case kIDA_GrBlendCoeff:
+            dstColor = ~dstColor; // fallthrough
+        case kDA_GrBlendCoeff:
+            if (kA_GrColorComponentFlag & dstCompFlags) {
+                if (0xff == GrColorUnpackA(dstColor)) {
+                    *srcCoeff = kOne_GrBlendCoeff;
+                } else if (0 == GrColorUnpackA(dstColor)) {
+                    *srcCoeff = kZero_GrBlendCoeff;
+                }
+            }
+            break;
+
+        case kIConstC_GrBlendCoeff:
+            constantColor = ~constantColor; // fallthrough
+        case kConstC_GrBlendCoeff:
+            if (0xffffffff == constantColor) {
+                *srcCoeff = kOne_GrBlendCoeff;
+            } else if (0 == constantColor) {
+                *srcCoeff = kZero_GrBlendCoeff;
+            }
+            break;
+
+        case kIConstA_GrBlendCoeff:
+            constantColor = ~constantColor; // fallthrough
+        case kConstA_GrBlendCoeff:
+            if (0xff == GrColorUnpackA(constantColor)) {
+                *srcCoeff = kOne_GrBlendCoeff;
+            } else if (0 == GrColorUnpackA(constantColor)) {
+                *srcCoeff = kZero_GrBlendCoeff;
+            }
+            break;
+            
+        default:
+            break;
+    }
+    // We may have invalidated these above and shouldn't read them again.
+    GR_DEBUGCODE(dstColor = constantColor = GrColor_ILLEGAL;)
+
+    if (kZero_GrBlendCoeff == *srcCoeff || (valid_color(srcCompFlags) && 0 == srcColor)) {
+        *srcCoeff = kZero_GrBlendCoeff;
+        return 0;
+    }
+
+    if (kOne_GrBlendCoeff == *srcCoeff && valid_color(srcCompFlags)) {
+        return srcColor;
+    } else {
+        return GrColor_ILLEGAL;
+    }
+}
+
+GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
+                        GrBlendCoeff* dstCoeff,
+                        GrColor srcColor, uint32_t srcCompFlags,
+                        GrColor dstColor, uint32_t dstCompFlags,
+                        GrColor constantColor) {
+    GrColor srcTermColor = simplify_blend_term(srcCoeff,
+                                               srcColor, srcCompFlags,
+                                               dstColor, dstCompFlags,
+                                               constantColor);
+
+    // We call the same function to simplify the dst blend coeff. We trick it out by swapping the
+    // src and dst.
+    GrBlendCoeff spoofedCoeff = swap_coeff_src_dst(*dstCoeff);
+    GrColor dstTermColor = simplify_blend_term(&spoofedCoeff,
+                                               dstColor, dstCompFlags,
+                                               srcColor, srcCompFlags,
+                                               constantColor);
+    *dstCoeff = swap_coeff_src_dst(spoofedCoeff);
+
+    if (GrColor_ILLEGAL != srcTermColor && GrColor_ILLEGAL != dstTermColor) {
+        return add_colors(srcTermColor, dstTermColor);
+    } else {
+        return GrColor_ILLEGAL;
+    }
+}