constexprify GrBlend.h and GrPorterDuffXferProcessor.cpp

Also remove some unused functions from GrBlend.h and related unit test.

Bug: skia:
Change-Id: Id8ad0057a02f65a9e19dc75e4b88709a762f4139
Reviewed-on: https://skia-review.googlesource.com/12623
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/gn/tests.gni b/gn/tests.gni
index 196c86d..be99a9e 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -89,7 +89,6 @@
   "$_tests/GrContextAbandonTest.cpp",
   "$_tests/GrContextFactoryTest.cpp",
   "$_tests/GrDrawTargetTest.cpp",
-  "$_tests/GrGetCoeffBlendKnownComponentsTest.cpp",
   "$_tests/GrGLSLPrettyPrintTest.cpp",
   "$_tests/GrMemoryPoolTest.cpp",
   "$_tests/GrPorterDuffTest.cpp",
diff --git a/include/gpu/GrBlend.h b/include/gpu/GrBlend.h
index 97a5166..30b0b9b 100644
--- a/include/gpu/GrBlend.h
+++ b/include/gpu/GrBlend.h
@@ -73,121 +73,38 @@
 
 static const int kGrBlendCoeffCnt = kLast_GrBlendCoeff + 1;
 
-/**
- * Given a known blend equation in the form of srcCoeff * srcColor + dstCoeff * dstColor where
- * there may be partial knowledge of the srcColor and dstColor component values, determine what
- * components of the blended output color are known. Coeffs must not refer to the constant or
- * secondary src color.
- */
-void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
-                                    GrColor srcColor,
-                                    GrColorComponentFlags srcColorFlags,
-                                    GrColor dstColor,
-                                    GrColorComponentFlags dstColorFlags,
-                                    GrColor* outColor,
-                                    GrColorComponentFlags* outFlags);
-
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsSrc : skstd::bool_constant<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) {
-    switch (coeff) {
-        case kSC_GrBlendCoeff:
-        case kISC_GrBlendCoeff:
-        case kSA_GrBlendCoeff:
-        case kISA_GrBlendCoeff:
-            return true;
-        default:
-            return false;
-    }
+static constexpr bool GrBlendCoeffRefsSrc(const GrBlendCoeff coeff) {
+    return kSC_GrBlendCoeff == coeff || kISC_GrBlendCoeff == coeff || kSA_GrBlendCoeff == coeff ||
+           kISA_GrBlendCoeff == coeff;
 }
 
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsDst : skstd::bool_constant<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) {
-    switch (coeff) {
-        case kDC_GrBlendCoeff:
-        case kIDC_GrBlendCoeff:
-        case kDA_GrBlendCoeff:
-        case kIDA_GrBlendCoeff:
-            return true;
-        default:
-            return false;
-    }
+static constexpr bool GrBlendCoeffRefsDst(const GrBlendCoeff coeff) {
+    return kDC_GrBlendCoeff == coeff || kIDC_GrBlendCoeff == coeff || kDA_GrBlendCoeff == coeff ||
+           kIDA_GrBlendCoeff == coeff;
 }
 
-
-template<GrBlendCoeff Coeff>
-struct GrTBlendCoeffRefsSrc2 : skstd::bool_constant<kS2C_GrBlendCoeff == Coeff ||
-                                                    kIS2C_GrBlendCoeff == Coeff ||
-                                                    kS2A_GrBlendCoeff == Coeff ||
-                                                    kIS2A_GrBlendCoeff == Coeff> {};
-
-#define GR_BLEND_COEFF_REFS_SRC2(COEFF) \
-    GrTBlendCoeffRefsSrc2<COEFF>::value
-
-inline bool GrBlendCoeffRefsSrc2(GrBlendCoeff coeff) {
-    switch (coeff) {
-        case kS2C_GrBlendCoeff:
-        case kIS2C_GrBlendCoeff:
-        case kS2A_GrBlendCoeff:
-        case kIS2A_GrBlendCoeff:
-            return true;
-        default:
-            return false;
-    }
+static constexpr bool GrBlendCoeffRefsSrc2(const GrBlendCoeff coeff) {
+    return kS2C_GrBlendCoeff == coeff || kIS2C_GrBlendCoeff == coeff ||
+           kS2A_GrBlendCoeff == coeff || kIS2A_GrBlendCoeff == coeff;
 }
 
+static constexpr bool GrBlendCoeffsUseSrcColor(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+    return kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff);
+}
 
-template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendCoeffsUseSrcColor : skstd::bool_constant<kZero_GrBlendCoeff != SrcCoeff ||
-                                                        GR_BLEND_COEFF_REFS_SRC(DstCoeff)> {};
+static constexpr bool GrBlendCoeffsUseDstColor(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+    return GrBlendCoeffRefsDst(srcCoeff) || kZero_GrBlendCoeff != 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 : skstd::bool_constant<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 : skstd::bool_constant<Equation >= kFirstAdvancedGrBlendEquation> {};
-
-#define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \
-    GrTBlendEquationIsAdvanced<EQUATION>::value
-
-inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
+static constexpr bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
     return equation >= kFirstAdvancedGrBlendEquation;
 }
 
-
-template<GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendModifiesDst : skstd::bool_constant<
-    (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
-
+static constexpr bool GrBlendModifiesDst(GrBlendEquation equation, GrBlendCoeff srcCoeff,
+                                         GrBlendCoeff dstCoeff) {
+    return (kAdd_GrBlendEquation != equation && kReverseSubtract_GrBlendEquation != equation) ||
+           kZero_GrBlendCoeff != srcCoeff || kOne_GrBlendCoeff != dstCoeff;
+}
 
 /**
  * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
@@ -216,17 +133,15 @@
  * Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src
  * color so folding in coverage is allowed.
  */
-template<GrBlendEquation Equation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-struct GrTBlendCanTweakAlphaForCoverage : skstd::bool_constant<
-    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)) ||
-    !GrTBlendModifiesDst<Equation, SrcCoeff, DstCoeff>::value> {};
-
-#define GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(EQUATION, SRC_COEFF, DST_COEFF) \
-    GrTBlendCanTweakAlphaForCoverage<EQUATION, SRC_COEFF, DST_COEFF>::value
+static constexpr bool GrBlendAllowsCoverageAsAlpha(GrBlendEquation equation,
+                                                   GrBlendCoeff srcCoeff,
+                                                   GrBlendCoeff dstCoeff) {
+    return GrBlendEquationIsAdvanced(equation) ||
+           !GrBlendModifiesDst(equation, srcCoeff, dstCoeff) ||
+           ((kAdd_GrBlendEquation == equation || kReverseSubtract_GrBlendEquation == equation) &&
+            !GrBlendCoeffRefsSrc(srcCoeff) &&
+            (kOne_GrBlendCoeff == dstCoeff || kISC_GrBlendCoeff == dstCoeff ||
+             kISA_GrBlendCoeff == dstCoeff));
+}
 
 #endif
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index b4d917a..e3548ad 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -23,7 +23,7 @@
 /**
  * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
  */
-struct BlendFormula {
+class BlendFormula {
 public:
     /**
      * Values the shader can write to primary and secondary outputs. These must all be modulated by
@@ -40,6 +40,76 @@
         kLast_OutputType = kISCModulate_OutputType
     };
 
+    BlendFormula() = default;
+
+    constexpr BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation,
+                           GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff)
+            : fPrimaryOutputType(primaryOut)
+            , fSecondaryOutputType(secondaryOut)
+            , fBlendEquation(equation)
+            , fSrcCoeff(srcCoeff)
+            , fDstCoeff(dstCoeff)
+            , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {}
+
+    BlendFormula& operator=(const BlendFormula& other) {
+        SkDEBUGCODE(other.validatePreoptimized());
+        fData = other.fData;
+        return *this;
+    }
+
+    bool operator==(const BlendFormula& other) const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        SkDEBUGCODE(other.validatePreoptimized());
+        return fData == other.fData;
+    }
+
+    bool hasSecondaryOutput() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return kNone_OutputType != fSecondaryOutputType;
+    }
+    bool modifiesDst() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return SkToBool(fProps & kModifiesDst_Property);
+    }
+    bool usesDstColor() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return SkToBool(fProps & kUsesDstColor_Property);
+    }
+    bool usesInputColor() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return SkToBool(fProps & kUsesInputColor_Property);
+    }
+    bool canTweakAlphaForCoverage() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
+    }
+
+    GrBlendEquation equation() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return fBlendEquation;
+    }
+
+    GrBlendCoeff srcCoeff() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return fSrcCoeff;
+    }
+
+    GrBlendCoeff dstCoeff() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return fDstCoeff;
+    }
+
+    OutputType primaryOutput() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return fPrimaryOutputType;
+    }
+
+    OutputType secondaryOutput() const {
+        SkDEBUGCODE(this->validatePreoptimized());
+        return fSecondaryOutputType;
+    }
+
+private:
     enum Properties {
         kModifiesDst_Property              = 1,
         kUsesDstColor_Property             = 1 << 1,
@@ -48,55 +118,30 @@
 
         kLast_Property = kCanTweakAlphaForCoverage_Property
     };
+    GR_DECL_BITFIELD_OPS_FRIENDS(Properties)
 
-    BlendFormula& operator =(const BlendFormula& other) {
-        fData = other.fData;
-        return *this;
+#ifdef SK_DEBUG
+    void validatePreoptimized() const {
+        // The provided formula should already be optimized before a BlendFormula is constructed.
+        // Preferably these asserts would be done statically in the constexpr constructor, but this
+        // is not allowed in C++11.
+        SkASSERT((kNone_OutputType == fPrimaryOutputType) ==
+                 !GrBlendCoeffsUseSrcColor(fSrcCoeff, fDstCoeff));
+        SkASSERT(!GrBlendCoeffRefsSrc2(fSrcCoeff));
+        SkASSERT((kNone_OutputType == fSecondaryOutputType) == !GrBlendCoeffRefsSrc2(fDstCoeff));
+        SkASSERT(fPrimaryOutputType != fSecondaryOutputType ||
+                 kNone_OutputType == fPrimaryOutputType);
+        SkASSERT(kNone_OutputType != fPrimaryOutputType ||
+                 kNone_OutputType == fSecondaryOutputType);
     }
-
-    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);
-    }
+#endif
 
     /**
-     * Deduce the properties of a compile-time constant BlendFormula.
+     * Deduce the properties of a BlendFormula.
      */
-    template<OutputType PrimaryOut, OutputType SecondaryOut,
-             GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
-    struct get_properties : std::integral_constant<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 == 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);
-    };
+    static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut,
+                                              GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff,
+                                              GrBlendCoeff DstCoeff);
 
     union {
         struct {
@@ -122,51 +167,48 @@
 
 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}}}
+constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut,
+                                                               OutputType SecondaryOut,
+                                                               GrBlendEquation BlendEquation,
+                                                               GrBlendCoeff SrcCoeff,
+                                                               GrBlendCoeff DstCoeff) {
+    return static_cast<Properties>(
+            (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) |
+            (GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff) ? kUsesDstColor_Property : 0) |
+            ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) ||
+                             (SecondaryOut >= kModulate_OutputType &&
+                              GrBlendCoeffRefsSrc2(DstCoeff))
+                     ? kUsesInputColor_Property
+                     : 0) |  // We assert later that SrcCoeff doesn't ref src2.
+            ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
+                             kNone_OutputType == SecondaryOut &&
+                             GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff)
+                     ? kCanTweakAlphaForCoverage_Property
+                     : 0));
+}
 
 /**
  * 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)
+static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+    // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none.
+    return (kZero_GrBlendCoeff == srcCoeff &&
+            (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff))
+           ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType,
+                          kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff)
+           : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType,
+                        kAdd_GrBlendEquation, srcCoeff, dstCoeff);
+}
 
 /**
- * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
+ * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in
  * LCD dst-out.
  */
-#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
-    INIT_BLEND_FORMULA(BlendFormula::kSAModulate_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)
+static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+    return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType,
+                        kAdd_GrBlendEquation, srcCoeff, dstCoeff);
+}
 
 /**
  * When there is coverage, the equation with f=coverage is:
@@ -182,10 +224,11 @@
  *
  * 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)
+static constexpr BlendFormula MakeCoverageFormula(
+        BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) {
+    return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput,
+                        kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff);
+}
 
 /**
  * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
@@ -201,10 +244,11 @@
  *
  * 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)
+static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula(
+        BlendFormula::OutputType oneMinusDstCoeffModulateOutput) {
+    return BlendFormula(oneMinusDstCoeffModulateOutput, 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:
@@ -216,109 +260,119 @@
  *
  * 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)
+static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) {
+    return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType,
+                        kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff);
+}
+
+// Older GCC won't like the constexpr arrays because of
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61484.
+// MSVC crashes with an internal compiler error.
+#if !defined(__clang__) && ((defined(__GNUC__) && __GNUC__ < 5) || defined(_MSC_VER))
+#   define MAYBE_CONSTEXPR const
+#else
+#   define MAYBE_CONSTEXPR constexpr
+#endif
 
 /**
  * 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][(int)SkBlendMode::kLastCoeffMode + 1] = {
-
+static MAYBE_CONSTEXPR BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
                      /*>> 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),
+    /* clear */      MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
+    /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
+    /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff),
+    /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
+    /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
+    /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kSA_GrBlendCoeff),
+    /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* modulate */   MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
+    /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
 
                      }, /*>> 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),
+    /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
+    /* src */        MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff),
+    /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* src-in */     MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff),
+    /* dst-in */     MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
+    /* src-out */    MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff),
+    /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
+    /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
+    /* dst-atop */   MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
+    /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
+    /* screen */     MakeCoeffFormula(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),
+    /* clear */      MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
+    /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
+    /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
+    /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
+    /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
+    /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* modulate */   MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
+    /* screen */     MakeCoeffFormula(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),
+    /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
+    /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
+    /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* dst-out */    MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
+    /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
+    /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
+    /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
+    /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
+    /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
 }}};
 
-static const BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
-    /* clear */      COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
-    /* src */        COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
-    /* dst */        NO_DST_WRITE_FORMULA,
-    /* src-over */   COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
-    /* dst-over */   COEFF_FORMULA(   kIDA_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* src-in */     COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
-    /* dst-in */     COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
-    /* src-out */    COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
-    /* dst-out */    COEFF_FORMULA_SA_MODULATE(   kZero_GrBlendCoeff,   kISC_GrBlendCoeff),
-    /* src-atop */   COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
-    /* dst-atop */   COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
-    /* xor */        COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
-    /* plus */       COEFF_FORMULA(   kOne_GrBlendCoeff,    kOne_GrBlendCoeff),
-    /* modulate */   COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
-    /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
+static MAYBE_CONSTEXPR BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
+    /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
+    /* src */        MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
+    /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-over */   MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
+    /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* src-in */     MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
+    /* dst-in */     MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
+    /* src-out */    MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
+    /* dst-out */    MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff),
+    /* src-atop */   MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
+    /* dst-atop */   MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
+    /* xor */        MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
+    /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
+    /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
+    /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
 };
 
+#undef MAYBE_CONSTEXPR
+
 static BlendFormula get_blend_formula(bool isOpaque,
                                       bool hasCoverage,
                                       bool hasMixedSamples,
@@ -354,9 +408,9 @@
     bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
 
     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
-        blendInfo->fEquation = fBlendFormula.fBlendEquation;
-        blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
-        blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
+        blendInfo->fEquation = fBlendFormula.equation();
+        blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
+        blendInfo->fDstBlend = fBlendFormula.dstCoeff();
         blendInfo->fWriteColor = fBlendFormula.modifiesDst();
     }
 
@@ -408,8 +462,8 @@
 public:
     static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
         const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
-        b->add32(xp.getBlendFormula().fPrimaryOutputType |
-                 (xp.getBlendFormula().fSecondaryOutputType << 3));
+        b->add32(xp.getBlendFormula().primaryOutput() |
+                 (xp.getBlendFormula().secondaryOutput() << 3));
         GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
     }
 
@@ -420,11 +474,11 @@
 
         BlendFormula blendFormula = xp.getBlendFormula();
         if (blendFormula.hasSecondaryOutput()) {
-            append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType,
+            append_color_output(xp, fragBuilder, blendFormula.secondaryOutput(),
                                 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
         }
-        append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType,
-                            args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
+        append_color_output(xp, fragBuilder, blendFormula.primaryOutput(), args.fOutputPrimary,
+                            args.fInputColor, args.fInputCoverage);
     }
 
     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
@@ -756,7 +810,7 @@
     }
     // Ignore the effect of coverage here for overlap stencil and cover property
     auto colorFormula = gBlendTable[color.isOpaque()][0][(int)mode];
-    SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
+    SkASSERT(kAdd_GrBlendEquation == colorFormula.equation());
     if (!colorFormula.usesDstColor()) {
         props |= AnalysisProperties::kCanCombineOverlappedStencilAndCover;
     }
@@ -787,16 +841,16 @@
         return;
     }
     BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
-    *outPrimary = blendFormula.fPrimaryOutputType;
-    *outSecondary = blendFormula.fSecondaryOutputType;
+    *outPrimary = blendFormula.primaryOutput();
+    *outSecondary = blendFormula.secondaryOutput();
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////
 // SrcOver Global functions
 ////////////////////////////////////////////////////////////////////////////////////////////////
 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
-    static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
-                                                             kISA_GrBlendCoeff);
+    static BlendFormula gSrcOverBlendFormula =
+            MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
     static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
     return gSrcOverXP;
 }
diff --git a/tests/GrGetCoeffBlendKnownComponentsTest.cpp b/tests/GrGetCoeffBlendKnownComponentsTest.cpp
deleted file mode 100644
index 53bd09e..0000000
--- a/tests/GrGetCoeffBlendKnownComponentsTest.cpp
+++ /dev/null
@@ -1,111 +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 "Test.h"
-
-#if SK_SUPPORT_GPU
-
-#include "GrBlend.h"
-#include "SkGr.h"
-#include "SkRandom.h"
-
-static inline SkPMColor GrColorToSkPMColor(GrColor c) {
-    GrColorIsPMAssert(c);
-    return SkPackARGB32(GrColorUnpackA(c), GrColorUnpackR(c), GrColorUnpackG(c), GrColorUnpackB(c));
-}
-
-static inline GrColor SkPMColorToGrColor(SkPMColor c) {
-    return GrColorPackRGBA(SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c),
-                           SkGetPackedA32(c));
-}
-
-static GrColor make_baseline_color(GrColor src, GrColor dst, const SkXfermode* xm) {
-    SkPMColor skSrc = GrColorToSkPMColor(src);
-    SkPMColor skDst = GrColorToSkPMColor(dst);
-    if (xm) {
-        xm->xfer32(&skDst, &skSrc, 1, nullptr);
-    } else {
-        // null means src-over
-        skDst = SkPMSrcOver(skSrc, skDst);
-    }
-    return SkPMColorToGrColor(skDst);
-}
-
-DEF_TEST(GrGetCoeffBlendKnownComponents, reporter) {
-    SkRandom random;
-    for (int i = 0; i < SkXfermode::kLastCoeffMode; ++i) {
-        SkXfermode::Mode mode = (SkXfermode::Mode)i;
-        auto xm(SkXfermode::Make(mode));
-        SkXfermode::Coeff srcCoeff, dstCoeff;
-        SkAssertResult(SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff));
-        for (int j = 0; j < 1000; ++j) {
-            GrColor src = GrPremulColor(random.nextU());
-            GrColor dst = GrPremulColor(random.nextU());
-            GrColor outColor;
-            GrColorComponentFlags outFlags;
-            GrGetCoeffBlendKnownComponents(SkXfermodeCoeffToGrBlendCoeff(srcCoeff),
-                                           SkXfermodeCoeffToGrBlendCoeff(dstCoeff),
-                                           src, kRGBA_GrColorComponentFlags,
-                                           dst, kRGBA_GrColorComponentFlags,
-                                           &outColor, &outFlags);
-            GrColor baselineColor = make_baseline_color(src, dst, xm.get());
-            if (SkAbs32(GrColorUnpackA(baselineColor) - GrColorUnpackA(outColor)) > 1 ||
-                SkAbs32(GrColorUnpackR(baselineColor) - GrColorUnpackR(outColor)) > 1 ||
-                SkAbs32(GrColorUnpackG(baselineColor) - GrColorUnpackG(outColor)) > 1 ||
-                SkAbs32(GrColorUnpackB(baselineColor) - GrColorUnpackB(outColor)) > 1) {
-                ERRORF(reporter, "Blended color is 0x%08x, expected 0x%08x", outColor,
-                       baselineColor);
-            }
-            GrColorIsPMAssert(outColor);
-        }
-    }
-    GrColor outColor;
-    GrColorComponentFlags outFlags;
-    GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kZero_GrBlendCoeff,
-                                   0xFFFFFFFF, kNone_GrColorComponentFlags,
-                                   0xFFFFFFFF, kNone_GrColorComponentFlags,
-                                   &outColor, &outFlags);
-    REPORTER_ASSERT(reporter, GrColor_TRANSPARENT_BLACK == outColor &&
-                              kRGBA_GrColorComponentFlags == outFlags);
-    GrGetCoeffBlendKnownComponents(
-        kOne_GrBlendCoeff, kOne_GrBlendCoeff,
-        0x80FF0100, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag),
-        0x7F00FFFF, (kR_GrColorComponentFlag | kG_GrColorComponentFlag | kA_GrColorComponentFlag),
-        &outColor, &outFlags);
-    REPORTER_ASSERT(reporter, GrColor_WHITE == outColor && kRGBA_GrColorComponentFlags == outFlags);
-
-    GrGetCoeffBlendKnownComponents(
-        kOne_GrBlendCoeff, kISA_GrBlendCoeff,
-        0x0000000, kRGBA_GrColorComponentFlags,
-        0x80010203, kRGBA_GrColorComponentFlags,
-        &outColor, &outFlags);
-    REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags);
-
-    GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kISA_GrBlendCoeff,
-                                   0x0000000, kA_GrColorComponentFlag,
-                                   0x80010203, kRGBA_GrColorComponentFlags,
-                                   &outColor, &outFlags);
-    REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags);
-
-    GrGetCoeffBlendKnownComponents(
-        kIDC_GrBlendCoeff, kSC_GrBlendCoeff,
-        0x0, kNone_GrColorComponentFlags,
-        0x0, kRGBA_GrColorComponentFlags,
-        &outColor, &outFlags);
-    REPORTER_ASSERT(reporter, kNone_GrColorComponentFlags == outFlags);
-
-    GrGetCoeffBlendKnownComponents(
-        kOne_GrBlendCoeff, kISA_GrBlendCoeff,
-        0xFF808080, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag),
-        0xFF606060, kRGBA_GrColorComponentFlags,
-        &outColor, &outFlags);
-    REPORTER_ASSERT(reporter,
-                    (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag) == outFlags &&
-                    (outColor & 0xFFFFFF00) == 0xFF808000);
-}
-
-#endif