Remove GrXferProcessor::getOptimizations.

This replaces GrXferProcessor::getOptimizations with a new function on GrXPFactory. The results are made available via FragmentProcessorAnalysis.

Bug: skia:
Change-Id: I535985458c9d13ad858cac94e957e2fdbe332036
Reviewed-on: https://skia-review.googlesource.com/10218
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index adcdd0f..d8f7fbd 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -52,37 +52,32 @@
     bool isHWAA = kHWAntialias_Flag & args.fFlags;
 
     // Create XferProcessor from DS's XPFactory
-    bool hasMixedSamples = args.fRenderTarget->isMixedSampled() && (isHWAA || isStencilEnabled());
-    const GrXPFactory* xpFactory = args.fProcessors->xpFactory();
-    sk_sp<GrXferProcessor> xferProcessor;
-    if (xpFactory) {
-        xferProcessor.reset(xpFactory->createXferProcessor(*args.fAnalysis, hasMixedSamples,
-                                                           &args.fDstTexture, *args.fCaps));
-        SkASSERT(xferProcessor);
-    } else {
-        // This may return nullptr in the common case of src-over implemented using hw blending.
-        xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
-                *args.fCaps, *args.fAnalysis, hasMixedSamples, &args.fDstTexture));
+    {
+        bool hasMixedSamples =
+                args.fRenderTarget->isMixedSampled() && (isHWAA || this->isStencilEnabled());
+        sk_sp<GrXferProcessor> xferProcessor;
+        const GrXPFactory* xpFactory = args.fProcessors->xpFactory();
+        if (xpFactory) {
+            xferProcessor.reset(xpFactory->createXferProcessor(*args.fAnalysis, hasMixedSamples,
+                                                               &args.fDstTexture, *args.fCaps));
+            SkASSERT(xferProcessor);
+        } else {
+            // This may return nullptr in the common case of src-over implemented using hw blending.
+            xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
+                    *args.fCaps, *args.fAnalysis, hasMixedSamples, &args.fDstTexture));
+        }
+        fXferProcessor.reset(xferProcessor.get());
     }
+
+    // This is for the legacy GrPipeline creation in GrMeshDrawOp where analysis does not
+    // eliminate fragment processors from GrProcessorSet.
     GrColor overrideColor = GrColor_ILLEGAL;
     int colorFPsToEliminate =
             args.fAnalysis->getInputColorOverrideAndColorProcessorEliminationCount(&overrideColor);
     colorFPsToEliminate = SkTMax(colorFPsToEliminate, 0);
-
-    GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
-
-    const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() :
-                                                       &GrPorterDuffXPFactory::SimpleSrcOverXP();
-    optFlags = xpForOpts->getOptimizations(*args.fAnalysis);
-
-    // No need to have an override color if it isn't even going to be used.
-    if (SkToBool(GrXferProcessor::kIgnoreColor_OptFlag & optFlags)) {
+    if (args.fAnalysis->isInputColorIgnored()) {
+        // No need to have an override color if it isn't even going to be used.
         overrideColor = GrColor_ILLEGAL;
-    }
-
-    fXferProcessor.reset(xferProcessor.get());
-
-    if ((optFlags & GrXferProcessor::kIgnoreColor_OptFlag)) {
         colorFPsToEliminate = args.fProcessors->numColorFragmentProcessors();
     }
 
@@ -122,7 +117,7 @@
     if (args.fAnalysis->usesLocalCoords()) {
         optimizations.fFlags |= GrPipelineOptimizations::kReadsLocalCoords_Flag;
     }
-    if (SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag)) {
+    if (args.fAnalysis->isCompatibleWithCoverageAsAlpha()) {
         optimizations.fFlags |= GrPipelineOptimizations::kCanTweakAlphaForCoverage_Flag;
     }
     return optimizations;
diff --git a/src/gpu/GrPipelineAnalysis.h b/src/gpu/GrPipelineAnalysis.h
index 4f553b0..d55ff0a 100644
--- a/src/gpu/GrPipelineAnalysis.h
+++ b/src/gpu/GrPipelineAnalysis.h
@@ -41,9 +41,11 @@
 
     bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); }
 
-    bool isConstant(GrColor* color) const {
+    bool isConstant(GrColor* color = nullptr) const {
         if (kColorIsKnown_Flag & fFlags) {
-            *color = fColor;
+            if (color) {
+                *color = fColor;
+            }
             return true;
         }
         return false;
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 17dfe90..7451b65 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -65,20 +65,6 @@
 
     /// @}
 
-    ///////////////////////////////////////////////////////////////////////////
-    /// @name Blending
-    ////
-
-    /**
-     * Checks whether the xp will need destination in a texture to correctly blend.
-     */
-    bool willXPNeedDstTexture(const GrCaps& caps,
-                              const GrProcessorSet::FragmentProcessorAnalysis& analysis) const {
-        return GrXPFactory::WillNeedDstTexture(fProcessors.xpFactory(), caps, analysis);
-    }
-
-    /// @}
-
 
     ///////////////////////////////////////////////////////////////////////////
     /// @name Stencil
diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp
index 4a50892..0350ba5 100644
--- a/src/gpu/GrProcessorSet.cpp
+++ b/src/gpu/GrProcessorSet.cpp
@@ -9,6 +9,7 @@
 #include "GrAppliedClip.h"
 #include "GrCaps.h"
 #include "GrPipelineAnalysis.h"
+#include "GrXferProcessor.h"
 
 GrProcessorSet::GrProcessorSet(GrPaint&& paint) {
     fXPFactory = paint.fXPFactory;
@@ -97,7 +98,7 @@
     fps += processors.fColorFragmentProcessorCnt;
     int n = processors.numCoverageFragmentProcessors();
     bool hasCoverageFP = n > 0;
-    fUsesLocalCoords = colorInfo.usesLocalCoords();
+    bool coverageUsesLocalCoords = false;
     for (int i = 0; i < n; ++i) {
         if (!fps[i]->compatibleWithCoverageAsAlpha()) {
             fCompatibleWithCoverageAsAlpha = false;
@@ -105,12 +106,12 @@
             // compatible with the coverage-as-alpha optimization.
             GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n");
         }
-        fUsesLocalCoords |= fps[i]->usesLocalCoords();
+        coverageUsesLocalCoords |= fps[i]->usesLocalCoords();
     }
 
     if (clipFP) {
         fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha();
-        fUsesLocalCoords |= clipFP->usesLocalCoords();
+        coverageUsesLocalCoords |= clipFP->usesLocalCoords();
         hasCoverageFP = true;
     }
     fInitialColorProcessorsToEliminate = colorInfo.initialProcessorsToEliminate(&fInputColor);
@@ -126,12 +127,44 @@
         fOutputColorType = static_cast<unsigned>(ColorType::kUnknown);
     }
 
+    GrPipelineAnalysisCoverage outputCoverage;
     if (GrPipelineAnalysisCoverage::kLCD == coverageInput) {
-        fOutputCoverageType = static_cast<unsigned>(GrPipelineAnalysisCoverage::kLCD);
+        outputCoverage = GrPipelineAnalysisCoverage::kLCD;
     } else if (hasCoverageFP || GrPipelineAnalysisCoverage::kSingleChannel == coverageInput) {
-        fOutputCoverageType = static_cast<unsigned>(GrPipelineAnalysisCoverage::kSingleChannel);
+        outputCoverage = GrPipelineAnalysisCoverage::kSingleChannel;
     } else {
-        fOutputCoverageType = static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone);
+        outputCoverage = GrPipelineAnalysisCoverage::kNone;
+    }
+    fOutputCoverageType = static_cast<unsigned>(outputCoverage);
+
+    GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties(
+            processors.fXPFactory, colorInfo.outputColor(), outputCoverage, caps);
+    if (!processors.numCoverageFragmentProcessors() &&
+        GrPipelineAnalysisCoverage::kNone == coverageInput) {
+        fCanCombineOverlappedStencilAndCover = SkToBool(
+                props & GrXPFactory::AnalysisProperties::kCanCombineOverlappedStencilAndCover);
+    } else {
+        // If we have non-clipping coverage processors we don't try to merge stencil steps as its
+        // unclear whether it will be correct. We don't expect this to happen in practice.
+        fCanCombineOverlappedStencilAndCover = false;
+    }
+    fRequiresDstTexture = SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture);
+    fIgnoresInputColor = SkToBool(props & GrXPFactory::AnalysisProperties::kIgnoresInputColor);
+    fCompatibleWithCoverageAsAlpha &=
+            SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage);
+    if (props & GrXPFactory::AnalysisProperties::kIgnoresInputColor) {
+        fInitialColorProcessorsToEliminate = processors.numColorFragmentProcessors();
+        // If the output of the last color stage is known then the kIgnoresInputColor optimization
+        // may depend upon it being the input to the xp.
+        if (!outputColor.isConstant(&fInputColor)) {
+            // Otherwise, the only property the XP factory could have relied upon to compute
+            // kIgnoresInputColor is opaqueness.
+            fInputColor = GrColor_WHITE;
+        }
+        fValidInputColor = true;
+        fUsesLocalCoords = coverageUsesLocalCoords;
+    } else {
+        fUsesLocalCoords = coverageUsesLocalCoords | colorInfo.usesLocalCoords();
     }
 }
 
@@ -149,9 +182,12 @@
 GrProcessorSet::FragmentProcessorAnalysis::FragmentProcessorAnalysis(
         const GrPipelineAnalysisColor& colorInput,
         const GrPipelineAnalysisCoverage coverageInput,
+        const GrXPFactory* factory,
         const GrCaps& caps)
         : FragmentProcessorAnalysis() {
-    this->internalInit(colorInput, coverageInput, GrProcessorSet(GrPaint()), nullptr, caps);
+    GrPaint paint;
+    paint.setXPFactory(factory);
+    this->internalInit(colorInput, coverageInput, GrProcessorSet(std::move(paint)), nullptr, caps);
 }
 
 void GrProcessorSet::analyzeAndEliminateFragmentProcessors(
diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h
index bfad769..e584a94 100644
--- a/src/gpu/GrProcessorSet.h
+++ b/src/gpu/GrProcessorSet.h
@@ -79,13 +79,16 @@
                 : fIsInitializedWithProcessorSet(false)
                 , fCompatibleWithCoverageAsAlpha(true)
                 , fValidInputColor(false)
+                , fRequiresDstTexture(false)
+                , fCanCombineOverlappedStencilAndCover(true)
+                , fIgnoresInputColor(false)
                 , fOutputCoverageType(static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone))
                 , fOutputColorType(static_cast<unsigned>(ColorType::kUnknown))
                 , fInitialColorProcessorsToEliminate(0) {}
 
-        // This version is used by a unit test that assumes no clip, no processors, and no PLS.
+        // This version is used by a unit test that assumes no clip and no fragment processors.
         FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage,
-                                  const GrCaps&);
+                                  const GrXPFactory*, const GrCaps&);
 
         void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrProcessorSet&,
                   const GrAppliedClip*, const GrCaps&);
@@ -119,7 +122,12 @@
         }
 
         bool usesLocalCoords() const { return fUsesLocalCoords; }
+        bool requiresDstTexture() const { return fRequiresDstTexture; }
+        bool canCombineOverlappedStencilAndCover() const {
+            return fCanCombineOverlappedStencilAndCover;
+        }
         bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; }
+        bool isInputColorIgnored() const { return fIgnoresInputColor; }
         bool isOutputColorOpaque() const {
             return ColorType::kOpaque == this->outputColorType() ||
                    ColorType::kOpaqueConstant == this->outputColorType();
@@ -154,11 +162,17 @@
         PackedBool fUsesLocalCoords : 1;
         PackedBool fCompatibleWithCoverageAsAlpha : 1;
         PackedBool fValidInputColor : 1;
+        PackedBool fRequiresDstTexture : 1;
+        PackedBool fCanCombineOverlappedStencilAndCover : 1;
+        // These could be removed if we created the XP from the XPFactory when doing analysis.
+        PackedBool fIgnoresInputColor : 1;
         unsigned fOutputCoverageType : 2;
         unsigned fOutputColorType : 2;
-        unsigned fInitialColorProcessorsToEliminate : 32 - 8;
+
+        unsigned fInitialColorProcessorsToEliminate : 32 - 11;
 
         GrColor fInputColor;
+        // This could be removed if we created the XP from the XPFactory when doing analysis.
         GrColor fKnownOutputColor;
 
         friend class GrProcessorSet;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 70d4485..79ae757 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1743,7 +1743,7 @@
     args.fCaps = this->caps();
     args.fAnalysis = &analysis;
 
-    if (pipelineBuilder.willXPNeedDstTexture(*this->caps(), analysis)) {
+    if (analysis.requiresDstTexture()) {
         this->setupDstTexture(rt, clip, bounds, &args.fDstTexture);
         if (!args.fDstTexture.texture()) {
             return SK_InvalidUniqueID;
diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp
index bd63a0a..45bcc2d 100644
--- a/src/gpu/GrXferProcessor.cpp
+++ b/src/gpu/GrXferProcessor.cpp
@@ -29,11 +29,6 @@
     }
 }
 
-GrXferProcessor::OptFlags GrXferProcessor::getOptimizations(
-        const FragmentProcessorAnalysis& analysis) const {
-    return this->onGetOptimizations(analysis);
-}
-
 bool GrXferProcessor::hasSecondaryOutput() const {
     if (!this->willReadDstColor()) {
         return this->onHasSecondaryOutput();
@@ -175,39 +170,31 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool GrXPFactory::WillNeedDstTexture(const GrXPFactory* factory, const GrCaps& caps,
-                                     const GrProcessorSet::FragmentProcessorAnalysis& analysis) {
-    bool result;
+GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties(
+        const GrXPFactory* factory,
+        const GrPipelineAnalysisColor& color,
+        const GrPipelineAnalysisCoverage& coverage,
+        const GrCaps& caps) {
+    AnalysisProperties result;
     if (factory) {
-        result = !caps.shaderCaps()->dstReadInShaderSupport() &&
-                 factory->willReadDstInShader(caps, analysis);
+        result = factory->analysisProperties(color, coverage, caps);
     } else {
-        result = GrPorterDuffXPFactory::WillSrcOverNeedDstTexture(caps, analysis);
+        result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps);
+    }
+    SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture));
+    if ((result & AnalysisProperties::kReadsDstInShader) &&
+        !caps.shaderCaps()->dstReadInShaderSupport()) {
+        result |= AnalysisProperties::kRequiresDstTexture;
     }
     return result;
 }
 
-bool GrXPFactory::CompatibleWithCoverageAsAlpha(const GrXPFactory* factory, bool colorIsOpaque) {
-    if (factory) {
-        return factory->compatibleWithCoverageAsAlpha(colorIsOpaque);
-    }
-    return GrPorterDuffXPFactory::SrcOverIsCompatibleWithCoverageAsAlpha();
-}
-
-bool GrXPFactory::CanCombineOverlappedStencilAndCover(const GrXPFactory* factory,
-                                                      bool colorIsOpaque) {
-    if (factory) {
-        return factory->canCombineOverlappedStencilAndCover(colorIsOpaque);
-    }
-    return GrPorterDuffXPFactory::SrcOverCanCombineOverlappedStencilAndCover(colorIsOpaque);
-}
-
 GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysis& analysis,
                                                   bool hasMixedSamples,
                                                   const DstTexture* dstTexture,
                                                   const GrCaps& caps) const {
 #ifdef SK_DEBUG
-    if (this->willReadDstInShader(caps, analysis)) {
+    if (analysis.requiresDstTexture()) {
         if (!caps.shaderCaps()->dstReadInShaderSupport()) {
             SkASSERT(dstTexture && dstTexture->texture());
         } else {
diff --git a/src/gpu/GrXferProcessor.h b/src/gpu/GrXferProcessor.h
index bdf6f7d..54630af 100644
--- a/src/gpu/GrXferProcessor.h
+++ b/src/gpu/GrXferProcessor.h
@@ -108,32 +108,6 @@
     virtual GrGLSLXferProcessor* createGLSLInstance() const = 0;
 
     /**
-     * Optimizations for blending / coverage that an OptDrawState should apply to itself.
-     */
-    enum OptFlags {
-        /**
-         * GrXferProcessor will ignore color, thus no need to provide
-         */
-        kIgnoreColor_OptFlag = 0x1,
-        /**
-         * Can tweak alpha for coverage.
-         */
-        kCanTweakAlphaForCoverage_OptFlag = 0x2,
-    };
-
-    static const OptFlags kNone_OptFlags = (OptFlags)0;
-
-    GR_DECL_BITFIELD_OPS_FRIENDS(OptFlags);
-
-    /**
-     * Determines which optimizations (as described by the ptFlags above) can be performed by
-     * the draw with this xfer processor. If this function is called, the xfer processor may change
-     * its state to reflected the given blend optimizations. Callers are required to honor the
-     * returned OptFlags.
-     */
-    OptFlags getOptimizations(const FragmentProcessorAnalysis&) const;
-
-    /**
      * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType
      * is updated to contain the type of barrier needed.
      */
@@ -224,8 +198,6 @@
 private:
     void notifyRefCntIsZero() const final {}
 
-    virtual OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const = 0;
-
     /**
      * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer
      * processor's GL backend implementation.
@@ -265,10 +237,6 @@
     typedef GrFragmentProcessor INHERITED;
 };
 
-GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags);
-
-///////////////////////////////////////////////////////////////////////////////
-
 /**
  * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is
  * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the
@@ -305,22 +273,20 @@
                                          const DstTexture*,
                                          const GrCaps& caps) const;
 
-    /**
-    * This will return true if the xfer processor needs the dst color in the shader and the way
-    * that the color will be made available to the xfer processor is by sampling a texture.
-    */
-    static bool WillNeedDstTexture(const GrXPFactory*,
-                                   const GrCaps&,
-                                   const FragmentProcessorAnalysis&);
+    enum class AnalysisProperties : unsigned {
+        kNone = 0x0,
+        kReadsDstInShader = 0x1,
+        kRequiresDstTexture = 0x2,
+        kCompatibleWithAlphaAsCoverage = 0x4,
+        kIgnoresInputColor = 0x8,
+        kCanCombineOverlappedStencilAndCover = 0x10
+    };
+    GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties);
 
-    static bool CompatibleWithCoverageAsAlpha(const GrXPFactory*, bool colorIsOpaque);
-
-    /**
-     * This indicates whether the the xfer processor will produce the same bleneded color result
-     * if a series of overlapping stencil and cover operations are replaced by a series of stencil
-     * operations and a single cover. A uniform src color is assumed.
-     **/
-    static bool CanCombineOverlappedStencilAndCover(const GrXPFactory*, bool colorIsOpaque);
+    static AnalysisProperties GetAnalysisProperties(const GrXPFactory*,
+                                                    const GrPipelineAnalysisColor&,
+                                                    const GrPipelineAnalysisCoverage&,
+                                                    const GrCaps&);
 
 protected:
     constexpr GrXPFactory() {}
@@ -332,17 +298,17 @@
                                                    const DstTexture*) const = 0;
 
     /**
-     *  Returns true if the XP generated by this factory will explicitly read dst in the fragment
-     *  shader.
+     * Subclass analysis implementation. This should not return kNeedsDstInTexture as that will be
+     * inferred by the base class based on kReadsDstInShader and the caps.
      */
-    virtual bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const = 0;
-
-    virtual bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const = 0;
-    virtual bool canCombineOverlappedStencilAndCover(bool colorIsOpaque) const { return false; }
+    virtual AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
+                                                  const GrPipelineAnalysisCoverage&,
+                                                  const GrCaps&) const = 0;
 };
 #if defined(__GNUC__) || defined(__clang)
 #pragma GCC diagnostic pop
 #endif
 
-#endif
+GR_MAKE_BITFIELD_CLASS_OPS(GrXPFactory::AnalysisProperties);
 
+#endif
diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp
index 1013706..84219ae 100644
--- a/src/gpu/effects/GrCoverageSetOpXP.cpp
+++ b/src/gpu/effects/GrCoverageSetOpXP.cpp
@@ -33,8 +33,6 @@
 private:
     CoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage);
 
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override;
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
@@ -103,12 +101,6 @@
     return new GLCoverageSetOpXP(*this);
 }
 
-GrXferProcessor::OptFlags CoverageSetOpXP::onGetOptimizations(
-        const FragmentProcessorAnalysis&) const {
-    // We never look at the color input
-    return GrXferProcessor::kIgnoreColor_OptFlag;
-}
-
 void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const {
     switch (fRegionOp) {
         case SkRegion::kReplace_Op:
diff --git a/src/gpu/effects/GrCoverageSetOpXP.h b/src/gpu/effects/GrCoverageSetOpXP.h
index a0cb0c5..b7239f3 100644
--- a/src/gpu/effects/GrCoverageSetOpXP.h
+++ b/src/gpu/effects/GrCoverageSetOpXP.h
@@ -35,11 +35,12 @@
                                            bool hasMixedSamples,
                                            const DstTexture*) const override;
 
-    bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override {
-        return false;
+    AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
+                                          const GrPipelineAnalysisCoverage&,
+                                          const GrCaps&) const override {
+        return AnalysisProperties::kIgnoresInputColor;
     }
 
-    bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const override { return false; }
 
     GR_DECLARE_XP_FACTORY_TEST;
 
diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp
index 1f2771c..2e6d27c 100644
--- a/src/gpu/effects/GrCustomXfermode.cpp
+++ b/src/gpu/effects/GrCustomXfermode.cpp
@@ -98,8 +98,6 @@
     }
 
 private:
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override;
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const override;
@@ -189,11 +187,68 @@
     return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
 }
 
-GrXferProcessor::OptFlags CustomXP::onGetOptimizations(
-        const FragmentProcessorAnalysis& analysis) const {
-    /*
-      Most the optimizations we do here are based on tweaking alpha for coverage.
+GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const {
+    if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
+        return kBlend_GrXferBarrierType;
+    }
+    return kNone_GrXferBarrierType;
+}
 
+void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
+    if (this->hasHWBlendEquation()) {
+        blendInfo->fEquation = this->hwBlendEquation();
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+// See the comment above GrXPFactory's definition about this warning suppression.
+#if defined(__GNUC__) || defined(__clang)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+class CustomXPFactory : public GrXPFactory {
+public:
+    constexpr CustomXPFactory(SkBlendMode mode)
+            : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
+
+private:
+    GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
+                                           const FragmentProcessorAnalysis&,
+                                           bool hasMixedSamples,
+                                           const DstTexture*) const override;
+
+    AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
+                                          const GrPipelineAnalysisCoverage&,
+                                          const GrCaps&) const override;
+
+    GR_DECLARE_XP_FACTORY_TEST;
+
+    SkBlendMode fMode;
+    GrBlendEquation fHWBlendEquation;
+
+    typedef GrXPFactory INHERITED;
+};
+#if defined(__GNUC__) || defined(__clang)
+#pragma GCC diagnostic pop
+#endif
+
+GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
+                                                        const FragmentProcessorAnalysis& analysis,
+                                                        bool hasMixedSamples,
+                                                        const DstTexture* dstTexture) const {
+    SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
+    if (can_use_hw_blend_equation(fHWBlendEquation, analysis.outputCoverageType(), caps)) {
+        SkASSERT(!dstTexture || !dstTexture->texture());
+        return new CustomXP(fMode, fHWBlendEquation);
+    }
+    return new CustomXP(dstTexture, hasMixedSamples, fMode);
+}
+
+GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
+        const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage& coverage,
+        const GrCaps& caps) const {
+    /*
       The general SVG blend equation is defined in the spec as follows:
 
         Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
@@ -287,76 +342,12 @@
           = f*Sa - f*Sa * Da + Da
           = f*Sa + Da - f*Sa * Da
           = blend(f*Sa, Da)
-     */
-
-    OptFlags flags = kNone_OptFlags;
-    if (analysis.isCompatibleWithCoverageAsAlpha()) {
-        flags |= kCanTweakAlphaForCoverage_OptFlag;
+    */
+    if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
+        return AnalysisProperties::kCompatibleWithAlphaAsCoverage;
     }
-    return flags;
-}
-
-GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const {
-    if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
-        return kBlend_GrXferBarrierType;
-    }
-    return kNone_GrXferBarrierType;
-}
-
-void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
-    if (this->hasHWBlendEquation()) {
-        blendInfo->fEquation = this->hwBlendEquation();
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// See the comment above GrXPFactory's definition about this warning suppression.
-#if defined(__GNUC__) || defined(__clang)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
-#endif
-class CustomXPFactory : public GrXPFactory {
-public:
-    constexpr CustomXPFactory(SkBlendMode mode)
-            : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
-
-private:
-    GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
-                                           const FragmentProcessorAnalysis&,
-                                           bool hasMixedSamples,
-                                           const DstTexture*) const override;
-
-    bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override;
-
-    bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const override { return true; }
-
-    GR_DECLARE_XP_FACTORY_TEST;
-
-    SkBlendMode     fMode;
-    GrBlendEquation fHWBlendEquation;
-
-    typedef GrXPFactory INHERITED;
-};
-#if defined(__GNUC__) || defined(__clang)
-#pragma GCC diagnostic pop
-#endif
-
-GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
-                                                        const FragmentProcessorAnalysis& analysis,
-                                                        bool hasMixedSamples,
-                                                        const DstTexture* dstTexture) const {
-    SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
-    if (can_use_hw_blend_equation(fHWBlendEquation, analysis.outputCoverageType(), caps)) {
-        SkASSERT(!dstTexture || !dstTexture->texture());
-        return new CustomXP(fMode, fHWBlendEquation);
-    }
-    return new CustomXP(dstTexture, hasMixedSamples, fMode);
-}
-
-bool CustomXPFactory::willReadDstInShader(const GrCaps& caps,
-                                          const FragmentProcessorAnalysis& analysis) const {
-    return !can_use_hw_blend_equation(fHWBlendEquation, analysis.outputCoverageType(), caps);
+    return AnalysisProperties::kCompatibleWithAlphaAsCoverage |
+           AnalysisProperties::kReadsDstInShader;
 }
 
 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp
index f95cd9b..2268097 100644
--- a/src/gpu/effects/GrDisableColorXP.cpp
+++ b/src/gpu/effects/GrDisableColorXP.cpp
@@ -29,10 +29,6 @@
 private:
     DisableColorXP();
 
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override {
-        return GrXferProcessor::kIgnoreColor_OptFlag;
-    }
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override;
diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h
index 821ad27..9a829ed 100644
--- a/src/gpu/effects/GrDisableColorXP.h
+++ b/src/gpu/effects/GrDisableColorXP.h
@@ -24,12 +24,13 @@
 private:
     constexpr GrDisableColorXPFactory() {}
 
-    bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override {
-        return false;
+    AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
+                                          const GrPipelineAnalysisCoverage&,
+                                          const GrCaps&) const override {
+        return AnalysisProperties::kCompatibleWithAlphaAsCoverage |
+               AnalysisProperties::kIgnoresInputColor;
     }
 
-    bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const override { return true; }
-
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const FragmentProcessorAnalysis&,
                                            bool hasMixedSamples,
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index aa416e0..98268a2 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -83,7 +83,7 @@
          (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
             kUsesInputColor_Property : 0) |  // We assert later that SrcCoeff doesn't ref src2.
 
-        (kModulate_OutputType == PrimaryOut &&
+        ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
          kNone_OutputType == SecondaryOut &&
          GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
             kCanTweakAlphaForCoverage_Property : 0))> {
@@ -349,8 +349,6 @@
     BlendFormula getBlendFormula() const { return fBlendFormula; }
 
 private:
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override;
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
@@ -445,24 +443,6 @@
     return new GLPorterDuffXferProcessor;
 }
 
-GrXferProcessor::OptFlags PorterDuffXferProcessor::onGetOptimizations(
-        const FragmentProcessorAnalysis& analysis) const {
-    GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
-    if (!fBlendFormula.modifiesDst()) {
-        optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
-                     GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
-    } else {
-        if (!fBlendFormula.usesInputColor()) {
-            optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
-        }
-        if (analysis.isCompatibleWithCoverageAsAlpha() &&
-            fBlendFormula.canTweakAlphaForCoverage()) {
-            optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
-        }
-    }
-    return optFlags;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 class ShaderPDXferProcessor : public GrXferProcessor {
@@ -482,10 +462,6 @@
     SkBlendMode getXfermode() const { return fXfermode; }
 
 private:
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override {
-        return kNone_OptFlags;
-    }
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     bool onIsEqual(const GrXferProcessor& xpBase) const override {
@@ -558,8 +534,6 @@
 private:
     PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
 
-    GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override;
-
     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
 
     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
@@ -655,11 +629,6 @@
     return new GLPDLCDXferProcessor(*this);
 }
 
-GrXferProcessor::OptFlags PDLCDXferProcessor::onGetOptimizations(
-        const FragmentProcessorAnalysis&) const {
-    return GrXferProcessor::kIgnoreColor_OptFlag;
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
@@ -758,42 +727,53 @@
     return new PorterDuffXferProcessor(blendFormula);
 }
 
-bool GrPorterDuffXPFactory::canCombineOverlappedStencilAndCover(bool colorIsOpaque) const {
-    // Ignore the effect of coverage here.
-    BlendFormula colorFormula = gBlendTable[colorIsOpaque][0][(int)fBlendMode];
-    SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
-    return !colorFormula.usesDstColor();
-}
-
-bool GrPorterDuffXPFactory::willReadDstInShader(const GrCaps& caps,
-                                                const FragmentProcessorAnalysis& analysis) const {
-    if (caps.shaderCaps()->dualSourceBlendingSupport()) {
-        return false;
+static inline GrXPFactory::AnalysisProperties analysis_properties(
+        const GrPipelineAnalysisColor& color, const GrPipelineAnalysisCoverage& coverage,
+        const GrCaps& caps, SkBlendMode mode) {
+    using AnalysisProperties = GrXPFactory::AnalysisProperties;
+    AnalysisProperties props = AnalysisProperties::kNone;
+    bool hasCoverage = GrPipelineAnalysisCoverage::kNone != coverage;
+    auto formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
+    if (formula.canTweakAlphaForCoverage()) {
+        props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage;
     }
-
-    // When we have four channel coverage we always need to read the dst in order to correctly
-    // blend. The one exception is when we are using srcover mode and we know the input color into
-    // the XP.
-    if (analysis.outputCoverageType() == GrPipelineAnalysisCoverage::kLCD) {
-        if (SkBlendMode::kSrcOver == fBlendMode && analysis.hasKnownOutputColor() &&
-            !caps.shaderCaps()->dstReadInShaderSupport()) {
-            return false;
+    // With dual-source blending we never need the destination color in the shader.
+    if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
+        // Mixed samples implicity computes a fractional coverage from sample coverage. This could
+        // affect the formula used. However, we don't expect to have mixed samples without dual
+        // source blending.
+        SkASSERT(!caps.usesMixedSamples());
+        if (GrPipelineAnalysisCoverage::kLCD == coverage) {
+            // Check for special case of srcover with a known color which can be done using the
+            // blend constant.
+            if (SkBlendMode::kSrcOver == mode && color.isConstant()) {
+                props |= AnalysisProperties::kIgnoresInputColor;
+            } else {
+                if (get_lcd_blend_formula(mode).hasSecondaryOutput()) {
+                    props |= AnalysisProperties::kReadsDstInShader;
+                }
+            }
+        } else if (formula.hasSecondaryOutput()) {
+            props |= AnalysisProperties::kReadsDstInShader;
         }
-        return get_lcd_blend_formula(fBlendMode).hasSecondaryOutput();
     }
-
-    // We fallback on the shader XP when the blend formula would use dual source blending but we
-    // don't have support for it.
-    static const bool kHasMixedSamples = false;
-    SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending.
-    auto formula = get_blend_formula(analysis.isOutputColorOpaque(), analysis.hasCoverage(),
-                                     kHasMixedSamples, fBlendMode);
-    return formula.hasSecondaryOutput();
+    if (!formula.modifiesDst() || !formula.usesInputColor()) {
+        props |= AnalysisProperties::kIgnoresInputColor;
+    }
+    // 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);
+    if (!colorFormula.usesDstColor()) {
+        props |= AnalysisProperties::kCanCombineOverlappedStencilAndCover;
+    }
+    return props;
 }
 
-bool GrPorterDuffXPFactory::compatibleWithCoverageAsAlpha(bool colorIsOpaque) const {
-    // We assume we have coverage (or else this doesn't matter).
-    return gBlendTable[colorIsOpaque][1][(int)fBlendMode].canTweakAlphaForCoverage();
+GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
+        const GrPipelineAnalysisColor& color,
+        const GrPipelineAnalysisCoverage& coverage,
+        const GrCaps& caps) const {
+    return analysis_properties(color, coverage, caps, fBlendMode);
 }
 
 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
@@ -869,31 +849,9 @@
     return sk_make_sp<PorterDuffXferProcessor>(formula);
 }
 
-bool GrPorterDuffXPFactory::WillSrcOverNeedDstTexture(const GrCaps& caps,
-                                                      const FragmentProcessorAnalysis& analysis) {
-    if (caps.shaderCaps()->dstReadInShaderSupport() ||
-        caps.shaderCaps()->dualSourceBlendingSupport()) {
-        return false;
-    }
-
-    // When we have four channel coverage we always need to read the dst in order to correctly
-    // blend. The one exception is when we are using srcover mode and we know the input color
-    // into the XP.
-    if (analysis.outputCoverageType() == GrPipelineAnalysisCoverage::kLCD) {
-        if (analysis.hasKnownOutputColor() && !caps.shaderCaps()->dstReadInShaderSupport()) {
-            return false;
-        }
-        auto formula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
-        return formula.hasSecondaryOutput();
-    }
-
-    // We fallback on the shader XP when the blend formula would use dual source blending but we
-    // don't have support for it.
-    static const bool kHasMixedSamples = false;
-    bool isOpaque = analysis.isOutputColorOpaque();
-    bool hasCoverage = analysis.hasCoverage();
-    SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending.
-    auto formula =
-            get_blend_formula(isOpaque, hasCoverage, kHasMixedSamples, SkBlendMode::kSrcOver);
-    return formula.hasSecondaryOutput();
+GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
+        const GrPipelineAnalysisColor& color,
+        const GrPipelineAnalysisCoverage& coverage,
+        const GrCaps& caps) {
+    return analysis_properties(color, coverage, caps, SkBlendMode::kSrcOver);
 }
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.h b/src/gpu/effects/GrPorterDuffXferProcessor.h
index 23f1e9c..81e8261 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.h
@@ -35,25 +35,21 @@
         by reference because it is global and its ref-cnting methods are not thread safe. */
     static const GrXferProcessor& SimpleSrcOverXP();
 
-    static bool WillSrcOverNeedDstTexture(const GrCaps&, const FragmentProcessorAnalysis&);
-    static bool SrcOverIsCompatibleWithCoverageAsAlpha() { return true; }
-    static bool SrcOverCanCombineOverlappedStencilAndCover(bool colorIsOpaque) {
-        return colorIsOpaque;
-    }
+    static AnalysisProperties SrcOverAnalysisProperties(const GrPipelineAnalysisColor&,
+                                                        const GrPipelineAnalysisCoverage&,
+                                                        const GrCaps&);
 
 private:
     constexpr GrPorterDuffXPFactory(SkBlendMode);
 
-    bool canCombineOverlappedStencilAndCover(bool colorIsOpaque) const override;
-
     GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
                                            const FragmentProcessorAnalysis&,
                                            bool hasMixedSamples,
                                            const DstTexture*) const override;
 
-    bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override;
-
-    bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const override;
+    AnalysisProperties analysisProperties(const GrPipelineAnalysisColor&,
+                                          const GrPipelineAnalysisCoverage&,
+                                          const GrCaps&) const override;
 
     GR_DECLARE_XP_FACTORY_TEST;
     static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary);
diff --git a/src/gpu/instanced/InstancedRendering.cpp b/src/gpu/instanced/InstancedRendering.cpp
index e67a8be..d75af35 100644
--- a/src/gpu/instanced/InstancedRendering.cpp
+++ b/src/gpu/instanced/InstancedRendering.cpp
@@ -367,13 +367,10 @@
         SkASSERT(State::kRecordingDraws == fInstancedRendering->fState);
         this->getSingleDraw().fInstance.fColor = overrideColor;
     }
-    fInfo.fCannotTweakAlphaForCoverage =
-            !analysis.isCompatibleWithCoverageAsAlpha() ||
-            !GrXPFactory::CompatibleWithCoverageAsAlpha(fProcessors.xpFactory(),
-                                                        analysis.isOutputColorOpaque());
+    fInfo.fCannotTweakAlphaForCoverage = !analysis.isCompatibleWithCoverageAsAlpha();
 
     fInfo.fUsesLocalCoords = analysis.usesLocalCoords();
-    return GrXPFactory::WillNeedDstTexture(fProcessors.xpFactory(), caps, analysis);
+    return analysis.requiresDstTexture();
 }
 
 void InstancedRendering::Op::wasRecorded() {
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index fa08ae6..0a3df45 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -148,13 +148,7 @@
         GrPathRendering::kWinding_FillType != that->fillType()) {
         return false;
     }
-    // If we have non-clipping coverage processors we don't try to merge as its unclear whether it
-    // will be correct. We don't expect this to happen in practice.
-    if (this->processors().numCoverageFragmentProcessors()) {
-        return false;
-    }
-    bool opaque = this->fragmentProcessorAnalysis().isOutputColorOpaque();
-    if (!GrXPFactory::CanCombineOverlappedStencilAndCover(this->processors().xpFactory(), opaque)) {
+    if (!this->fragmentProcessorAnalysis().canCombineOverlappedStencilAndCover()) {
         return false;
     }
     fTotalPathCount += that->fTotalPathCount;
diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h
index b1ce2df..5650b88 100644
--- a/src/gpu/ops/GrDrawPathOp.h
+++ b/src/gpu/ops/GrDrawPathOp.h
@@ -29,8 +29,7 @@
         return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
     }
     bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override {
-        return GrXPFactory::WillNeedDstTexture(fProcessorSet.xpFactory(), caps,
-                                               this->doFragmentProcessorAnalysis(caps, clip));
+        return this->doFragmentProcessorAnalysis(caps, clip).requiresDstTexture();
     }
 
     void wasRecorded() override { fProcessorSet.makePendingExecution(); }