Create a static instances of SrcOver XferProcessor

BUG=skia:

Review URL: https://codereview.chromium.org/1471293003
diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h
index 0aa09d8..ce26709 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -145,7 +145,7 @@
     OptFlags getOptimizations(const GrPipelineOptimizations& optimizations,
                               bool doesStencilWrite,
                               GrColor* overrideColor,
-                              const GrCaps& caps);
+                              const GrCaps& caps) const;
 
     /**
      * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType
@@ -199,11 +199,6 @@
     bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; }
 
     /**
-     * Returns whether or not the XP will look at coverage when doing its blending.
-     */
-    bool readsCoverage() const { return fReadsCoverage; }
-
-    /**
      * Returns whether or not this xferProcossor will set a secondary output to be used with dual
      * source blending.
      */
@@ -224,9 +219,6 @@
         if (this->fWillReadDstColor != that.fWillReadDstColor) {
             return false;
         }
-        if (this->fReadsCoverage != that.fReadsCoverage) {
-            return false;
-        }
         if (this->fDstTexture.getTexture() != that.fDstTexture.getTexture()) {
             return false;
         }
@@ -249,7 +241,7 @@
     virtual OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                         bool doesStencilWrite,
                                         GrColor* overrideColor,
-                                        const GrCaps& caps) = 0;
+                                        const GrCaps& caps) const = 0;
 
     /**
      * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer
@@ -285,7 +277,6 @@
 
     bool                    fWillReadDstColor;
     bool                    fDstReadUsesMixedSamples;
-    bool                    fReadsCoverage;
     SkIPoint                fDstTextureOffset;
     GrTextureAccess         fDstTexture;
 
diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp
index c9493d7..994b073 100644
--- a/src/effects/SkArithmeticMode_gpu.cpp
+++ b/src/effects/SkArithmeticMode_gpu.cpp
@@ -170,7 +170,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* overrideColor,
-                                                 const GrCaps& caps) override;
+                                                 const GrCaps& caps) const override;
 
     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
 
@@ -260,7 +260,7 @@
                                                        const GrPipelineOptimizations& optimizations,
                                                        bool doesStencilWrite,
                                                        GrColor* overrideColor,
-                                                       const GrCaps& caps) {
+                                                       const GrCaps& caps) const {
    return GrXferProcessor::kNone_OptFlags;
 }
 
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index e5cf044..02edd42 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -184,6 +184,7 @@
                                                 const GrProcOptInfo& coveragePOI,
                                                 int* firstColorProcessorIdx,
                                                 int* firstCoverageProcessorIdx) {
+    fIgnoresCoverage = SkToBool(flags & GrXferProcessor::kIgnoreCoverage_OptFlag);
     fReadsFragPosition = fXferProcessor->willReadFragmentPosition();
 
     if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) ||
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 2d909be..fbfe119 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -150,6 +150,7 @@
     ///////////////////////////////////////////////////////////////////////////
 
     bool readsFragPosition() const { return fReadsFragPosition; }
+    bool ignoresCoverage() const { return fIgnoresCoverage; }
 
 private:
     GrPipeline() { /** Initialized in factory function*/ }
@@ -189,6 +190,7 @@
     ProgramXferProcessor                fXferProcessor;
     FragmentProcessorArray              fFragmentProcessors;
     bool                                fReadsFragPosition;
+    bool                                fIgnoresCoverage;
 
     // This value is also the index in fFragmentProcessors where coverage processors begin.
     int                                 fNumColorProcessors;
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index 1510630..13dd149 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -76,8 +76,9 @@
         uint8_t                     fSnapVerticesToPixelCenters;
         int8_t                      fColorEffectCnt;
         int8_t                      fCoverageEffectCnt;
+        uint8_t                     fIgnoresCoverage;
     };
-    GR_STATIC_ASSERT(sizeof(KeyHeader) == 4);
+    GR_STATIC_ASSERT(sizeof(KeyHeader) == 5);
 
     int numColorEffects() const {
         return this->header().fColorEffectCnt;
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index 3bccd6e..b07b972 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -14,7 +14,6 @@
 GrXferProcessor::GrXferProcessor()
     : fWillReadDstColor(false)
     , fDstReadUsesMixedSamples(false)
-    , fReadsCoverage(true)
     , fDstTextureOffset() {
 }
 
@@ -23,7 +22,6 @@
                                  bool hasMixedSamples)
     : fWillReadDstColor(willReadDstColor)
     , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples)
-    , fReadsCoverage(true)
     , fDstTextureOffset() {
     if (dstTexture && dstTexture->texture()) {
         SkASSERT(willReadDstColor);
@@ -38,7 +36,7 @@
                                                        const GrPipelineOptimizations& optimizations,
                                                        bool doesStencilWrite,
                                                        GrColor* overrideColor,
-                                                       const GrCaps& caps) {
+                                                       const GrCaps& caps) const {
     GrXferProcessor::OptFlags flags = this->onGetOptimizations(optimizations,
                                                                doesStencilWrite,
                                                                overrideColor,
@@ -51,9 +49,6 @@
             flags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
         }
     }
-    if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) {
-        fReadsCoverage = false;
-    }
     return flags;
 }
 
@@ -82,11 +77,8 @@
                 key |= 0x4;
             }
         }
-        if (this->readsCoverage()) {
-            key |= 0x8;
-        }
         if (this->dstReadUsesMixedSamples()) {
-            key |= 0x10;
+            key |= 0x8;
         }
     }
     b->add32(key);
diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp
index c7226fc..43bb488 100644
--- a/src/gpu/effects/GrCoverageSetOpXP.cpp
+++ b/src/gpu/effects/GrCoverageSetOpXP.cpp
@@ -35,7 +35,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* color,
-                                                 const GrCaps& caps) override;
+                                                 const GrCaps& caps) const override;
 
     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
 
@@ -109,7 +109,7 @@
 CoverageSetOpXP::onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                     bool doesStencilWrite,
                                     GrColor* color,
-                                    const GrCaps& caps) {
+                                    const GrCaps& caps) const {
     // We never look at the color input
     return GrXferProcessor::kIgnoreColor_OptFlag; 
 }
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 9de178d..93999dd 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -103,7 +103,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* overrideColor,
-                                                 const GrCaps& caps) override;
+                                                 const GrCaps& caps) const override;
 
     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
 
@@ -132,7 +132,6 @@
         if (xp.hasHWBlendEquation()) {
             SkASSERT(caps.advBlendEqInteraction() > 0);  // 0 will mean !xp.hasHWBlendEquation().
             key |= caps.advBlendEqInteraction();
-            key |= xp.readsCoverage() << 2;
             GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4);
         }
         if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) {
@@ -151,7 +150,7 @@
 
         // Apply coverage by multiplying it into the src color before blending. Mixed samples will
         // "just work" automatically. (See onGetOptimizations())
-        if (xp.readsCoverage()) {
+        if (args.fInputCoverage) {
             fragBuilder->codeAppendf("%s = %s * %s;",
                                      args.fOutputPrimary, args.fInputCoverage, args.fInputColor);
         } else {
@@ -195,7 +194,7 @@
 GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                        bool doesStencilWrite,
                                                        GrColor* overrideColor,
-                                                       const GrCaps& caps) {
+                                                       const GrCaps& caps) const {
   /*
     Most the optimizations we do here are based on tweaking alpha for coverage.
 
diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp
index abeaa8c..e669f8b 100644
--- a/src/gpu/effects/GrDisableColorXP.cpp
+++ b/src/gpu/effects/GrDisableColorXP.cpp
@@ -32,7 +32,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* color,
-                                                 const GrCaps& caps) override {
+                                                 const GrCaps& caps) const override {
         return GrXferProcessor::kIgnoreColor_OptFlag | GrXferProcessor::kIgnoreCoverage_OptFlag;
     }
 
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 88275c2..e288f0c 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -356,7 +356,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* overrideColor,
-                                                 const GrCaps& caps) override;
+                                                 const GrCaps& caps) const override;
 
     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
 
@@ -391,32 +391,35 @@
             break;
         case BlendFormula::kCoverage_OutputType:
             // We can have a coverage formula while not reading coverage if there are mixed samples.
-            fragBuilder->codeAppendf("%s = %s;",
-                                   output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
+            if (inCoverage) {
+                fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
+            } else {
+                fragBuilder->codeAppendf("%s = vec4(1.0);", output);
+            }
             break;
         case BlendFormula::kModulate_OutputType:
-            if (xp.readsCoverage()) {
+            if (inCoverage) {
                 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
             } else {
                 fragBuilder->codeAppendf("%s = %s;", output, inColor);
             }
             break;
         case BlendFormula::kSAModulate_OutputType:
-            if (xp.readsCoverage()) {
+            if (inCoverage) {
                 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
             } else {
                 fragBuilder->codeAppendf("%s = %s;", output, inColor);
             }
             break;
         case BlendFormula::kISAModulate_OutputType:
-            if (xp.readsCoverage()) {
+            if (inCoverage) {
                 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
             } else {
                 fragBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
             }
             break;
         case BlendFormula::kISCModulate_OutputType:
-            if (xp.readsCoverage()) {
+            if (inCoverage) {
                 fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
             } else {
                 fragBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
@@ -432,9 +435,8 @@
 public:
     static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
         const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
-        b->add32(SkToInt(xp.readsCoverage()) |
-                 (xp.getBlendFormula().fPrimaryOutputType << 1) |
-                 (xp.getBlendFormula().fSecondaryOutputType << 4));
+        b->add32(xp.getBlendFormula().fPrimaryOutputType |
+                 (xp.getBlendFormula().fSecondaryOutputType << 3));
         GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
     };
 
@@ -472,7 +474,7 @@
 PorterDuffXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                             bool doesStencilWrite,
                                             GrColor* overrideColor,
-                                            const GrCaps& caps) {
+                                            const GrCaps& caps) const {
     GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
     if (!fBlendFormula.modifiesDst()) {
         if (!doesStencilWrite) {
@@ -517,7 +519,7 @@
 
 private:
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*, 
-                                                 const GrCaps&) override {
+                                                 const GrCaps&) const override {
         return kNone_OptFlags;
     }
 
@@ -588,7 +590,7 @@
     GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                                  bool doesStencilWrite,
                                                  GrColor* overrideColor,
-                                                 const GrCaps& caps) override;
+                                                 const GrCaps& caps) const override;
 
     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
 
@@ -627,6 +629,7 @@
 private:
     void emitOutputsForBlendState(const EmitArgs& args) override {
         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
+        SkASSERT(args.fInputCoverage);
         fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
                                  args.fInputCoverage);
     }
@@ -677,7 +680,7 @@
 PDLCDXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
                                        bool doesStencilWrite,
                                        GrColor* overrideColor,
-                                       const GrCaps& caps) {
+                                       const GrCaps& caps) const {
         // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
         // value of the blend the constant. We should already have valid blend coeff's if we are at
         // a point where we have RGB coverage. We don't need any color stages since the known color
@@ -838,6 +841,18 @@
         const GrPipelineOptimizations& optimizations,
         bool hasMixedSamples,
         const GrXferProcessor::DstTexture* dstTexture) {
+    if (!optimizations.fCoveragePOI.isFourChannelOutput() &&
+        !(optimizations.fCoveragePOI.isSolidWhite() &&
+          !hasMixedSamples &&
+          optimizations.fColorPOI.isOpaque())) {
+        static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
+                                                                 kISA_GrBlendCoeff);
+        static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
+        SkASSERT(!dstTexture || !dstTexture->texture());
+        gSrcOverXP.ref();
+        return &gSrcOverXP;
+    }
+
     BlendFormula blendFormula;
     if (optimizations.fCoveragePOI.isFourChannelOutput()) {
         if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index e3ee913..e3d292c 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -147,6 +147,13 @@
     } else {
         header->fFragPosKey = 0;
     }
+
+    if (pipeline.ignoresCoverage()) {
+        header->fIgnoresCoverage = 1;
+    } else {
+        header->fIgnoresCoverage = 0;
+    }
+
     header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters();
     header->fColorEffectCnt = pipeline.numColorFragmentProcessors();
     header->fCoverageEffectCnt = pipeline.numCoverageFragmentProcessors();
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index b5108a7..86264c0 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -140,7 +140,8 @@
     this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
     this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
                                   inputCoverage);
-    this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage);
+    this->emitAndInstallXferProc(*this->pipeline().getXferProcessor(), *inputColor, *inputCoverage,
+                                 this->pipeline().ignoresCoverage());
     return true;
 }
 
@@ -266,7 +267,8 @@
 
 void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
                                                 const GrGLSLExpr4& colorIn,
-                                                const GrGLSLExpr4& coverageIn) {
+                                                const GrGLSLExpr4& coverageIn,
+                                                bool ignoresCoverage) {
     // Program builders have a bit of state we need to clear with each effect
     AutoStageAdvance adv(this);
 
@@ -295,7 +297,7 @@
                                        &fFS,
                                        this->glslCaps(),
                                        xp, colorIn.c_str(),
-                                       coverageIn.c_str(),
+                                       ignoresCoverage ? nullptr : coverageIn.c_str(),
                                        fFS.getPrimaryColorOutputName(),
                                        fFS.getSecondaryColorOutputName(),
                                        samplers);
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index edc467c..329e5d7 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -108,7 +108,8 @@
                             const char* outCoverage);
     void emitAndInstallXferProc(const GrXferProcessor&,
                                 const GrGLSLExpr4& colorIn,
-                                const GrGLSLExpr4& coverageIn);
+                                const GrGLSLExpr4& coverageIn,
+                                bool ignoresCoverage);
 
     void verify(const GrPrimitiveProcessor&);
     void verify(const GrXferProcessor&);
diff --git a/src/gpu/glsl/GrGLSLXferProcessor.cpp b/src/gpu/glsl/GrGLSLXferProcessor.cpp
index 4d2ec10..7382660 100644
--- a/src/gpu/glsl/GrGLSLXferProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLXferProcessor.cpp
@@ -24,7 +24,7 @@
     if (args.fXP.getDstTexture()) {
         bool topDown = kTopLeft_GrSurfaceOrigin == args.fXP.getDstTexture()->origin();
 
-        if (args.fXP.readsCoverage()) {
+        if (args.fInputCoverage) {
             // We don't think any shaders actually output negative coverage, but just as a safety
             // check for floating point precision errors we compare with <= here
             fragBuilder->codeAppendf("if (all(lessThanEqual(%s, vec4(0)))) {"
@@ -69,13 +69,13 @@
 
     // Apply coverage.
     if (args.fXP.dstReadUsesMixedSamples()) {
-        if (args.fXP.readsCoverage()) {
+        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.fXP.readsCoverage()) {
+    } else if (args.fInputCoverage) {
         fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
                                  args.fOutputPrimary, args.fInputCoverage,
                                  args.fOutputPrimary, args.fInputCoverage, dstColor);