diff options
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/GrPipeline.cpp | 47 | ||||
-rw-r--r-- | src/gpu/GrPipelineAnalysis.h | 6 | ||||
-rw-r--r-- | src/gpu/GrPipelineBuilder.h | 14 | ||||
-rw-r--r-- | src/gpu/GrProcessorSet.cpp | 50 | ||||
-rw-r--r-- | src/gpu/GrProcessorSet.h | 20 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 2 | ||||
-rw-r--r-- | src/gpu/GrXferProcessor.cpp | 41 | ||||
-rw-r--r-- | src/gpu/GrXferProcessor.h | 74 | ||||
-rw-r--r-- | src/gpu/effects/GrCoverageSetOpXP.cpp | 8 | ||||
-rw-r--r-- | src/gpu/effects/GrCoverageSetOpXP.h | 7 | ||||
-rw-r--r-- | src/gpu/effects/GrCustomXfermode.cpp | 141 | ||||
-rw-r--r-- | src/gpu/effects/GrDisableColorXP.cpp | 4 | ||||
-rw-r--r-- | src/gpu/effects/GrDisableColorXP.h | 9 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.cpp | 140 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.h | 16 | ||||
-rw-r--r-- | src/gpu/instanced/InstancedRendering.cpp | 7 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawPathOp.cpp | 8 | ||||
-rw-r--r-- | src/gpu/ops/GrDrawPathOp.h | 3 |
18 files changed, 254 insertions, 343 deletions
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp index adcdd0fe02..d8f7fbdbf8 100644 --- a/src/gpu/GrPipeline.cpp +++ b/src/gpu/GrPipeline.cpp @@ -52,37 +52,32 @@ GrPipelineOptimizations GrPipeline::init(const InitArgs& args) { 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 @@ GrPipelineOptimizations GrPipeline::init(const InitArgs& args) { 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 4f553b0ce5..d55ff0a34c 100644 --- a/src/gpu/GrPipelineAnalysis.h +++ b/src/gpu/GrPipelineAnalysis.h @@ -41,9 +41,11 @@ public: 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 17dfe90ddd..7451b655b1 100644 --- a/src/gpu/GrPipelineBuilder.h +++ b/src/gpu/GrPipelineBuilder.h @@ -65,20 +65,6 @@ public: /// @} - /////////////////////////////////////////////////////////////////////////// - /// @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 4a508921b1..0350ba5758 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 @@ void GrProcessorSet::FragmentProcessorAnalysis::internalInit( 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 @@ void GrProcessorSet::FragmentProcessorAnalysis::internalInit( // 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 @@ void GrProcessorSet::FragmentProcessorAnalysis::internalInit( 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 @@ void GrProcessorSet::FragmentProcessorAnalysis::init(const GrPipelineAnalysisCol 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 bfad769a18..e584a94709 100644 --- a/src/gpu/GrProcessorSet.h +++ b/src/gpu/GrProcessorSet.h @@ -79,13 +79,16 @@ public: : 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 @@ public: } 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 @@ public: 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 70d4485468..79ae757b34 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1743,7 +1743,7 @@ uint32_t GrRenderTargetContext::addMeshDrawOp(const GrPipelineBuilder& pipelineB 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 bd63a0a40b..45bcc2d595 100644 --- a/src/gpu/GrXferProcessor.cpp +++ b/src/gpu/GrXferProcessor.cpp @@ -29,11 +29,6 @@ GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture, } } -GrXferProcessor::OptFlags GrXferProcessor::getOptimizations( - const FragmentProcessorAnalysis& analysis) const { - return this->onGetOptimizations(analysis); -} - bool GrXferProcessor::hasSecondaryOutput() const { if (!this->willReadDstColor()) { return this->onHasSecondaryOutput(); @@ -175,31 +170,23 @@ SkString GrXferProcessor::BlendInfo::dump() const { /////////////////////////////////////////////////////////////////////////////// -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); } - return result; -} - -bool GrXPFactory::CompatibleWithCoverageAsAlpha(const GrXPFactory* factory, bool colorIsOpaque) { - if (factory) { - return factory->compatibleWithCoverageAsAlpha(colorIsOpaque); + SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture)); + if ((result & AnalysisProperties::kReadsDstInShader) && + !caps.shaderCaps()->dstReadInShaderSupport()) { + result |= AnalysisProperties::kRequiresDstTexture; } - return GrPorterDuffXPFactory::SrcOverIsCompatibleWithCoverageAsAlpha(); -} - -bool GrXPFactory::CanCombineOverlappedStencilAndCover(const GrXPFactory* factory, - bool colorIsOpaque) { - if (factory) { - return factory->canCombineOverlappedStencilAndCover(colorIsOpaque); - } - return GrPorterDuffXPFactory::SrcOverCanCombineOverlappedStencilAndCover(colorIsOpaque); + return result; } GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysis& analysis, @@ -207,7 +194,7 @@ GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysi 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 bdf6f7d50c..54630af750 100644 --- a/src/gpu/GrXferProcessor.h +++ b/src/gpu/GrXferProcessor.h @@ -108,32 +108,6 @@ public: 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 @@ protected: 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 @@ private: 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 @@ public: 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 @@ private: 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 1013706842..84219aef11 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -33,8 +33,6 @@ public: 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 @@ GrGLSLXferProcessor* CoverageSetOpXP::createGLSLInstance() const { 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 a0cb0c518c..b7239f3a19 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.h +++ b/src/gpu/effects/GrCoverageSetOpXP.h @@ -35,11 +35,12 @@ private: 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 1f2771cb52..2e6d27cdfa 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -98,8 +98,6 @@ public: } 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 @@ bool CustomXP::onIsEqual(const GrXferProcessor& other) const { 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 @@ GrXferProcessor::OptFlags CustomXP::onGetOptimizations( = 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 f95cd9b81a..226809725c 100644 --- a/src/gpu/effects/GrDisableColorXP.cpp +++ b/src/gpu/effects/GrDisableColorXP.cpp @@ -29,10 +29,6 @@ public: 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 821ad2768e..9a829ed5ba 100644 --- a/src/gpu/effects/GrDisableColorXP.h +++ b/src/gpu/effects/GrDisableColorXP.h @@ -24,12 +24,13 @@ public: 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 aa416e0d1b..98268a2c5f 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -83,7 +83,7 @@ public: (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 @@ public: 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 @@ GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const { 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 @@ public: 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 @@ public: 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 @@ GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const { return new GLPDLCDXferProcessor(*this); } -GrXferProcessor::OptFlags PDLCDXferProcessor::onGetOptimizations( - const FragmentProcessorAnalysis&) const { - return GrXferProcessor::kIgnoreColor_OptFlag; -} - /////////////////////////////////////////////////////////////////////////////// constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode) @@ -758,42 +727,53 @@ GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor( 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; - } - - // 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; +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; + } + // 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 @@ sk_sp<GrXferProcessor> GrPorterDuffXPFactory::CreateNoCoverageXP(SkBlendMode ble 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 23f1e9c5c5..81e8261724 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.h +++ b/src/gpu/effects/GrPorterDuffXferProcessor.h @@ -35,25 +35,21 @@ public: 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 e67a8be977..d75af35dab 100644 --- a/src/gpu/instanced/InstancedRendering.cpp +++ b/src/gpu/instanced/InstancedRendering.cpp @@ -367,13 +367,10 @@ bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAp 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 fa08ae6d54..0a3df45cae 100644 --- a/src/gpu/ops/GrDrawPathOp.cpp +++ b/src/gpu/ops/GrDrawPathOp.cpp @@ -148,13 +148,7 @@ bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) { 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 b1ce2dfe5a..5650b888ba 100644 --- a/src/gpu/ops/GrDrawPathOp.h +++ b/src/gpu/ops/GrDrawPathOp.h @@ -29,8 +29,7 @@ protected: 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(); } |