Add mixed samples support to XPs

BUG=skia:

Review URL: https://codereview.chromium.org/1164973002
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index ecaa87f..df44a1b 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -288,21 +288,23 @@
     /* screen */     COEFF_FORMULA(   kOne_GrBlendCoeff,    kISC_GrBlendCoeff),
 }}};
 
-static BlendFormula get_blend_formula(SkXfermode::Mode xfermode,
-                                      const GrProcOptInfo& colorPOI,
-                                      const GrProcOptInfo& coveragePOI) {
+static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
+                                      const GrProcOptInfo& coveragePOI,
+                                      bool hasMixedSamples,
+                                      SkXfermode::Mode xfermode) {
     SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
     SkASSERT(!coveragePOI.isFourChannelOutput());
 
-    return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermode];
+    bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
+    return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 class PorterDuffXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(BlendFormula blendFormula) {
-        return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
+    PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
+        this->initClassID<PorterDuffXferProcessor>();
     }
 
     const char* name() const override { return "Porter Duff"; }
@@ -312,10 +314,6 @@
     BlendFormula getBlendFormula() const { return fBlendFormula; }
 
 private:
-    PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
-        this->initClassID<PorterDuffXferProcessor>();
-    }
-
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
                                                  const GrProcOptInfo& coveragePOI,
                                                  bool doesStencilWrite,
@@ -353,6 +351,7 @@
             fsBuilder->codeAppendf("%s = vec4(0.0);", output);
             break;
         case BlendFormula::kCoverage_OutputType:
+            // We can have a coverage formula while not reading coverage if there are mixed samples.
             fsBuilder->codeAppendf("%s = %s;",
                                    output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
             break;
@@ -455,8 +454,12 @@
 
 class ShaderPDXferProcessor : public GrXferProcessor {
 public:
-    static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
-        return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
+    ShaderPDXferProcessor(const DstTexture* dstTexture,
+                          bool hasMixedSamples,
+                          SkXfermode::Mode xfermode)
+        : INHERITED(dstTexture, true, hasMixedSamples)
+        , fXfermode(xfermode) {
+        this->initClassID<ShaderPDXferProcessor>();
     }
 
     const char* name() const override { return "Porter Duff Shader"; }
@@ -466,12 +469,6 @@
     SkXfermode::Mode getXfermode() const { return fXfermode; }
 
 private:
-    ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTexture)
-        : INHERITED(dstTexture, true)
-        , fXfermode(xfermode) {
-        this->initClassID<ShaderPDXferProcessor>();
-    }
-
     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
                                                  bool, GrColor*, const GrCaps&) override {
         return kNone_Opt;
@@ -738,19 +735,20 @@
 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
                                              const GrProcOptInfo& covPOI,
+                                             bool hasMixedSamples,
                                              const DstTexture* dstTexture) const {
     if (covPOI.isFourChannelOutput()) {
         SkASSERT(!dstTexture || !dstTexture->texture());
         return PDLCDXferProcessor::Create(fXfermode, colorPOI);
     }
 
-    BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
+    BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
     if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
-        return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
+        return SkNEW_ARGS(ShaderPDXferProcessor, (dstTexture, hasMixedSamples, fXfermode));
     }
 
     SkASSERT(!dstTexture || !dstTexture->texture());
-    return PorterDuffXferProcessor::Create(blendFormula);
+    return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
 }
 
 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
@@ -795,15 +793,17 @@
 
 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
                                              const GrProcOptInfo& colorPOI,
-                                             const GrProcOptInfo& coveragePOI) const {
-    if (coveragePOI.isFourChannelOutput()) {
-        return false; // The LCD XP never does a dst read.
+                                             const GrProcOptInfo& covPOI,
+                                             bool hasMixedSamples) const {
+    if (caps.shaderCaps()->dualSourceBlendingSupport()) {
+        return false;
     }
-
+    if (covPOI.isFourChannelOutput()) {
+        return false; // The LCD XP will abort rather than doing a dst read.
+    }
     // We fallback on the shader XP when the blend formula would use dual source blending but we
     // don't have support for it.
-    return !caps.shaderCaps()->dualSourceBlendingSupport() &&
-           get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
+    return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
 }
 
 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);