Add in shader blending for CoverageSetOp XP

BUG=skia:

Review URL: https://codereview.chromium.org/1488213002
diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp
index 994b073..a379324 100644
--- a/src/effects/SkArithmeticMode_gpu.cpp
+++ b/src/effects/SkArithmeticMode_gpu.cpp
@@ -213,8 +213,10 @@
     void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb,
                                  GrGLSLXPFragmentBuilder* fragBuilder,
                                  const char* srcColor,
+                                 const char* srcCoverage,
                                  const char* dstColor,
                                  const char* outColor,
+                                 const char* outColorSecondary,
                                  const GrXferProcessor& proc) override {
         fKUni = pb->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
                                kVec4f_GrSLType, kDefault_GrSLPrecision,
@@ -222,6 +224,19 @@
         const char* kUni = pb->getUniformCStr(fKUni);
 
         add_arithmetic_code(fragBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor);
+
+        // Apply coverage.
+        if (proc.dstReadUsesMixedSamples()) {
+            if (srcCoverage) {
+                fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage);
+                fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage);
+            } else {
+                fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary);
+            }
+        } else if (srcCoverage) {
+            fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
+                                     outColor, srcCoverage, outColor, srcCoverage, dstColor);
+        }
     }
 
     void onSetData(const GrGLSLProgramDataManager& pdman,
diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp
index 43bb488..219ed0b 100644
--- a/src/gpu/effects/GrCoverageSetOpXP.cpp
+++ b/src/gpu/effects/GrCoverageSetOpXP.cpp
@@ -11,6 +11,7 @@
 #include "GrColor.h"
 #include "GrProcessor.h"
 #include "GrProcOptInfo.h"
+#include "glsl/GrGLSLBlend.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLXferProcessor.h"
@@ -146,6 +147,96 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+class ShaderCSOXferProcessor : public GrXferProcessor {
+public:
+    ShaderCSOXferProcessor(const DstTexture* dstTexture,
+                           bool hasMixedSamples,
+                           SkXfermode::Mode xfermode,
+                           SkRegion::Op regionOp,
+                           bool invertCoverage)
+        : INHERITED(dstTexture, true, hasMixedSamples)
+        , fRegionOp(regionOp)
+        , fInvertCoverage(invertCoverage) {
+        this->initClassID<ShaderCSOXferProcessor>();
+    }
+
+    const char* name() const override { return "Coverage Set Op Shader"; }
+
+    GrGLSLXferProcessor* createGLSLInstance() const override;
+
+    SkRegion::Op regionOp() const { return fRegionOp; }
+    bool invertCoverage() const { return fInvertCoverage; }
+
+private:
+    GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*, 
+                                                 const GrCaps&) const override {
+        // We never look at the color input
+        return GrXferProcessor::kIgnoreColor_OptFlag; 
+    }
+
+    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
+
+    bool onIsEqual(const GrXferProcessor& xpBase) const override {
+        const ShaderCSOXferProcessor& xp = xpBase.cast<ShaderCSOXferProcessor>();
+        return (fRegionOp == xp.fRegionOp &&
+                fInvertCoverage == xp.fInvertCoverage);
+    }
+
+    SkRegion::Op fRegionOp;
+    bool         fInvertCoverage;
+
+    typedef GrXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GLShaderCSOXferProcessor : public GrGLSLXferProcessor {
+public:
+    static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
+        const ShaderCSOXferProcessor& xp = processor.cast<ShaderCSOXferProcessor>();
+        b->add32(xp.regionOp());
+        uint32_t key = xp.invertCoverage() ?  0x0 : 0x1;
+        b->add32(key);
+    }
+
+private:
+    void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb,
+                                 GrGLSLXPFragmentBuilder* fragBuilder,
+                                 const char* srcColor,
+                                 const char* srcCoverage,
+                                 const char* dstColor,
+                                 const char* outColor,
+                                 const char* outColorSecondary,
+                                 const GrXferProcessor& proc) override {
+        const ShaderCSOXferProcessor& xp = proc.cast<ShaderCSOXferProcessor>();
+
+        if (xp.invertCoverage()) {
+            fragBuilder->codeAppendf("%s = 1.0 - %s;", outColor, srcCoverage);
+        } else {
+            fragBuilder->codeAppendf("%s = %s;", outColor, srcCoverage);
+        }
+
+        GrGLSLBlend::AppendRegionOp(fragBuilder, outColor, dstColor, outColor, xp.regionOp());
+    }
+
+    void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
+
+    typedef GrGLSLXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+void ShaderCSOXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
+                                                   GrProcessorKeyBuilder* b) const {
+    GLShaderCSOXferProcessor::GenKey(*this, b);
+}
+
+GrGLSLXferProcessor* ShaderCSOXferProcessor::createGLSLInstance() const {
+    return new GLShaderCSOXferProcessor;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//
 GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage)
     : fRegionOp(regionOp)
     , fInvertCoverage(invertCoverage) {
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 93999dd..d2aff60 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -161,13 +161,28 @@
     void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb,
                                  GrGLSLXPFragmentBuilder* fragBuilder,
                                  const char* srcColor,
+                                 const char* srcCoverage,
                                  const char* dstColor,
                                  const char* outColor,
+                                 const char* outColorSecondary,
                                  const GrXferProcessor& proc) override {
         const CustomXP& xp = proc.cast<CustomXP>();
         SkASSERT(!xp.hasHWBlendEquation());
 
         GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.mode());
+
+        // Apply coverage.
+        if (xp.dstReadUsesMixedSamples()) {
+            if (srcCoverage) {
+                fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage);
+                fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage);
+            } else {
+                fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary);
+            }
+        } else if (srcCoverage) {
+            fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
+                                     outColor, srcCoverage, outColor, srcCoverage, dstColor);
+        }
     }
 
     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index e288f0c..42a9631 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -548,12 +548,27 @@
     void emitBlendCodeForDstRead(GrGLSLXPBuilder* pb,
                                  GrGLSLXPFragmentBuilder* fragBuilder,
                                  const char* srcColor,
+                                 const char* srcCoverage,
                                  const char* dstColor,
                                  const char* outColor,
+                                 const char* outColorSecondary,
                                  const GrXferProcessor& proc) override {
         const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
 
         GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
+
+        // Apply coverage.
+        if (xp.dstReadUsesMixedSamples()) {
+            if (srcCoverage) {
+                fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage);
+                fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage);
+            } else {
+                fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary);
+            }
+        } else if (srcCoverage) {
+            fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
+                                     outColor, srcCoverage, outColor, srcCoverage, dstColor);
+        }
     }
 
     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
diff --git a/src/gpu/glsl/GrGLSLBlend.cpp b/src/gpu/glsl/GrGLSLBlend.cpp
index 3c83068..6937977 100644
--- a/src/gpu/glsl/GrGLSLBlend.cpp
+++ b/src/gpu/glsl/GrGLSLBlend.cpp
@@ -433,3 +433,50 @@
         emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
     }
 }
+
+void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
+                                 const char* dstColor, const char* outColor,
+                                 SkRegion::Op regionOp) {
+    SkXfermode::Coeff srcCoeff, dstCoeff;
+    switch (regionOp) {
+        case SkRegion::kReplace_Op:
+            srcCoeff = SkXfermode::kOne_Coeff;
+            dstCoeff = SkXfermode::kZero_Coeff;
+            break;
+        case SkRegion::kIntersect_Op:
+            srcCoeff = SkXfermode::kDC_Coeff;
+            dstCoeff = SkXfermode::kZero_Coeff;
+            break;
+        case SkRegion::kUnion_Op:
+            srcCoeff = SkXfermode::kOne_Coeff;
+            dstCoeff = SkXfermode::kISC_Coeff;
+            break;
+        case SkRegion::kXOR_Op:
+            srcCoeff = SkXfermode::kIDC_Coeff;
+            dstCoeff = SkXfermode::kISC_Coeff;
+            break;
+        case SkRegion::kDifference_Op:
+            srcCoeff = SkXfermode::kZero_Coeff;
+            dstCoeff = SkXfermode::kISC_Coeff;
+            break;
+        case SkRegion::kReverseDifference_Op:
+            srcCoeff = SkXfermode::kIDC_Coeff;
+            dstCoeff = SkXfermode::kZero_Coeff;
+            break;
+        default:
+            SkFAIL("Unsupported Op");
+            // We should never get here but to make compiler happy
+            srcCoeff = SkXfermode::kZero_Coeff;
+            dstCoeff = SkXfermode::kZero_Coeff;
+    }
+    fsBuilder->codeAppendf("%s = ", outColor);
+    // append src blend
+    bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
+                                            false);
+    // append dst blend
+    if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
+        fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
+    }
+    fsBuilder->codeAppend(";");
+}
+
diff --git a/src/gpu/glsl/GrGLSLBlend.h b/src/gpu/glsl/GrGLSLBlend.h
index 25ae37b..c8047f8 100644
--- a/src/gpu/glsl/GrGLSLBlend.h
+++ b/src/gpu/glsl/GrGLSLBlend.h
@@ -8,6 +8,7 @@
 #ifndef GrGLBlend_DEFINED
 #define GrGLBlend_DEFINED
 
+#include "SkRegion.h"
 #include "SkXfermode.h"
 
 class GrGLSLFragmentBuilder;
@@ -19,6 +20,9 @@
      */
     void AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
                     const char* dstColor, const char* outColor, SkXfermode::Mode mode);
+
+    void AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
+                        const char* dstColor, const char* outColor, SkRegion::Op regionOp);
 };
 
 #endif
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.cpp b/src/gpu/glsl/GrGLSLXferProcessor.cpp
index 7382660..b6af968 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLXferProcessor.cpp
@@ -63,23 +63,11 @@
     this->emitBlendCodeForDstRead(args.fPB,
                                   fragBuilder,
                                   args.fInputColor,
+                                  args.fInputCoverage,
                                   dstColor,
                                   args.fOutputPrimary,
+                                  args.fOutputSecondary,
                                   args.fXP);
-
-    // Apply coverage.
-    if (args.fXP.dstReadUsesMixedSamples()) {
-        if (args.fInputCoverage) {
-            fragBuilder->codeAppendf("%s *= %s;", args.fOutputPrimary, args.fInputCoverage);
-            fragBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
-        } else {
-            fragBuilder->codeAppendf("%s = vec4(1.0);", args.fOutputSecondary);
-        }
-    } else if (args.fInputCoverage) {
-        fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
-                                 args.fOutputPrimary, args.fInputCoverage,
-                                 args.fOutputPrimary, args.fInputCoverage, dstColor);
-    }
 }
 
 void GrGLSLXferProcessor::setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) {
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h
index 46d775d..3707d93 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.h
+++ b/src/gpu/glsl/GrGLSLXferProcessor.h
@@ -85,8 +85,10 @@
     virtual void emitBlendCodeForDstRead(GrGLSLXPBuilder*,
                                          GrGLSLXPFragmentBuilder*,
                                          const char* srcColor,
+                                         const char* srcCoverage,
                                          const char* dstColor,
                                          const char* outColor,
+                                         const char* outColorSecondary,
                                          const GrXferProcessor&) {
         SkFAIL("emitBlendCodeForDstRead not implemented.");
     }