Revert of Implement Porter Duff XP with a blend table (patchset #12 id:220001 of...
authorbungeman <bungeman@google.com>
Sat, 23 May 2015 00:55:26 +0000 (17:55 -0700)
committerCommit bot <commit-bot@chromium.org>
Sat, 23 May 2015 00:55:26 +0000 (17:55 -0700)
Reason for revert:
Blocking DEPS roll into Chromium. Crashing virtual/gpu/fast/canvas/canvas-composite-*.html tests with the assert

../../third_party/skia/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp:281: failed assertion "k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty()"

Original issue's description:
> Implement Porter Duff XP with a blend table
>
> Removes the runtime logic used by PorterDuffXferProcessor to decide
> blend coeffs and shader outputs, and instead uses a compile-time
> constant table of pre-selected blend formulas.
>
> Introduces a new blend strategy for srcCoeff=0 that can apply coverage
> with a reverse subtract blend equation instead of dual source
> blending.
>
> Adds new macros in GrBlend.h to analyze blend formulas both runtime.
>
> Removes kSetCoverageDrawing_OptFlag and GrSimplifyBlend as they are no
> longer used.
>
> Adds a GM that verifies all xfermodes, including arithmetic, with the
> color/coverage invariants used by Porter Duff.
>
> Adds a unit test that verifies each Porter Duff formula with every
> color/coverage invariant.
>
> Major changes:
>
>  * Uses a reverse subtract blend equation for coverage when srcCoeff=0
>    (clear, dst-out [Sa=1], dst-in, modulate). Platforms that don't
>    support dual source blending no longer require a dst copy for
>    dst-in and modulate.
>
>  * Sets BlendInfo::fWriteColor to false when the blend does not modify
>    the dst. GrGLGpu will now use glColorMask instead of blending for
>    these modes (dst, dst-in [Sa=1], modulate ignored for [Sc=1]).
>
>  * Converts all SA blend coeffs to One for opaque inputs, and ISA to
>    Zero if there is also no coverage. (We keep ISA around when there
>    is coverage because we use it to tweak alpha for coverage.)
>
>  * Abandons solid white optimizations for the sake of simplicity
>    (screen was the only mode that previous had solid white opts).
>
> Minor differences:
>
>  * Inconsequential differences in opt flags (e.g. we now return
>    kCanTweakAlphaForCoverage_OptFlag even when there is no coverage).
>
>  * Src coeffs when the shader outputs 0.
>
>  * IS2C vs IS2A when the secondary output is scalar.
>
> BUG=skia:
>
> Committed: https://skia.googlesource.com/skia/+/9a70920db22b6309c671f8e5d519bb95570e4414

TBR=egdaniel@google.com,bsalomon@google.com,cdalton@nvidia.com
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

Review URL: https://codereview.chromium.org/1153993002

gm/aaxfermodes.cpp [deleted file]
gyp/gpu.gypi
include/gpu/GrColor.h
include/gpu/GrXferProcessor.h
include/gpu/effects/GrPorterDuffXferProcessor.h
src/gpu/GrBlend.cpp [new file with mode: 0644]
src/gpu/GrBlend.h
src/gpu/effects/GrPorterDuffXferProcessor.cpp
tests/GrPorterDuffTest.cpp [deleted file]

diff --git a/gm/aaxfermodes.cpp b/gm/aaxfermodes.cpp
deleted file mode 100644 (file)
index 30b34a4..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-#include "gm.h"
-#include "SkArithmeticMode.h"
-#include "SkShader.h"
-#include "SkXfermode.h"
-
-enum {
-    kXfermodeCount = SkXfermode::kLastMode + 2, // All xfermodes plus arithmetic mode.
-    kShapeSize = 22,
-    kShapeSpacing = 36,
-    kShapeTypeSpacing = 4 * kShapeSpacing/3,
-    kPaintSpacing = 2 * kShapeSpacing,
-    kPadding = (kPaintSpacing - kShapeSpacing) / 2,
-
-    kPaintWidth = 3*kShapeSpacing + 2*kShapeTypeSpacing + kShapeSize,
-    kPaintPadding = kPaintSpacing - kShapeSize,
-};
-
-static const SkColor kBGColor = SkColorSetARGB(200, 210, 184, 135);
-
-static const SkColor kShapeColors[3] = {
-    SkColorSetARGB(130, 255, 0, 128),   // input color unknown
-    SkColorSetARGB(255, 0, 255, 255),   // input color opaque
-    SkColorSetARGB(255, 255, 255, 255)  // input solid white
-};
-
-enum Shape {
-    kSquare_Shape,
-    kDiamond_Shape,
-    kOval_Shape,
-
-    kLast_Shape = kOval_Shape
-};
-
-namespace skiagm {
-
-static void draw_shape(SkCanvas* canvas, Shape shape, const SkColor color, size_t xfermodeIdx);
-
-/**
- * Verifies AA works properly on all Xfermodes, including arithmetic, with various color invariants.
- */
-class AAXfermodesGM : public GM {
-public:
-    AAXfermodesGM() {}
-
-protected:
-    SkString onShortName() override {
-        return SkString("aaxfermodes");
-    }
-
-    SkISize onISize() override {
-        return SkISize::Make(3*kPaintWidth + 2*kPaintPadding + 2*kPadding,
-                             (2 + SkXfermode::kLastCoeffMode) * kShapeSpacing + 2*kPadding);
-    }
-
-    void onDraw(SkCanvas* canvas) override {
-        sk_tool_utils::draw_checkerboard(canvas, 0xffffffff, 0xffc0c0c0, 10);
-
-        canvas->saveLayer(NULL, NULL);
-        canvas->drawColor(kBGColor, SkXfermode::kSrc_Mode);
-
-        canvas->translate(kPadding + kShapeSize/2, kPadding + kShapeSpacing + kShapeSize/2);
-
-        for (size_t colorIdx = 0; colorIdx < SK_ARRAY_COUNT(kShapeColors); colorIdx++) {
-            SkColor color = kShapeColors[colorIdx];
-
-            for (size_t shapeIdx = 0; shapeIdx <= kLast_Shape; shapeIdx++) {
-                Shape shape = static_cast<Shape>(shapeIdx);
-                canvas->save();
-
-                for (size_t xfermodeIdx = 0; xfermodeIdx < kXfermodeCount; xfermodeIdx++) {
-                    draw_shape(canvas, shape, color, xfermodeIdx);
-
-                    if (xfermodeIdx == SkXfermode::kLastCoeffMode) {
-                        // New column.
-                        canvas->restore();
-                        canvas->translate(kShapeSpacing, 0);
-                        canvas->save();
-                    } else {
-                        canvas->translate(0, kShapeSpacing);
-                    }
-                }
-
-                canvas->restore();
-
-                if (shape != kLast_Shape) {
-                    canvas->translate(kShapeTypeSpacing, 0);
-                } else {
-                    canvas->translate(kPaintSpacing, 0);
-                }
-            }
-        }
-
-        canvas->restore();
-
-        SkPaint textPaint;
-        textPaint.setAntiAlias(true);
-        sk_tool_utils::set_portable_typeface(&textPaint);
-        textPaint.setTextAlign(SkPaint::kCenter_Align);
-        textPaint.setFakeBoldText(true);
-        textPaint.setTextSize(21 * kShapeSize/32);
-
-        canvas->translate(kPadding + kPaintWidth/2,
-                          kPadding + kShapeSize/2 + textPaint.getTextSize()/4);
-        canvas->drawText("input color unknown", sizeof("input color unknown") - 1, 0, 0, textPaint);
-
-        canvas->translate(kPaintWidth + kPaintPadding, 0);
-        canvas->drawText("input color opaque", sizeof("input color opaque") - 1, 0, 0, textPaint);
-
-        canvas->translate(kPaintWidth + kPaintPadding, 0);
-        canvas->drawText("input solid white", sizeof("input solid white") - 1, 0, 0, textPaint);
-    }
-
-private:
-    typedef GM INHERITED;
-};
-
-static void draw_shape(SkCanvas* canvas, Shape shape, const SkColor color, size_t xfermodeIdx) {
-    SkPaint shapePaint;
-    shapePaint.setAntiAlias(kSquare_Shape != shape);
-    shapePaint.setColor(color);
-
-    SkAutoTUnref<SkXfermode> xfermode;
-    if (xfermodeIdx <= SkXfermode::kLastMode) {
-        SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeIdx);
-        xfermode.reset(SkXfermode::Create(mode));
-    } else {
-        xfermode.reset(SkArithmeticMode::Create(+1.0f, +0.25f, -0.5f, +0.1f));
-    }
-    shapePaint.setXfermode(xfermode);
-
-    if (xfermodeIdx == SkXfermode::kPlus_Mode) {
-        // Check for overflow and dim the src and dst colors if we need to, otherwise we might get
-        // confusing AA artifacts.
-        int maxSum = SkTMax(SkTMax(SkColorGetA(kBGColor) + SkColorGetA(color),
-                                   SkColorGetR(kBGColor) + SkColorGetR(color)),
-                            SkTMax(SkColorGetG(kBGColor) + SkColorGetG(color),
-                                   SkColorGetB(kBGColor) + SkColorGetB(color)));
-
-        if (maxSum > 255) {
-            SkPaint dimPaint;
-            dimPaint.setARGB(255 * 255 / maxSum, 0, 0, 0);
-            dimPaint.setAntiAlias(false);
-            dimPaint.setXfermode(SkXfermode::Create(SkXfermode::kDstIn_Mode));
-            canvas->drawRectCoords(-kShapeSpacing/2, -kShapeSpacing/2,
-                                   kShapeSpacing/2, kShapeSpacing/2, dimPaint);
-
-            shapePaint.setAlpha(255 * shapePaint.getAlpha() / maxSum);
-        }
-    }
-
-    switch (shape) {
-        case kSquare_Shape:
-            canvas->drawRectCoords(-kShapeSize/2, -kShapeSize/2, kShapeSize/2, kShapeSize/2,
-                                   shapePaint);
-            break;
-
-        case kDiamond_Shape:
-            canvas->save();
-            canvas->rotate(45);
-            canvas->drawRectCoords(-kShapeSize/2, -kShapeSize/2, kShapeSize/2, kShapeSize/2,
-                                   shapePaint);
-            canvas->restore();
-            break;
-
-        case kOval_Shape:
-            canvas->save();
-            canvas->rotate(static_cast<SkScalar>((511 * xfermodeIdx + 257) % 360));
-            canvas->drawArc(SkRect::MakeLTRB(-kShapeSize/2, -1.4f * kShapeSize/2,
-                                             kShapeSize/2, 1.4f * kShapeSize/2),
-                            0, 360, true, shapePaint);
-            canvas->restore();
-            break;
-
-        default:
-            SkFAIL("Invalid shape.");
-    }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-static GM* MyFactory(void*) { return new AAXfermodesGM; }
-static GMRegistry reg(MyFactory);
-
-}
index e56175b..01f70f1 100644 (file)
@@ -80,6 +80,7 @@
       '<(skia_src_path)/gpu/GrBatchTarget.h',
       '<(skia_src_path)/gpu/GrBatchTest.cpp',
       '<(skia_src_path)/gpu/GrBatchTest.h',
+      '<(skia_src_path)/gpu/GrBlend.cpp',
       '<(skia_src_path)/gpu/GrBlend.h',
       '<(skia_src_path)/gpu/GrBufferAllocPool.cpp',
       '<(skia_src_path)/gpu/GrBufferAllocPool.h',
index 9ccc638..f5757b9 100644 (file)
@@ -142,8 +142,6 @@ enum GrColorComponentFlags {
     kB_GrColorComponentFlag = 1 << (GrColor_SHIFT_B / 8),
     kA_GrColorComponentFlag = 1 << (GrColor_SHIFT_A / 8),
 
-    kNone_GrColorComponentFlags = 0,
-
     kRGB_GrColorComponentFlags = (kR_GrColorComponentFlag | kG_GrColorComponentFlag |
                                   kB_GrColorComponentFlag),
 
@@ -151,8 +149,6 @@ enum GrColorComponentFlags {
                                    kB_GrColorComponentFlag | kA_GrColorComponentFlag)
 };
 
-GR_MAKE_BITFIELD_OPS(GrColorComponentFlags)
-
 static inline char GrColorComponentFlagToChar(GrColorComponentFlags component) {
     SkASSERT(SkIsPow2(component));
     switch (component) {
index 85e5aa0..8458a62 100644 (file)
@@ -51,6 +51,10 @@ enum GrBlendEquation {
 
 static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1;
 
+inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
+    return equation >= kFirstAdvancedGrBlendEquation;
+}
+
 /**
  * Coeffecients for alpha-blending.
  */
@@ -139,6 +143,10 @@ public:
          */
         kOverrideColor_OptFlag            = 0x8,
         /**
+         * Set CoverageDrawing_StateBit
+         */
+        kSetCoverageDrawing_OptFlag       = 0x10,
+        /**
          * Can tweak alpha for coverage. Currently this flag should only be used by a batch
          */
         kCanTweakAlphaForCoverage_OptFlag = 0x20,
index 56ddb37..481b373 100644 (file)
@@ -24,7 +24,7 @@ public:
                             GrXPFactory::InvariantOutput*) const override;
 
 private:
-    GrPorterDuffXPFactory(SkXfermode::Mode);
+    GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst); 
 
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const GrProcOptInfo& colorPOI,
@@ -37,15 +37,14 @@ private:
 
     bool onIsEqual(const GrXPFactory& xpfBase) const override {
         const GrPorterDuffXPFactory& xpf = xpfBase.cast<GrPorterDuffXPFactory>();
-        return fXfermode == xpf.fXfermode;
+        return (fSrcCoeff == xpf.fSrcCoeff && fDstCoeff == xpf.fDstCoeff);
     }
 
     GR_DECLARE_XP_FACTORY_TEST;
-    static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary);
 
-    SkXfermode::Mode fXfermode;
+    GrBlendCoeff fSrcCoeff;
+    GrBlendCoeff fDstCoeff;
 
-    friend class GrPorterDuffTest; // for TestGetXPOutputTypes()
     typedef GrXPFactory INHERITED;
 };
 
diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp
new file mode 100644 (file)
index 0000000..52e335e
--- /dev/null
@@ -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) {
+
+    SkASSERT(!GrBlendCoeffRefsSrc(*srcCoeff));
+    SkASSERT(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.
+    SkDEBUGCODE(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;
+    }
+}
index 05d7ebc..e5b8993 100644 (file)
@@ -7,22 +7,13 @@
  */
 
 #include "GrTypes.h"
-#include "SkTLogic.h"
+#include "GrColor.h"
 #include "GrXferProcessor.h"
 
 #ifndef GrBlend_DEFINED
 #define GrBlend_DEFINED
 
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsSrc : SkTBool<kSC_GrBlendCoeff == Coeff ||
-                                      kISC_GrBlendCoeff == Coeff ||
-                                      kSA_GrBlendCoeff == Coeff ||
-                                      kISA_GrBlendCoeff == Coeff> {};
-
-#define GR_BLEND_COEFF_REFS_SRC(COEFF) \
-    GrTBlendCoeffRefsSrc<COEFF>::value
-
-inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
+static inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
     switch (coeff) {
         case kSC_GrBlendCoeff:
         case kISC_GrBlendCoeff:
@@ -34,17 +25,7 @@ inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
     }
 }
 
-
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsDst : SkTBool<kDC_GrBlendCoeff == Coeff ||
-                                      kIDC_GrBlendCoeff == Coeff ||
-                                      kDA_GrBlendCoeff == Coeff ||
-                                      kIDA_GrBlendCoeff == Coeff> {};
-
-#define GR_BLEND_COEFF_REFS_DST(COEFF) \
-    GrTBlendCoeffRefsDst<COEFF>::value
-
-inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
+static inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
     switch (coeff) {
         case kDC_GrBlendCoeff:
         case kIDC_GrBlendCoeff:
@@ -56,88 +37,10 @@ inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
     }
 }
 
-
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsSrc2 : SkTBool<kS2C_GrBlendCoeff == Coeff ||
-                                       kIS2C_GrBlendCoeff == Coeff ||
-                                       kS2A_GrBlendCoeff == Coeff ||
-                                       kIS2A_GrBlendCoeff == Coeff> {};
-
-#define GR_BLEND_COEFF_REFS_SRC2(COEFF) \
-    GrTBlendCoeffRefsSrc2<COEFF>::value
-
-
-template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendCoeffsUseSrcColor : SkTBool<kZero_GrBlendCoeff != SrcCoeff ||
-                                           GR_BLEND_COEFF_REFS_SRC(DstCoeff)> {};
-
-#define GR_BLEND_COEFFS_USE_SRC_COLOR(SRC_COEFF, DST_COEFF) \
-    GrTBlendCoeffsUseSrcColor<SRC_COEFF, DST_COEFF>::value
-
-
-template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendCoeffsUseDstColor : SkTBool<GR_BLEND_COEFF_REFS_DST(SrcCoeff) ||
-                                           kZero_GrBlendCoeff != DstCoeff> {};
-
-#define GR_BLEND_COEFFS_USE_DST_COLOR(SRC_COEFF, DST_COEFF) \
-    GrTBlendCoeffsUseDstColor<SRC_COEFF, DST_COEFF>::value
-
-
-template<GrBlendEquation Equation>
-struct GrTBlendEquationIsAdvanced : SkTBool<Equation >= kFirstAdvancedGrBlendEquation> {};
-
-#define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \
-    GrTBlendEquationIsAdvanced<EQUATION>::value
-
-inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
-    return equation >= kFirstAdvancedGrBlendEquation;
-}
-
-
-template<GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendModifiesDst : SkTBool<(kAdd_GrBlendEquation != BlendEquation &&
-                                      kReverseSubtract_GrBlendEquation != BlendEquation) ||
-                                     kZero_GrBlendCoeff != SrcCoeff ||
-                                     kOne_GrBlendCoeff != DstCoeff> {};
-
-#define GR_BLEND_MODIFIES_DST(EQUATION, SRC_COEFF, DST_COEFF) \
-    GrTBlendModifiesDst<EQUATION, SRC_COEFF, DST_COEFF>::value
-
-
-/**
- * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
- *
- * For "add" and "reverse subtract" the blend equation with f=coverage is:
- *
- *   D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
- *      = f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
- *
- * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the
- * following relationship holds:
- *
- *   (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
- *
- * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.)
- *
- * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff
- * does not reference S). For the dst term, this will work as long as the following is true:
- *|
- *   dstCoeff' == f * dstCoeff + (1 - f)
- *   dstCoeff' == 1 - f * (1 - dstCoeff)
- *
- * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in
- * dstCoeff references S.
- */
-template<GrBlendEquation Equation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendCanTweakAlphaForCoverage : SkTBool<GR_BLEND_EQUATION_IS_ADVANCED(Equation) ||
-                                                  ((kAdd_GrBlendEquation == Equation ||
-                                                    kReverseSubtract_GrBlendEquation == Equation) &&
-                                                   !GR_BLEND_COEFF_REFS_SRC(SrcCoeff) &&
-                                                   (kOne_GrBlendCoeff == DstCoeff ||
-                                                    kISC_GrBlendCoeff == DstCoeff ||
-                                                    kISA_GrBlendCoeff == DstCoeff))> {};
-
-#define GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(EQUATION, SRC_COEFF, DST_COEFF) \
-    GrTBlendCanTweakAlphaForCoverage<EQUATION, SRC_COEFF, DST_COEFF>::value
+GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
+                        GrBlendCoeff* dstCoeff,
+                        GrColor srcColor, uint32_t srcCompFlags,
+                        GrColor dstColor, uint32_t dstCompFlags,
+                        GrColor constantColor);
 
 #endif
index de0143a..43cdc40 100644 (file)
 #include "gl/builders/GrGLFragmentShaderBuilder.h"
 #include "gl/builders/GrGLProgramBuilder.h"
 
-/**
- * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
- */
-struct BlendFormula {
-public:
-    /**
-     * Values the shader can write to primary and secondary outputs. These must all be modulated by
-     * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
+static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
+    /*
+     The fractional coverage is f.
+     The src and dst coeffs are Cs and Cd.
+     The dst and src colors are S and D.
+     We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
+     we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
+     term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
+     find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
      */
-    enum OutputType {
-        kNone_OutputType,        //<! 0
-        kCoverage_OutputType,    //<! inputCoverage
-        kModulate_OutputType,    //<! inputColor * inputCoverage
-        kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
-        kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
-
-        kLast_OutputType = kISCModulate_OutputType
-    };
-
-    enum Properties {
-        kModifiesDst_Property              = 1,
-        kUsesDstColor_Property             = 1 << 1,
-        kUsesInputColor_Property           = 1 << 2,
-        kCanTweakAlphaForCoverage_Property = 1 << 3,
-
-        kLast_Property = kCanTweakAlphaForCoverage_Property
-    };
-
-    BlendFormula& operator =(const BlendFormula& other) {
-        fData = other.fData;
-        return *this;
-    }
-
-    bool operator ==(const BlendFormula& other) const {
-        return fData == other.fData;
-    }
-
-    bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
-    bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
-    bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
-    bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
-    bool canTweakAlphaForCoverage() const {
-        return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
-    }
-
-    /**
-     * Deduce the properties of a compile-time constant BlendFormula.
-     */
-    template<OutputType PrimaryOut, OutputType SecondaryOut,
-             GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-    struct get_properties : SkTIntegralConstant<Properties, static_cast<Properties>(
-
-        (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
-            kModifiesDst_Property : 0) |
-
-        (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
-            kUsesDstColor_Property : 0) |
-
-        ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
-         (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
-            kUsesInputColor_Property : 0) |  // We assert later that SrcCoeff doesn't ref src2.
-
-        (kModulate_OutputType == PrimaryOut &&
-         kNone_OutputType == SecondaryOut &&
-         GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
-            kCanTweakAlphaForCoverage_Property : 0))> {
-
-        // The provided formula should already be optimized.
-        GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
-                         !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
-        GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
-        GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
-                         !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
-        GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
-        GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
-    };
-
-    union {
-        struct {
-            // We allot the enums one more bit than they require because MSVC seems to sign-extend
-            // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
-            OutputType        fPrimaryOutputType    : 4;
-            OutputType        fSecondaryOutputType  : 4;
-            GrBlendEquation   fBlendEquation        : 6;
-            GrBlendCoeff      fSrcCoeff             : 6;
-            GrBlendCoeff      fDstCoeff             : 6;
-            Properties        fProps                : 32 - (4 + 4 + 6 + 6 + 6);
-        };
-        uint32_t fData;
-    };
-
-    GR_STATIC_ASSERT(kLast_OutputType      < (1 << 3));
-    GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
-    GR_STATIC_ASSERT(kLast_GrBlendCoeff    < (1 << 5));
-    GR_STATIC_ASSERT(kLast_Property        < (1 << 6));
-};
-
-GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
-
-GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
-
-/**
- * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
- */
-#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
-    {{{PRIMARY_OUT, \
-       SECONDARY_OUT, \
-       BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
-       BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
-                                    BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
-
-/**
- * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
- * Porter Duff formula.
- */
-#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
-    INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
-                       BlendFormula::kNone_OutputType, \
-                       kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
-
-/**
- * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
- * the primary output type to none.
- */
-#define DST_CLEAR_FORMULA \
-    INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
-                       BlendFormula::kNone_OutputType, \
-                       kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
-
-/**
- * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
- * so we can set the primary output type to none.
- */
-#define NO_DST_WRITE_FORMULA \
-    INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
-                       BlendFormula::kNone_OutputType, \
-                       kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
-
-/**
- * When there is coverage, the equation with f=coverage is:
- *
- *   D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
- *
- * This can be rewritten as:
- *
- *   D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
- *
- * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
- * HW dst coeff with IS2C.
- *
- * Xfer modes: dst-atop (Sa!=1)
- */
-#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
-    INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
-                       ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
-                       kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
-
-/**
- * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
- *
- *   D' = f * D * dstCoeff + (1-f) * D
- *
- * This can be rewritten as:
- *
- *   D' = D - D * [f * (1 - dstCoeff)]
- *
- * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
- * subtract HW blend equation with coeffs of (DC, One).
- *
- * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
- */
-#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
-    INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
-                       BlendFormula::kNone_OutputType, \
-                       kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
-
-/**
- * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
- *
- *   D' = f * S * srcCoeff + (1-f) * D
- *
- * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
- * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
- *
- * Xfer modes (Sa!=1): src, src-in, src-out
- */
-#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
-    INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
-                       BlendFormula::kCoverage_OutputType, \
-                       kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
-
-/**
- * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
- * with and without an opaque input color. Optimization properties are deduced at compile time so we
- * can make runtime decisions quickly. RGB coverage is not supported.
- */
-static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
-
-                     /*>> Has coverage, input color unknown <<*/ {{
-
-    /* clear */      COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
-    /* src */        COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
-    /* dst */        NO_DST_WRITE_FORMULA,
-    /* src-over */   COEFF_FORMULA(   kOne_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* src-in */     COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
-    /* dst-in */     COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
-    /* src-out */    COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
-    /* dst-out */    COEFF_FORMULA(   kZero_GrBlendCoeff,   kISA_GrBlendCoeff),
-    /* src-atop */   COEFF_FORMULA(   kDA_GrBlendCoeff,     kISA_GrBlendCoeff),
-    /* dst-atop */   COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
-    /* xor */        COEFF_FORMULA(   kIDA_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* modulate */   COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
-    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
-
-                     }, /*>> No coverage, input color unknown <<*/ {
-
-    /* clear */      DST_CLEAR_FORMULA,
-    /* src */        COEFF_FORMULA(   kOne_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* dst */        NO_DST_WRITE_FORMULA,
-    /* src-over */   COEFF_FORMULA(   kOne_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* src-in */     COEFF_FORMULA(   kDA_GrBlendCoeff,     kZero_GrBlendCoeff),
-    /* dst-in */     COEFF_FORMULA(   kZero_GrBlendCoeff,   kSA_GrBlendCoeff),
-    /* src-out */    COEFF_FORMULA(   kIDA_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* dst-out */    COEFF_FORMULA(   kZero_GrBlendCoeff,   kISA_GrBlendCoeff),
-    /* src-atop */   COEFF_FORMULA(   kDA_GrBlendCoeff,     kISA_GrBlendCoeff),
-    /* dst-atop */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kSA_GrBlendCoeff),
-    /* xor */        COEFF_FORMULA(   kIDA_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* modulate */   COEFF_FORMULA(   kZero_GrBlendCoeff,   kSC_GrBlendCoeff),
-    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
-
-                     }}, /*>> Has coverage, input color opaque <<*/ {{
-
-    /* clear */      COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
-    /* src */        COEFF_FORMULA(   kOne_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* dst */        NO_DST_WRITE_FORMULA,
-    /* src-over */   COEFF_FORMULA(   kOne_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* src-in */     COEFF_FORMULA(   kDA_GrBlendCoeff,     kISA_GrBlendCoeff),
-    /* dst-in */     NO_DST_WRITE_FORMULA,
-    /* src-out */    COEFF_FORMULA(   kIDA_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* dst-out */    COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
-    /* src-atop */   COEFF_FORMULA(   kDA_GrBlendCoeff,     kISA_GrBlendCoeff),
-    /* dst-atop */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* xor */        COEFF_FORMULA(   kIDA_GrBlendCoeff,    kISA_GrBlendCoeff),
-    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* modulate */   COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
-    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
-
-                     }, /*>> No coverage, input color opaque <<*/ {
-
-    /* clear */      DST_CLEAR_FORMULA,
-    /* src */        COEFF_FORMULA(   kOne_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* dst */        NO_DST_WRITE_FORMULA,
-    /* src-over */   COEFF_FORMULA(   kOne_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* src-in */     COEFF_FORMULA(   kDA_GrBlendCoeff,     kZero_GrBlendCoeff),
-    /* dst-in */     NO_DST_WRITE_FORMULA,
-    /* src-out */    COEFF_FORMULA(   kIDA_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* dst-out */    DST_CLEAR_FORMULA,
-    /* src-atop */   COEFF_FORMULA(   kDA_GrBlendCoeff,     kZero_GrBlendCoeff),
-    /* dst-atop */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* xor */        COEFF_FORMULA(   kIDA_GrBlendCoeff,    kZero_GrBlendCoeff),
-    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* modulate */   COEFF_FORMULA(   kZero_GrBlendCoeff,   kSC_GrBlendCoeff),
-    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
-}}};
-
-static BlendFormula get_blend_formula(SkXfermode::Mode xfermode,
-                                      const GrProcOptInfo& colorPOI,
-                                      const GrProcOptInfo& coveragePOI) {
-    SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
-    SkASSERT(!coveragePOI.isFourChannelOutput());
-
-    return gBlendTable[colorPOI.isOpaque()][coveragePOI.isSolidWhite()][xfermode];
-}
-
-static BlendFormula get_unoptimized_blend_formula(SkXfermode::Mode xfermode) {
-    SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
-
-    return gBlendTable[0][0][xfermode];
+    return kOne_GrBlendCoeff == dstCoeff ||
+           kISA_GrBlendCoeff == dstCoeff ||
+           kISC_GrBlendCoeff == dstCoeff;
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
 class PorterDuffXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrDeviceCoordTexture* dstCopy,
+    static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+                                   GrColor constant, const GrDeviceCoordTexture* dstCopy,
                                    bool willReadDstColor) {
-        return SkNEW_ARGS(PorterDuffXferProcessor, (xfermode, dstCopy, willReadDstColor));
+        return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant, dstCopy,
+                                                    willReadDstColor));
     }
 
     ~PorterDuffXferProcessor() override;
@@ -318,16 +47,49 @@ public:
 
     GrGLXferProcessor* createGLInstance() const override;
 
-    bool hasSecondaryOutput() const override {
-        return fBlendFormula.hasSecondaryOutput();
-    }
+    bool hasSecondaryOutput() const override;
+
+    ///////////////////////////////////////////////////////////////////////////
+    /// @name Stage Output Types
+    ////
+
+    enum PrimaryOutputType {
+        kNone_PrimaryOutputType,
+        kColor_PrimaryOutputType,
+        kCoverage_PrimaryOutputType,
+        // Modulate color and coverage, write result as the color output.
+        kModulate_PrimaryOutputType,
+        // Custom Porter-Duff output, used for when we explictly are reading the dst and blending
+        // in the shader. Secondary Output must be none if you use this. The custom blend uses the
+        // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D
+        kCustom_PrimaryOutputType
+    };
+
+    enum SecondaryOutputType {
+        // There is no secondary output
+        kNone_SecondaryOutputType,
+        // Writes coverage as the secondary output. Only set if dual source blending is supported
+        // and primary output is kModulate.
+        kCoverage_SecondaryOutputType,
+        // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending
+        // is supported and primary output is kModulate.
+        kCoverageISA_SecondaryOutputType,
+        // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source
+        // blending is supported and primary output is kModulate.
+        kCoverageISC_SecondaryOutputType,
+
+        kSecondaryOutputTypeCnt,
+    };
 
-    SkXfermode::Mode getXfermode() const { return fXfermode; }
-    BlendFormula getBlendFormula() const { return fBlendFormula; }
+    PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
+    SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
+
+    GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
+    GrBlendCoeff getDstBlend() const { return fDstBlend; }
 
 private:
-    PorterDuffXferProcessor(SkXfermode::Mode, const GrDeviceCoordTexture* dstCopy,
-                            bool willReadDstColor);
+    PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
+                            const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
 
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
                                                  const GrProcOptInfo& coveragePOI,
@@ -339,69 +101,49 @@ private:
 
     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
         if (!this->willReadDstColor()) {
-            blendInfo->fEquation = fBlendFormula.fBlendEquation;
-            blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
-            blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
-            blendInfo->fWriteColor = fBlendFormula.modifiesDst();
+            blendInfo->fSrcBlend = fSrcBlend;
+            blendInfo->fDstBlend = fDstBlend;
+        } else {
+            blendInfo->fSrcBlend = kOne_GrBlendCoeff;
+            blendInfo->fDstBlend = kZero_GrBlendCoeff;
         }
+        blendInfo->fBlendConstant = fBlendConstant;
     }
 
     bool onIsEqual(const GrXferProcessor& xpBase) const override {
         const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
-        return fXfermode == xp.fXfermode &&
-               fBlendFormula == xp.fBlendFormula;
+        if (fSrcBlend != xp.fSrcBlend ||
+            fDstBlend != xp.fDstBlend ||
+            fBlendConstant != xp.fBlendConstant ||
+            fPrimaryOutputType != xp.fPrimaryOutputType || 
+            fSecondaryOutputType != xp.fSecondaryOutputType) {
+            return false;
+        }
+        return true;
     }
 
-    SkXfermode::Mode fXfermode;
-    BlendFormula     fBlendFormula;
+    GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
+                                                       const GrProcOptInfo& coveragePOI,
+                                                       bool doesStencilWrite);
+
+    void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrCaps& caps,
+                         bool hasSolidCoverage);
+
+    GrBlendCoeff fSrcBlend;
+    GrBlendCoeff fDstBlend;
+    GrColor      fBlendConstant;
+    PrimaryOutputType fPrimaryOutputType;
+    SecondaryOutputType fSecondaryOutputType;
 
     typedef GrXferProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
-                         BlendFormula::OutputType outputType, const char* output,
-                         const char* inColor, const char* inCoverage) {
-    switch (outputType) {
-        case BlendFormula::kNone_OutputType:
-            fsBuilder->codeAppendf("%s = vec4(0.0);", output);
-            break;
-        case BlendFormula::kCoverage_OutputType:
-            fsBuilder->codeAppendf("%s = %s;",
-                                   output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
-            break;
-        case BlendFormula::kModulate_OutputType:
-            if (xp.readsCoverage()) {
-                fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
-            } else {
-                fsBuilder->codeAppendf("%s = %s;", output, inColor);
-            }
-            break;
-        case BlendFormula::kISAModulate_OutputType:
-            if (xp.readsCoverage()) {
-                fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
-            } else {
-                fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
-            }
-            break;
-        case BlendFormula::kISCModulate_OutputType:
-            if (xp.readsCoverage()) {
-                fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
-            } else {
-                fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
-            }
-            break;
-        default:
-            SkFAIL("Unsupported output type.");
-            break;
-    }
-}
-
-bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
+bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff,
                             const char* colorName, const char* srcColorName,
                             const char* dstColorName, bool hasPrevious) {
-    if (SkXfermode::kZero_Coeff == coeff) {
+    if (kZero_GrBlendCoeff == coeff) {
         return hasPrevious;
     } else {
         if (hasPrevious) {
@@ -409,30 +151,30 @@ bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff
         }
         fsBuilder->codeAppendf("%s", colorName);
         switch (coeff) {
-            case SkXfermode::kOne_Coeff:
+            case kOne_GrBlendCoeff:
                 break;
-            case SkXfermode::kSC_Coeff:
+            case kSC_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * %s", srcColorName); 
                 break;
-            case SkXfermode::kISC_Coeff:
+            case kISC_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 
                 break;
-            case SkXfermode::kDC_Coeff:
+            case kDC_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * %s", dstColorName); 
                 break;
-            case SkXfermode::kIDC_Coeff:
+            case kIDC_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 
                 break;
-            case SkXfermode::kSA_Coeff:
+            case kSA_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * %s.a", srcColorName); 
                 break;
-            case SkXfermode::kISA_Coeff:
+            case kISA_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 
                 break;
-            case SkXfermode::kDA_Coeff:
+            case kDA_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * %s.a", dstColorName); 
                 break;
-            case SkXfermode::kIDA_Coeff:
+            case kIDA_GrBlendCoeff:
                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); 
                 break;
             default:
@@ -451,13 +193,11 @@ public:
     static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
                        GrProcessorKeyBuilder* b) {
         const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
+        b->add32(xp.primaryOutputType());
+        b->add32(xp.secondaryOutputType());
         if (xp.willReadDstColor()) {
-            b->add32(xp.getXfermode());  // Parent class includes willReadDstColor() in key.
-        } else {
-            b->add32(SkToInt(xp.readsCoverage()) |
-                     (xp.getBlendFormula().fPrimaryOutputType << 1) |
-                     (xp.getBlendFormula().fSecondaryOutputType << 4));
-            GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
+            b->add32(xp.getSrcBlend());
+            b->add32(xp.getDstBlend());
         }
     };
 
@@ -465,29 +205,58 @@ private:
     void onEmitCode(const EmitArgs& args) override {
         const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
         GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-        if (!xp.willReadDstColor()) {
-            BlendFormula blendFormula = xp.getBlendFormula();
-            if (blendFormula.hasSecondaryOutput()) {
-                append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
-                                    args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
+        if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) {
+            SkASSERT(!xp.willReadDstColor());
+            switch(xp.secondaryOutputType()) {
+                case PorterDuffXferProcessor::kNone_SecondaryOutputType:
+                    break;
+                case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
+                    fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary,
+                                           args.fInputCoverage);
+                    break;
+                case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
+                    fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
+                                           args.fOutputSecondary, args.fInputColor,
+                                           args.fInputCoverage);
+                    break;
+                case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
+                    fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
+                                           args.fOutputSecondary, args.fInputColor,
+                                           args.fInputCoverage);
+                    break;
+                default:
+                    SkFAIL("Unexpected Secondary Output");
+            }
+
+            switch (xp.primaryOutputType()) {
+                case PorterDuffXferProcessor::kNone_PrimaryOutputType:
+                    fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
+                    break;
+                case PorterDuffXferProcessor::kColor_PrimaryOutputType:
+                    fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
+                    break;
+                case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
+                    fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
+                    break;
+                case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
+                    fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
+                                           args.fInputCoverage);
+                    break;
+                default:
+                    SkFAIL("Unexpected Primary Output");
             }
-            append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
-                                args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
         } else {
             SkASSERT(xp.willReadDstColor());
 
-            SkXfermode::Coeff srcCoeff, dstCoeff;
-            SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
-
             const char* dstColor = fsBuilder->dstColor();
 
             fsBuilder->codeAppend("vec4 colorBlend =");
             // append src blend
-            bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
+            bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(),
                                                     args.fInputColor, args.fInputColor,
                                                     dstColor, false);
             // append dst blend
-            SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
+            SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(),
                                                   dstColor, args.fInputColor,
                                                   dstColor, didAppend));
             fsBuilder->codeAppend(";");
@@ -505,12 +274,17 @@ private:
 
 ///////////////////////////////////////////////////////////////////////////////
 
-PorterDuffXferProcessor::PorterDuffXferProcessor(SkXfermode::Mode xfermode,
+PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend,
+                                                 GrBlendCoeff dstBlend,
+                                                 GrColor constant,
                                                  const GrDeviceCoordTexture* dstCopy,
                                                  bool willReadDstColor)
     : INHERITED(dstCopy, willReadDstColor)
-    , fXfermode(xfermode)
-    , fBlendFormula(get_unoptimized_blend_formula(xfermode)) {
+    , fSrcBlend(srcBlend)
+    , fDstBlend(dstBlend)
+    , fBlendConstant(constant)
+    , fPrimaryOutputType(kModulate_PrimaryOutputType) 
+    , fSecondaryOutputType(kNone_SecondaryOutputType) {
     this->initClassID<PorterDuffXferProcessor>();
 }
 
@@ -532,40 +306,168 @@ PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
                                             bool doesStencilWrite,
                                             GrColor* overrideColor,
                                             const GrCaps& caps) {
+    GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI,
+                                                                        coveragePOI,
+                                                                        doesStencilWrite);
+    this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
+    return optFlags;
+}
+
+void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
+                                              const GrCaps& caps,
+                                              bool hasSolidCoverage) {
+    if (this->willReadDstColor()) {
+        fPrimaryOutputType = kCustom_PrimaryOutputType;
+        return;
+    }
+
+    if (optFlags & kIgnoreColor_OptFlag) {
+        if (optFlags & kIgnoreCoverage_OptFlag) {
+            fPrimaryOutputType = kNone_PrimaryOutputType;
+            return;
+        } else {
+            fPrimaryOutputType = kCoverage_PrimaryOutputType;
+            return;
+        }
+    } else if (optFlags & kIgnoreCoverage_OptFlag) {
+        fPrimaryOutputType = kColor_PrimaryOutputType;
+        return;
+    }
+
+    // If we do have coverage determine whether it matters.  Dual source blending is expensive so
+    // we don't do it if we are doing coverage drawing.  If we aren't then We always do dual source
+    // blending if we have any effective coverage stages OR the geometry processor doesn't emits
+    // solid coverage.
+    if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
+        if (caps.shaderCaps()->dualSourceBlendingSupport()) {
+            if (kZero_GrBlendCoeff == fDstBlend) {
+                // write the coverage value to second color
+                fSecondaryOutputType = kCoverage_SecondaryOutputType;
+                fDstBlend = kIS2C_GrBlendCoeff;
+            } else if (kSA_GrBlendCoeff == fDstBlend) {
+                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
+                fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
+                fDstBlend = kIS2C_GrBlendCoeff;
+            } else if (kSC_GrBlendCoeff == fDstBlend) {
+                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
+                fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
+                fDstBlend = kIS2C_GrBlendCoeff;
+            }
+        }
+    }
+}
+
+GrXferProcessor::OptFlags
+PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
+                                                  const GrProcOptInfo& coveragePOI,
+                                                  bool doesStencilWrite) {
     if (this->willReadDstColor()) {
         return GrXferProcessor::kNone_Opt;
     }
 
-    fBlendFormula = get_blend_formula(fXfermode, colorPOI, coveragePOI);
+    bool srcAIsOne = colorPOI.isOpaque();
+    bool hasCoverage = !coveragePOI.isSolidWhite();
+
+    bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
+                         (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
+    bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
+                         (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
+
+    // When coeffs are (0,1) there is no reason to draw at all, unless
+    // stenciling is enabled. Having color writes disabled is effectively
+    // (0,1).
+    if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
+        if (doesStencilWrite) {
+            return GrXferProcessor::kIgnoreColor_OptFlag |
+                   GrXferProcessor::kSetCoverageDrawing_OptFlag;
+        } else {
+            fDstBlend = kOne_GrBlendCoeff;
+            return GrXferProcessor::kSkipDraw_OptFlag;
+        }
+    }
 
-    GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
-    if (!fBlendFormula.modifiesDst()) {
-        if (!doesStencilWrite) {
-            optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
+    // if we don't have coverage we can check whether the dst
+    // has to read at all. If not, we'll disable blending.
+    if (!hasCoverage) {
+        if (dstCoeffIsZero) {
+            if (kOne_GrBlendCoeff == fSrcBlend) {
+                // if there is no coverage and coeffs are (1,0) then we
+                // won't need to read the dst at all, it gets replaced by src
+                fDstBlend = kZero_GrBlendCoeff;
+                return GrXferProcessor::kNone_Opt |
+                       GrXferProcessor::kIgnoreCoverage_OptFlag;
+            } else if (kZero_GrBlendCoeff == fSrcBlend) {
+                // if the op is "clear" then we don't need to emit a color
+                // or blend, just write transparent black into the dst.
+                fSrcBlend = kOne_GrBlendCoeff;
+                fDstBlend = kZero_GrBlendCoeff;
+                return GrXferProcessor::kIgnoreColor_OptFlag |
+                       GrXferProcessor::kIgnoreCoverage_OptFlag;
+            }
         }
-        optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
-                     GrXferProcessor::kIgnoreCoverage_OptFlag |
-                     GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
-    } else {
-        if (!fBlendFormula.usesInputColor()) {
-            optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
+        return GrXferProcessor::kIgnoreCoverage_OptFlag;
+    }
+
+    // check whether coverage can be safely rolled into alpha
+    // of if we can skip color computation and just emit coverage
+    if (can_tweak_alpha_for_coverage(fDstBlend)) {
+        if (colorPOI.allStagesMultiplyInput()) {
+            return GrXferProcessor::kSetCoverageDrawing_OptFlag |
+                GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
+        } else {
+            return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+
         }
-        if (coveragePOI.isSolidWhite()) {
-            optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
+    }
+    if (dstCoeffIsZero) {
+        if (kZero_GrBlendCoeff == fSrcBlend) {
+            // the source color is not included in the blend
+            // the dst coeff is effectively zero so blend works out to:
+            // (c)(0)D + (1-c)D = (1-c)D.
+            fDstBlend = kISA_GrBlendCoeff;
+            return GrXferProcessor::kIgnoreColor_OptFlag |
+                GrXferProcessor::kSetCoverageDrawing_OptFlag;
+        } else if (srcAIsOne) {
+            // the dst coeff is effectively zero so blend works out to:
+            // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
+            // If Sa is 1 then we can replace Sa with c
+            // and set dst coeff to 1-Sa.
+            fDstBlend = kISA_GrBlendCoeff;
+            if (colorPOI.allStagesMultiplyInput()) {
+                return GrXferProcessor::kSetCoverageDrawing_OptFlag |
+                    GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
+            } else {
+                return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+
+            }
         }
-        if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
-            optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
+    } else if (dstCoeffIsOne) {
+        // the dst coeff is effectively one so blend works out to:
+        // cS + (c)(1)D + (1-c)D = cS + D.
+        fDstBlend = kOne_GrBlendCoeff;
+        if (colorPOI.allStagesMultiplyInput()) {
+            return GrXferProcessor::kSetCoverageDrawing_OptFlag |
+                GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
+        } else {
+            return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+
         }
+        return GrXferProcessor::kSetCoverageDrawing_OptFlag;
     }
 
-    return optFlags;
+    return GrXferProcessor::kNone_Opt;
+}
+
+bool PorterDuffXferProcessor::hasSecondaryOutput() const {
+    return kNone_SecondaryOutputType != fSecondaryOutputType;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 class PDLCDXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
+    static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+                                   const GrProcOptInfo& colorPOI);
 
     ~PDLCDXferProcessor() override;
 
@@ -639,9 +541,9 @@ PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
     this->initClassID<PDLCDXferProcessor>();
 }
 
-GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
+GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
                                             const GrProcOptInfo& colorPOI) {
-    if (SkXfermode::kSrcOver_Mode != xfermode) {
+    if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) {
         return NULL;
     }
 
@@ -683,40 +585,91 @@ PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-
-GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
-    : fXfermode(xfermode) {
+GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
+    : fSrcCoeff(src), fDstCoeff(dst) {
     this->initClassID<GrPorterDuffXPFactory>();
 }
 
-GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
-    static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
-    static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
-    static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
-    static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
-    static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
-    static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
-    static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
-    static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
-    static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
-    static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
-    static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
-    static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
-    static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
-    static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
-    static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
-
-    static GrPorterDuffXPFactory* gFactories[] = {
-        &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
-        &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
-        &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
-    };
-    GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
-
-    if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
-        return NULL;
+GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
+    switch (mode) {
+        case SkXfermode::kClear_Mode: {
+            static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
+            return SkRef(&gClearPDXPF);
+            break;
+        }
+        case SkXfermode::kSrc_Mode: {
+            static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
+            return SkRef(&gSrcPDXPF);
+            break;
+        }
+        case SkXfermode::kDst_Mode: {
+            static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
+            return SkRef(&gDstPDXPF);
+            break;
+        }
+        case SkXfermode::kSrcOver_Mode: {
+            static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
+            return SkRef(&gSrcOverPDXPF);
+            break;
+        }
+        case SkXfermode::kDstOver_Mode: {
+            static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
+            return SkRef(&gDstOverPDXPF);
+            break;
+        }
+        case SkXfermode::kSrcIn_Mode: {
+            static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
+            return SkRef(&gSrcInPDXPF);
+            break;
+        }
+        case SkXfermode::kDstIn_Mode: {
+            static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
+            return SkRef(&gDstInPDXPF);
+            break;
+        }
+        case SkXfermode::kSrcOut_Mode: {
+            static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
+            return SkRef(&gSrcOutPDXPF);
+            break;
+        }
+        case SkXfermode::kDstOut_Mode: {
+            static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
+            return SkRef(&gDstOutPDXPF);
+            break;
+        }
+        case SkXfermode::kSrcATop_Mode: {
+            static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
+            return SkRef(&gSrcATopPDXPF);
+            break;
+        }
+        case SkXfermode::kDstATop_Mode: {
+            static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
+            return SkRef(&gDstATopPDXPF);
+            break;
+        }
+        case SkXfermode::kXor_Mode: {
+            static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
+            return SkRef(&gXorPDXPF);
+            break;
+        }
+        case SkXfermode::kPlus_Mode: {
+            static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
+            return SkRef(&gPlusPDXPF);
+            break;
+        }
+        case SkXfermode::kModulate_Mode: {
+            static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
+            return SkRef(&gModulatePDXPF);
+            break;
+        }
+        case SkXfermode::kScreen_Mode: {
+            static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
+            return SkRef(&gScreenPDXPF);
+            break;
+        }
+        default:
+            return NULL;
     }
-    return SkRef(gFactories[xfermode]);
 }
 
 GrXferProcessor*
@@ -725,16 +678,16 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                              const GrProcOptInfo& covPOI,
                                              const GrDeviceCoordTexture* dstCopy) const {
     if (covPOI.isFourChannelOutput()) {
-        return PDLCDXferProcessor::Create(fXfermode, colorPOI);
+        return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI);
     } else {
-        return PorterDuffXferProcessor::Create(fXfermode, dstCopy,
+        return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
                                                this->willReadDstColor(caps, colorPOI, covPOI));
     }
 }
 
 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
                                                 uint32_t knownColorFlags) const {
-    if (SkXfermode::kSrcOver_Mode == fXfermode &&
+    if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
         kRGBA_GrColorComponentFlags == knownColorFlags) {
         return true;
     }
@@ -744,43 +697,103 @@ bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
                                                const GrProcOptInfo& coveragePOI,
                                                GrXPFactory::InvariantOutput* output) const {
-    const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, coveragePOI);
-
-    if (blendFormula.usesDstColor()) {
+    if (!coveragePOI.isSolidWhite()) {
         output->fWillBlendWithDst = true;
-        output->fBlendedColorFlags = kNone_GrColorComponentFlags;
+        output->fBlendedColorFlags = 0;
         return;
     }
 
-    SkASSERT(coveragePOI.isSolidWhite());
-    SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
+    GrBlendCoeff srcCoeff = fSrcCoeff;
+    GrBlendCoeff dstCoeff = fDstCoeff;
 
-    output->fWillBlendWithDst = false;
+    // TODO: figure out to merge this simplify with other current optimization code paths and
+    // eventually remove from GrBlend
+    GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
+                    0, 0, 0);
+
+    if (GrBlendCoeffRefsDst(srcCoeff)) {
+        output->fWillBlendWithDst = true;
+        output->fBlendedColorFlags = 0;
+        return;
+    }
+
+    if (kZero_GrBlendCoeff != dstCoeff) {
+        bool srcAIsOne = colorPOI.isOpaque();
+        if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
+            output->fWillBlendWithDst = true;
+        }
+        output->fBlendedColorFlags = 0;
+        return;
+    }
 
-    switch (blendFormula.fSrcCoeff) {
+    switch (srcCoeff) {
         case kZero_GrBlendCoeff:
             output->fBlendedColor = 0;
             output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
-            return;
+            break;
 
         case kOne_GrBlendCoeff:
             output->fBlendedColor = colorPOI.color();
             output->fBlendedColorFlags = colorPOI.validFlags();
-            return;
+            break;
 
-        // TODO: update if we ever use const color.
+            // The src coeff should never refer to the src and if it refers to dst then opaque
+            // should have been false.
+        case kSC_GrBlendCoeff:
+        case kISC_GrBlendCoeff:
+        case kDC_GrBlendCoeff:
+        case kIDC_GrBlendCoeff:
+        case kSA_GrBlendCoeff:
+        case kISA_GrBlendCoeff:
+        case kDA_GrBlendCoeff:
+        case kIDA_GrBlendCoeff:
         default:
-            output->fBlendedColorFlags = kNone_GrColorComponentFlags;
-            return;
+            SkFAIL("srcCoeff should not refer to src or dst.");
+            break;
+
+            // TODO: update this once GrPaint actually has a const color.
+        case kConstC_GrBlendCoeff:
+        case kIConstC_GrBlendCoeff:
+        case kConstA_GrBlendCoeff:
+        case kIConstA_GrBlendCoeff:
+            output->fBlendedColorFlags = 0;
+            break;
     }
+
+    output->fWillBlendWithDst = false;
 }
 
 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& coveragePOI) const {
-    // Some formulas use dual source blending, so we fall back if it is required but not supported.
-    return !caps.shaderCaps()->dualSourceBlendingSupport() &&
-           get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
+    // We can always blend correctly if we have dual source blending.
+    if (caps.shaderCaps()->dualSourceBlendingSupport()) {
+        return false;
+    }
+
+    if (can_tweak_alpha_for_coverage(fDstCoeff)) {
+        return false;
+    }
+
+    bool srcAIsOne = colorPOI.isOpaque();
+
+    if (kZero_GrBlendCoeff == fDstCoeff) {
+        if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
+            return false;
+        }
+    }
+
+    // Reduces to: coeffS * (Cov*S) + D
+    if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
+        return false;
+    }
+
+    // We can always blend correctly if we have solid coverage.
+    if (coveragePOI.isSolidWhite()) {
+        return false;
+    }
+
+    return true;
 }
 
 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
@@ -793,15 +806,3 @@ GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
     return GrPorterDuffXPFactory::Create(mode);
 }
 
-void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
-                                                 int* outPrimary,
-                                                 int* outSecondary) {
-    if (!!strcmp(xp->name(), "Porter Duff")) {
-        *outPrimary = *outSecondary = -1;
-        return;
-    }
-    BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
-    *outPrimary = blendFormula.fPrimaryOutputType;
-    *outSecondary = blendFormula.fSecondaryOutputType;
-}
-
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
deleted file mode 100644 (file)
index 79cee71..0000000
+++ /dev/null
@@ -1,1280 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkXfermode.h"
-#include "Test.h"
-
-#if SK_SUPPORT_GPU
-
-#include "GrContextFactory.h"
-#include "GrGpu.h"
-#include "GrXferProcessor.h"
-#include "effects/GrPorterDuffXferProcessor.h"
-
-////////////////////////////////////////////////////////////////////////////////
-
-static void test_alpha_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-static void test_alpha_unknown_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-static void test_alpha_opaque_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-static void test_alpha_opaque_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-static void test_color_white_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-static void test_color_white_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
-
-DEF_GPUTEST(GrPorterDuff, reporter, factory) {
-    GrContext* ctx = factory->get(GrContextFactory::kNull_GLContextType);
-    if (!ctx) {
-        SkFAIL("Failed to create null context.");
-        return;
-    }
-
-    const GrCaps& caps = *ctx->getGpu()->caps();
-    if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
-        SkFAIL("Null context does not support dual source blending.");
-        return;
-    }
-
-    test_alpha_unknown_with_coverage(reporter, caps);
-    test_alpha_unknown_no_coverage(reporter, caps);
-    test_alpha_opaque_with_coverage(reporter, caps);
-    test_alpha_opaque_no_coverage(reporter, caps);
-    test_color_white_with_coverage(reporter, caps);
-    test_color_white_with_coverage(reporter, caps);
-    test_color_white_no_coverage(reporter, caps);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-#define TEST_ASSERT(...) REPORTER_ASSERT(reporter, __VA_ARGS__)
-
-enum {
-    kNone_OutputType,
-    kCoverage_OutputType,
-    kModulate_OutputType,
-    kISAModulate_OutputType,
-    kISCModulate_OutputType
-};
-
-enum {
-    kNone_Opt                         = GrXferProcessor::kNone_Opt,
-    kSkipDraw_OptFlag                 = GrXferProcessor::kSkipDraw_OptFlag,
-    kIgnoreColor_OptFlag              = GrXferProcessor::kIgnoreColor_OptFlag,
-    kIgnoreCoverage_OptFlag           = GrXferProcessor::kIgnoreCoverage_OptFlag,
-    kCanTweakAlphaForCoverage_OptFlag = GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag
-};
-
-class GrPorterDuffTest {
-public:
-    struct XPInfo {
-        XPInfo(skiatest::Reporter* reporter, SkXfermode::Mode xfermode, const GrCaps& caps,
-               const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI) {
-            SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
-            SkAutoTUnref<GrXferProcessor> xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps));
-            TEST_ASSERT(!xpf->willNeedDstCopy(caps, colorPOI, covPOI));
-            xpf->getInvariantOutput(colorPOI, covPOI, &fInvariantOutput);
-            fOptFlags = xp->getOptimizations(colorPOI, covPOI, false, 0, caps);
-            GetXPOutputTypes(xp, &fPrimaryOutputType, &fSecondaryOutputType);
-            xp->getBlendInfo(&fBlendInfo);
-        }
-
-        GrXPFactory::InvariantOutput fInvariantOutput;
-        int fOptFlags;
-        int fPrimaryOutputType;
-        int fSecondaryOutputType;
-        GrXferProcessor::BlendInfo fBlendInfo;
-    };
-
-    static void GetXPOutputTypes(const GrXferProcessor* xp, int* outPrimary, int* outSecondary) {
-        GrPorterDuffXPFactory::TestGetXPOutputTypes(xp, outPrimary, outSecondary);
-    }
-};
-
-static void test_alpha_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false);
-    covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, true);
-
-    SkASSERT(!colorPOI.isOpaque());
-    SkASSERT(!colorPOI.isSolidWhite());
-    SkASSERT(!covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kISAModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kISAModulate_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-static void test_alpha_unknown_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, GrColorPackRGBA(229, 0, 154, 0),
-                                   kR_GrColorComponentFlag | kB_GrColorComponentFlag, false);
-    covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, true);
-
-    SkASSERT(!colorPOI.isOpaque());
-    SkASSERT(!colorPOI.isSolidWhite());
-    SkASSERT(covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(229 == GrColorUnpackR(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT(154 == GrColorUnpackB(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT((kR_GrColorComponentFlag |
-                             kB_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kSA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kSA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kSC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-static void test_alpha_opaque_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kA_GrColorComponentFlag, false);
-    covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, true);
-
-    SkASSERT(colorPOI.isOpaque());
-    SkASSERT(!colorPOI.isSolidWhite());
-    SkASSERT(!covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-static void test_alpha_opaque_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, GrColorPackRGBA(0, 82, 0, 255),
-                                   kG_GrColorComponentFlag | kA_GrColorComponentFlag, false);
-    covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, true);
-
-    SkASSERT(colorPOI.isOpaque());
-    SkASSERT(!colorPOI.isSolidWhite());
-    SkASSERT(covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(82 == GrColorUnpackG(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT(255 == GrColorUnpackA(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT((kG_GrColorComponentFlag |
-                             kA_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(82 == GrColorUnpackG(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT(255 == GrColorUnpackA(xpi.fInvariantOutput.fBlendedColor));
-                TEST_ASSERT((kG_GrColorComponentFlag |
-                             kA_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kSC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-static void test_color_white_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, false);
-    covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, true);
-
-    SkASSERT(colorPOI.isOpaque());
-    SkASSERT(colorPOI.isSolidWhite());
-    SkASSERT(!covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kNone_Opt) == xpi.fOptFlags);
-                TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-static void test_color_white_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
-    GrProcOptInfo colorPOI, covPOI;
-    colorPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, false);
-    covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, true);
-
-    SkASSERT(colorPOI.isOpaque());
-    SkASSERT(colorPOI.isSolidWhite());
-    SkASSERT(covPOI.isSolidWhite());
-
-    for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
-        SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
-        const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
-
-        switch (xfermode) {
-            case SkXfermode::kClear_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrc_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(GrColorPackA4(255) == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDst_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOver_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(GrColorPackA4(255) == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOver_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstIn_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kSkipDraw_OptFlag |
-                             kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcOut_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstOut_Mode:
-                TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
-                TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreColor_OptFlag |
-                             kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kSrcATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kDstATop_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kXor_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kPlus_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kModulate_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kSC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            case SkXfermode::kScreen_Mode:
-                TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
-                TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
-                TEST_ASSERT((kIgnoreCoverage_OptFlag |
-                             kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
-                TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
-                TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
-                TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
-                TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
-                TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
-                TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
-                break;
-            default:
-                ERRORF(reporter, "Invalid xfermode.");
-                break;
-        }
-    }
-}
-
-#endif
-