From 0ae0e23696f2ef08503040f8c02765eb58b26ddf Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Fri, 7 Apr 2017 15:37:58 -0400 Subject: Create GrXferProcessor while doing GrProcessorSet analysis. Bug: skia: Change-Id: I62a628f9c0536ffb05c8f9d0c9ded5657f93b48e Reviewed-on: https://skia-review.googlesource.com/11482 Reviewed-by: Greg Daniel Commit-Queue: Brian Salomon --- src/gpu/GrPipeline.cpp | 13 +- src/gpu/GrPipeline.h | 4 +- src/gpu/GrPipelineBuilder.h | 12 +- src/gpu/GrProcessorSet.cpp | 186 +++++++++++--------------- src/gpu/GrProcessorSet.h | 169 ++++++++--------------- src/gpu/GrRenderTargetContext.cpp | 15 ++- src/gpu/instanced/InstancedRendering.cpp | 31 +---- src/gpu/instanced/InstancedRendering.h | 1 - src/gpu/ops/GrDrawOp.h | 3 +- src/gpu/ops/GrDrawPathOp.cpp | 19 ++- src/gpu/ops/GrDrawPathOp.h | 45 ++++--- src/gpu/ops/GrMeshDrawOp.h | 24 ++-- src/gpu/ops/GrStencilAndCoverPathRenderer.cpp | 3 +- src/gpu/text/GrStencilAndCoverTextContext.cpp | 13 +- src/gpu/text/GrStencilAndCoverTextContext.h | 2 +- 15 files changed, 221 insertions(+), 319 deletions(-) (limited to 'src/gpu') diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp index 759f97ce2c..d1f5931d9a 100644 --- a/src/gpu/GrPipeline.cpp +++ b/src/gpu/GrPipeline.cpp @@ -20,6 +20,8 @@ void GrPipeline::init(const InitArgs& args) { SkASSERT(args.fRenderTarget); + SkASSERT(args.fProcessors); + SkASSERT(args.fProcessors->isFinalized()); fRenderTarget.reset(args.fRenderTarget); @@ -48,17 +50,8 @@ void GrPipeline::init(const InitArgs& args) { fDrawFace = static_cast(args.fDrawFace); - bool isHWAA = kHWAntialias_Flag & args.fFlags; + fXferProcessor.reset(args.fProcessors->xferProcessor()); - // Create XferProcessor from DS's XPFactory - { - bool hasMixedSamples = - args.fRenderTarget->isMixedSampled() && (isHWAA || this->isStencilEnabled()); - sk_sp xferProcessor = - GrXPFactory::MakeXferProcessor(args.fProcessors->xpFactory(), args.fXPInputColor, - args.fXPInputCoverage, hasMixedSamples, *args.fCaps); - fXferProcessor.reset(xferProcessor.get()); - } if (args.fDstTexture.texture()) { fDstTexture.reset(args.fDstTexture.texture()); fDstTextureOffset = args.fDstTexture.offset(); diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h index 02a14af889..a2a332fc36 100644 --- a/src/gpu/GrPipeline.h +++ b/src/gpu/GrPipeline.h @@ -56,9 +56,7 @@ public: struct InitArgs { uint32_t fFlags = 0; GrDrawFace fDrawFace = GrDrawFace::kBoth; - const GrProcessorSet* fProcessors = nullptr; - GrProcessorAnalysisColor fXPInputColor; - GrProcessorAnalysisCoverage fXPInputCoverage = GrProcessorAnalysisCoverage::kNone; + const GrProcessorSet* fProcessors = nullptr; // Must be finalized const GrUserStencilSettings* fUserStencil = &GrUserStencilSettings::kUnused; const GrAppliedClip* fAppliedClip = nullptr; GrRenderTarget* fRenderTarget = nullptr; diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h index 94e07e6cd8..78aead0f89 100644 --- a/src/gpu/GrPipelineBuilder.h +++ b/src/gpu/GrPipelineBuilder.h @@ -63,12 +63,12 @@ public: const GrProcessorSet& processors() const { return fProcessors; } - void analyzeAndEliminateFragmentProcessors(GrProcessorSet::Analysis* analysis, - const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrAppliedClip* clip, const GrCaps& caps) { - fProcessors.analyzeAndEliminateFragmentProcessors(analysis, colorInput, coverageInput, clip, - caps); + GrProcessorSet::Analysis finalizeProcessors(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, + const GrAppliedClip* clip, bool isMixedSamples, + const GrCaps& caps, GrColor* overrideColor) { + return fProcessors.finalize(colorInput, coverageInput, clip, isMixedSamples, caps, + overrideColor); } /// @} diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp index 8bdf6b63d1..93617649a3 100644 --- a/src/gpu/GrProcessorSet.cpp +++ b/src/gpu/GrProcessorSet.cpp @@ -9,9 +9,9 @@ #include "GrAppliedClip.h" #include "GrCaps.h" #include "GrXferProcessor.h" +#include "effects/GrPorterDuffXferProcessor.h" -GrProcessorSet::GrProcessorSet(GrPaint&& paint) { - fXPFactory = paint.fXPFactory; +GrProcessorSet::GrProcessorSet(GrPaint&& paint) : fXP(paint.getXPFactory()) { fFlags = 0; if (paint.numColorFragmentProcessors() <= kMaxColorProcessors) { fColorFragmentProcessorCnt = paint.numColorFragmentProcessors(); @@ -40,27 +40,22 @@ GrProcessorSet::GrProcessorSet(GrPaint&& paint) { GrProcessorSet::~GrProcessorSet() { for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) { - if (this->isPendingExecution()) { + if (this->isFinalized()) { fFragmentProcessors[i]->completedExecution(); } else { fFragmentProcessors[i]->unref(); } } -} - -void GrProcessorSet::makePendingExecution() { - SkASSERT(!(kPendingExecution_Flag & fFlags)); - fFlags |= kPendingExecution_Flag; - for (int i = fFragmentProcessorOffset; i < fFragmentProcessors.count(); ++i) { - fFragmentProcessors[i]->addPendingExecution(); - fFragmentProcessors[i]->unref(); + if (this->isFinalized() && this->xferProcessor()) { + this->xferProcessor()->completedExecution(); } } bool GrProcessorSet::operator==(const GrProcessorSet& that) const { + SkASSERT(this->isFinalized()); + SkASSERT(that.isFinalized()); int fpCount = this->numFragmentProcessors(); - if (((fFlags ^ that.fFlags) & ~kPendingExecution_Flag) || - fpCount != that.numFragmentProcessors() || + if (((fFlags ^ that.fFlags) & ~kFinalized_Flag) || fpCount != that.numFragmentProcessors() || fColorFragmentProcessorCnt != that.fColorFragmentProcessorCnt) { return false; } @@ -72,34 +67,43 @@ bool GrProcessorSet::operator==(const GrProcessorSet& that) const { return false; } } - if (fXPFactory != that.fXPFactory) { - return false; + // Most of the time both of these are null + if (!this->xferProcessor() && !that.xferProcessor()) { + return true; } - return true; + const GrXferProcessor& thisXP = this->xferProcessor() + ? *this->xferProcessor() + : GrPorterDuffXPFactory::SimpleSrcOverXP(); + const GrXferProcessor& thatXP = that.xferProcessor() + ? *that.xferProcessor() + : GrPorterDuffXPFactory::SimpleSrcOverXP(); + return thisXP.isEqual(thatXP); } -////////////////////////////////////////////////////////////////////////////// - -void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrProcessorSet& processors, - const GrFragmentProcessor* clipFP, - const GrCaps& caps) { - GrColorFragmentProcessorAnalysis colorInfo(colorInput); - fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput; - fValidInputColor = colorInput.isConstant(&fInputColor); - - const GrFragmentProcessor* const* fps = - processors.fFragmentProcessors.get() + processors.fFragmentProcessorOffset; - colorInfo.analyzeProcessors(fps, processors.fColorFragmentProcessorCnt); - fCompatibleWithCoverageAsAlpha &= colorInfo.allProcessorsCompatibleWithCoverageAsAlpha(); - fps += processors.fColorFragmentProcessorCnt; - int n = processors.numCoverageFragmentProcessors(); +GrProcessorSet::Analysis GrProcessorSet::finalize(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, + const GrAppliedClip* clip, bool isMixedSamples, + const GrCaps& caps, GrColor* overrideInputColor) { + SkASSERT(!this->isFinalized()); + SkASSERT(!fFragmentProcessorOffset); + + GrProcessorSet::Analysis analysis; + + const GrFragmentProcessor* clipFP = clip ? clip->clipCoverageFragmentProcessor() : nullptr; + GrColorFragmentProcessorAnalysis colorAnalysis(colorInput); + analysis.fCompatibleWithCoverageAsAlpha = GrProcessorAnalysisCoverage::kLCD != coverageInput; + + const GrFragmentProcessor* const* fps = fFragmentProcessors.get() + fFragmentProcessorOffset; + colorAnalysis.analyzeProcessors(fps, fColorFragmentProcessorCnt); + analysis.fCompatibleWithCoverageAsAlpha &= + colorAnalysis.allProcessorsCompatibleWithCoverageAsAlpha(); + fps += fColorFragmentProcessorCnt; + int n = this->numCoverageFragmentProcessors(); bool hasCoverageFP = n > 0; bool coverageUsesLocalCoords = false; for (int i = 0; i < n; ++i) { if (!fps[i]->compatibleWithCoverageAsAlpha()) { - fCompatibleWithCoverageAsAlpha = false; + analysis.fCompatibleWithCoverageAsAlpha = false; // Other than tests that exercise atypical behavior we expect all coverage FPs to be // compatible with the coverage-as-alpha optimization. GrCapsDebugf(&caps, "Coverage FP is not compatible with coverage as alpha.\n"); @@ -108,21 +112,14 @@ void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colo } if (clipFP) { - fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha(); + analysis.fCompatibleWithCoverageAsAlpha &= clipFP->compatibleWithCoverageAsAlpha(); coverageUsesLocalCoords |= clipFP->usesLocalCoords(); hasCoverageFP = true; } - fInitialColorProcessorsToEliminate = colorInfo.initialProcessorsToEliminate(&fInputColor); - fValidInputColor |= SkToBool(fInitialColorProcessorsToEliminate); - - GrProcessorAnalysisColor outputColor = colorInfo.outputColor(); - if (outputColor.isConstant(&fKnownOutputColor)) { - fOutputColorType = static_cast(ColorType::kConstant); - } else if (outputColor.isOpaque()) { - fOutputColorType = static_cast(ColorType::kOpaque); - } else { - fOutputColorType = static_cast(ColorType::kUnknown); - } + int colorFPsToEliminate = colorAnalysis.initialProcessorsToEliminate(overrideInputColor); + analysis.fInputColorType = static_cast( + colorFPsToEliminate ? Analysis::kOverridden_InputColorType + : Analysis::kOriginal_InputColorType); GrProcessorAnalysisCoverage outputCoverage; if (GrProcessorAnalysisCoverage::kLCD == coverageInput) { @@ -132,82 +129,51 @@ void GrProcessorSet::Analysis::internalInit(const GrProcessorAnalysisColor& colo } else { outputCoverage = GrProcessorAnalysisCoverage::kNone; } - fOutputCoverageType = static_cast(outputCoverage); GrXPFactory::AnalysisProperties props = GrXPFactory::GetAnalysisProperties( - processors.fXPFactory, colorInfo.outputColor(), outputCoverage, caps); - if (!processors.numCoverageFragmentProcessors() && + this->xpFactory(), colorAnalysis.outputColor(), outputCoverage, caps); + if (!this->numCoverageFragmentProcessors() && GrProcessorAnalysisCoverage::kNone == coverageInput) { - fCanCombineOverlappedStencilAndCover = SkToBool( + analysis.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; + analysis.fCanCombineOverlappedStencilAndCover = false; } - fRequiresDstTexture = SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture); - fIgnoresInputColor = SkToBool(props & GrXPFactory::AnalysisProperties::kIgnoresInputColor); - fCompatibleWithCoverageAsAlpha &= + analysis.fRequiresDstTexture = + SkToBool(props & GrXPFactory::AnalysisProperties::kRequiresDstTexture); + analysis.fCompatibleWithCoverageAsAlpha &= SkToBool(props & GrXPFactory::AnalysisProperties::kCompatibleWithAlphaAsCoverage); - fRequiresBarrierBetweenOverlappingDraws = SkToBool( + analysis.fRequiresBarrierBetweenOverlappingDraws = SkToBool( props & GrXPFactory::AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws); 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; + colorFPsToEliminate = this->numColorFragmentProcessors(); + analysis.fInputColorType = + static_cast(Analysis::kIgnored_InputColorType); + analysis.fUsesLocalCoords = coverageUsesLocalCoords; } else { - fUsesLocalCoords = coverageUsesLocalCoords | colorInfo.usesLocalCoords(); + analysis.fUsesLocalCoords = coverageUsesLocalCoords | colorAnalysis.usesLocalCoords(); } -} - -void GrProcessorSet::Analysis::init(const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrProcessorSet& processors, - const GrAppliedClip* appliedClip, - const GrCaps& caps) { - const GrFragmentProcessor* clipFP = - appliedClip ? appliedClip->clipCoverageFragmentProcessor() : nullptr; - this->internalInit(colorInput, coverageInput, processors, clipFP, caps); - fIsInitializedWithProcessorSet = true; -} - -GrProcessorSet::Analysis::Analysis(const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrXPFactory* factory, - const GrCaps& caps) - : Analysis() { - GrPaint paint; - paint.setXPFactory(factory); - this->internalInit(colorInput, coverageInput, GrProcessorSet(std::move(paint)), nullptr, caps); -} - -void GrProcessorSet::analyzeAndEliminateFragmentProcessors( - Analysis* analysis, - const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrAppliedClip* clip, - const GrCaps& caps) { - analysis->init(colorInput, coverageInput, *this, clip, caps); - if (analysis->fInitialColorProcessorsToEliminate > 0) { - for (unsigned i = 0; i < analysis->fInitialColorProcessorsToEliminate; ++i) { - if (this->isPendingExecution()) { - fFragmentProcessors[i + fFragmentProcessorOffset]->completedExecution(); - } else { - fFragmentProcessors[i + fFragmentProcessorOffset]->unref(); - } - fFragmentProcessors[i + fFragmentProcessorOffset] = nullptr; - } - fFragmentProcessorOffset += analysis->fInitialColorProcessorsToEliminate; - fColorFragmentProcessorCnt -= analysis->fInitialColorProcessorsToEliminate; - SkASSERT(fFragmentProcessorOffset + fColorFragmentProcessorCnt <= - fFragmentProcessors.count()); - analysis->fInitialColorProcessorsToEliminate = 0; + for (int i = 0; i < colorFPsToEliminate; ++i) { + fFragmentProcessors[i]->unref(); + fFragmentProcessors[i] = nullptr; + } + for (int i = colorFPsToEliminate; i < fFragmentProcessors.count(); ++i) { + fFragmentProcessors[i]->addPendingExecution(); + fFragmentProcessors[i]->unref(); + } + fFragmentProcessorOffset = colorFPsToEliminate; + fColorFragmentProcessorCnt -= colorFPsToEliminate; + + auto xp = GrXPFactory::MakeXferProcessor(this->xpFactory(), colorAnalysis.outputColor(), + outputCoverage, isMixedSamples, caps); + fXP.fProcessor = xp.get(); + if (fXP.fProcessor) { + fXP.fProcessor->addPendingExecution(); } + fFlags |= kFinalized_Flag; + + analysis.fIsInitialized = true; + return analysis; } diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h index 39ba0137b8..289ca1bcae 100644 --- a/src/gpu/GrProcessorSet.h +++ b/src/gpu/GrProcessorSet.h @@ -14,6 +14,7 @@ #include "SkTemplates.h" class GrAppliedClip; +class GrXferProcessor; class GrXPFactory; class GrProcessorSet : private SkNoncopyable { @@ -22,14 +23,6 @@ public: ~GrProcessorSet(); - /** - * If an op is recorded with this processor set then this must be called to ensure pending - * reads and writes are propagated to resources referred to by the processors. Otherwise, - * data hazards may occur. - */ - void makePendingExecution(); - bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); } - int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; } int numCoverageFragmentProcessors() const { return this->numFragmentProcessors() - fColorFragmentProcessorCnt; @@ -46,7 +39,10 @@ public: return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset]; } - const GrXPFactory* xpFactory() const { return fXPFactory; } + const GrXferProcessor* xferProcessor() const { + SkASSERT(this->isFinalized()); + return fXP.fProcessor; + } bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); } bool disableOutputConversionToSRGB() const { @@ -54,74 +50,20 @@ public: } bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); } + /** Comparisons are only legal on finalized processor sets. */ bool operator==(const GrProcessorSet& that) const; bool operator!=(const GrProcessorSet& that) const { return !(*this == that); } /** - * This is used to track analysis of color and coverage values through the processors. + * This is used to report results of processor analysis when a processor set is finalized (see + * below). */ class Analysis { public: - /** - * This constructor allows an op to record its initial color in an Analysis member and then - * then run analysis later when the analysis inputs are available. If the analysis produces - * color fragment processor elimination then the input color is replaced by the expected - * input to the first non-eliminated processor. Otherwise, the original input color is - * preserved. The only reason to use this is to save space on the op by not separately - * storing the initial color. - */ - explicit Analysis(GrColor initialColor) : Analysis() { - fInputColor = initialColor; - fValidInputColor = true; - } - - Analysis() - : fIsInitializedWithProcessorSet(false) - , fCompatibleWithCoverageAsAlpha(true) - , fValidInputColor(false) - , fRequiresDstTexture(false) - , fCanCombineOverlappedStencilAndCover(true) - , fIgnoresInputColor(false) - , fRequiresBarrierBetweenOverlappingDraws(false) - , fOutputCoverageType(static_cast(GrProcessorAnalysisCoverage::kNone)) - , fOutputColorType(static_cast(ColorType::kUnknown)) - , fInitialColorProcessorsToEliminate(0) {} - - // This version is used by a unit test that assumes no clip and no fragment processors. - Analysis(const GrProcessorAnalysisColor&, GrProcessorAnalysisCoverage, const GrXPFactory*, - const GrCaps&); - - void init(const GrProcessorAnalysisColor&, GrProcessorAnalysisCoverage, - const GrProcessorSet&, const GrAppliedClip*, const GrCaps&); - - bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; } - - /** - * If the return is greater than or equal to zero then 'newInputColor' should be used as the - * input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's - * initial color. If the return is less than zero then newInputColor has not been - * modified and no modification need be made to the pipeline's input color by the op. - */ - int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const { - if (fValidInputColor) { - *newInputColor = fInputColor; - return fInitialColorProcessorsToEliminate; - } - SkASSERT(!fInitialColorProcessorsToEliminate); - return -1; - } - - /** - * Valid if initialProcessorsToEliminate returns true or this analysis was initialized with - * a known color via constructor or init(). If color fragment processors are eliminated then - * this returns the expected input to the first non-eliminated processors. Otherwise it is - * the color passed to the constructor or init(). - */ - GrColor inputColor() const { - SkASSERT(fValidInputColor); - return fInputColor; - } + Analysis(const Analysis&) = default; + Analysis() { *reinterpret_cast(this) = 0; } + bool isInitialized() const { return fIsInitialized; } bool usesLocalCoords() const { return fUsesLocalCoords; } bool requiresDstTexture() const { return fRequiresDstTexture; } bool canCombineOverlappedStencilAndCover() const { @@ -131,60 +73,54 @@ public: return fRequiresBarrierBetweenOverlappingDraws; } bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } - bool isInputColorIgnored() const { return fIgnoresInputColor; } - GrProcessorAnalysisCoverage outputCoverage() const { - return static_cast(fOutputCoverageType); - } - GrProcessorAnalysisColor outputColor() const { - switch (this->outputColorType()) { - case ColorType::kConstant: - return fKnownOutputColor; - case ColorType::kOpaque: - return GrProcessorAnalysisColor::Opaque::kYes; - case ColorType::kUnknown: - return GrProcessorAnalysisColor::Opaque::kNo; - } - SkFAIL("Unexpected color type"); - return GrProcessorAnalysisColor::Opaque::kNo; + + bool inputColorIsIgnored() const { return fInputColorType == kIgnored_InputColorType; } + bool inputColorIsOverridden() const { + return fInputColorType == kOverridden_InputColorType; } private: - enum class ColorType : unsigned { kUnknown, kConstant, kOpaque }; + enum InputColorType : uint32_t { + kOriginal_InputColorType, + kOverridden_InputColorType, + kIgnored_InputColorType + }; - ColorType outputColorType() const { return static_cast(fOutputColorType); } + // MSVS 2015 won't pack different underlying types + using PackedBool = uint32_t; + using PackedInputColorType = uint32_t; - void internalInit(const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage, - const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&); - - // MSVS 2015 won't pack a bool with an unsigned. - using PackedBool = unsigned; - - PackedBool fIsInitializedWithProcessorSet : 1; 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; PackedBool fRequiresBarrierBetweenOverlappingDraws : 1; - unsigned fOutputCoverageType : 2; - unsigned fOutputColorType : 2; - - unsigned fInitialColorProcessorsToEliminate : 32 - 12; - - GrColor fInputColor; - // This could be removed if we created the XP from the XPFactory when doing analysis. - GrColor fKnownOutputColor; + PackedBool fIsInitialized : 1; + PackedInputColorType fInputColorType : 2; friend class GrProcessorSet; }; - GR_STATIC_ASSERT(sizeof(Analysis) == 2 * sizeof(GrColor) + sizeof(uint32_t)); + GR_STATIC_ASSERT(sizeof(Analysis) == sizeof(uint32_t)); - void analyzeAndEliminateFragmentProcessors(Analysis*, - const GrProcessorAnalysisColor& colorInput, - const GrProcessorAnalysisCoverage coverageInput, - const GrAppliedClip*, const GrCaps&); + /** + * This analyzes the processors given an op's input color and coverage as well as a clip. The + * state of the processor set may change to an equivalent but more optimal set of processors. + * This new state requires that the caller respect the returned 'inputColorOverride'. This is + * indicated by the returned Analysis's inputColorIsOverriden(). 'inputColorOverride' will not + * be written if the analysis does not override the input color. + * + * This must be called before the processor set is used to construct a GrPipeline and may only + * be called once. + * + * This also puts the processors in "pending execution" state and must be called when an op + * that owns a processor set is recorded to ensure pending and writes are propagated to + * resources referred to by the processors. Otherwise, data hazards may occur. + */ + Analysis finalize(const GrProcessorAnalysisColor& colorInput, + const GrProcessorAnalysisCoverage coverageInput, const GrAppliedClip*, + bool isMixedSamples, const GrCaps&, GrColor* inputColorOverride); + + bool isFinalized() const { return SkToBool(kFinalized_Flag & fFlags); } private: // This absurdly large limit allows Analysis and this to pack fields together. @@ -194,11 +130,22 @@ private: kUseDistanceVectorField_Flag = 0x1, kDisableOutputConversionToSRGB_Flag = 0x2, kAllowSRGBInputs_Flag = 0x4, - kPendingExecution_Flag = 0x8 + kFinalized_Flag = 0x8 + }; + + union XP { + XP(const GrXPFactory* factory) : fFactory(factory) {} + const GrXPFactory* fFactory; + const GrXferProcessor* fProcessor; }; - const GrXPFactory* fXPFactory = nullptr; + const GrXPFactory* xpFactory() const { + SkASSERT(!this->isFinalized()); + return fXP.fFactory; + } + SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors; + XP fXP; uint8_t fColorFragmentProcessorCnt; uint8_t fFragmentProcessorOffset = 0; uint8_t fFlags; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index a4b77310d0..b0a1b6d4af 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1688,30 +1688,33 @@ uint32_t GrRenderTargetContext::addLegacyMeshDrawOp(GrPipelineBuilder&& pipeline } GrResourceProvider* resourceProvider = fContext->resourceProvider(); - if (pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip()) { + bool usesStencil = pipelineBuilder.hasUserStencilSettings() || appliedClip.hasStencilClip(); + if (usesStencil) { if (!resourceProvider->attachStencilAttachment(this->accessRenderTarget())) { SkDebugf("ERROR creating stencil attachment. Draw skipped.\n"); return SK_InvalidUniqueID; } } - GrProcessorSet::Analysis analysis; - op->analyzeProcessors(&analysis, &pipelineBuilder, &appliedClip, *this->caps()); + bool isMixedSamples = fRenderTargetProxy->isMixedSampled() && + (pipelineBuilder.isHWAntialias() || usesStencil); + + GrColor overrideColor; + GrProcessorSet::Analysis analysis = op->analyzeUpdateAndRecordProcessors( + &pipelineBuilder, &appliedClip, isMixedSamples, *this->caps(), &overrideColor); GrPipeline::InitArgs args; pipelineBuilder.getPipelineInitArgs(&args); args.fAppliedClip = &appliedClip; args.fRenderTarget = rt; args.fCaps = this->caps(); - args.fXPInputColor = analysis.outputColor(); - args.fXPInputCoverage = analysis.outputCoverage(); if (analysis.requiresDstTexture()) { if (!this->setupDstTexture(fRenderTargetProxy.get(), clip, bounds, &args.fDstTexture)) { return SK_InvalidUniqueID; } } - op->initPipeline(args, analysis); + op->initPipeline(args, analysis, overrideColor); // TODO: We need to add pipeline dependencies on textures, etc before recording this op. op->setClippedBounds(bounds); return this->getOpList()->addOp(std::move(op), this); diff --git a/src/gpu/instanced/InstancedRendering.cpp b/src/gpu/instanced/InstancedRendering.cpp index 9b6e576f8f..9d17a82fc1 100644 --- a/src/gpu/instanced/InstancedRendering.cpp +++ b/src/gpu/instanced/InstancedRendering.cpp @@ -332,17 +332,19 @@ void InstancedRendering::Op::appendParamsTexel(SkScalar x, SkScalar y, SkScalar } bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) { - GrProcessorSet::Analysis analysis; + SkASSERT(State::kRecordingDraws == fInstancedRendering->fState); GrProcessorAnalysisCoverage coverageInput; + bool isMixedSamples = false; if (GrAAType::kCoverage == fInfo.aaType() || (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) { coverageInput = GrProcessorAnalysisCoverage::kSingleChannel; } else { coverageInput = GrProcessorAnalysisCoverage::kNone; + isMixedSamples = GrAAType::kMixedSamples == fInfo.aaType(); } - fProcessors.analyzeAndEliminateFragmentProcessors(&analysis, this->getSingleInstance().fColor, - coverageInput, clip, caps); - fAnalysisColor = analysis.outputColor(); + GrProcessorSet::Analysis analysis = + fProcessors.finalize(this->getSingleInstance().fColor, coverageInput, clip, + isMixedSamples, caps, &this->getSingleDraw().fInstance.fColor); Draw& draw = this->getSingleDraw(); // This will assert if we have > 1 command. SkASSERT(draw.fGeometry.isEmpty()); @@ -363,11 +365,6 @@ bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAp fInstancedRendering->fParams.push_back_n(fParams.count(), fParams.begin()); } - GrColor overrideColor; - if (analysis.getInputColorOverrideAndColorProcessorEliminationCount(&overrideColor) >= 0) { - SkASSERT(State::kRecordingDraws == fInstancedRendering->fState); - this->getSingleDraw().fInstance.fColor = overrideColor; - } fInfo.fCannotTweakAlphaForCoverage = !analysis.isCompatibleWithCoverageAsAlpha(); fInfo.fUsesLocalCoords = analysis.usesLocalCoords(); @@ -378,7 +375,6 @@ bool InstancedRendering::Op::xpRequiresDstTexture(const GrCaps& caps, const GrAp void InstancedRendering::Op::wasRecorded() { SkASSERT(!fIsTracked); fInstancedRendering->fTrackedOps.addToTail(this); - fProcessors.makePendingExecution(); fIsTracked = true; } @@ -413,7 +409,6 @@ bool InstancedRendering::Op::onCombineIfPossible(GrOp* other, const GrCaps& caps this->joinBounds(*that); fInfo = combinedInfo; fPixelLoad += that->fPixelLoad; - fAnalysisColor = GrProcessorAnalysisColor::Combine(fAnalysisColor, that->fAnalysisColor); // Adopt the other op's draws. fNumDraws += that->fNumDraws; fNumChangesInGeometry += that->fNumChangesInGeometry; @@ -470,21 +465,9 @@ void InstancedRendering::Op::onExecute(GrOpFlushState* state) { state->gpu()->handleDirtyContext(); - const GrAppliedClip* clip = state->drawOpArgs().fAppliedClip; - GrProcessorAnalysisCoverage coverage; - if (GrAAType::kCoverage == fInfo.aaType() || - (clip && clip->clipCoverageFragmentProcessor()) || - (GrAAType::kNone == fInfo.aaType() && !fInfo.isSimpleRects() && fInfo.fCannotDiscard)) { - coverage = GrProcessorAnalysisCoverage::kSingleChannel; - } else { - coverage = GrProcessorAnalysisCoverage::kNone; - } - GrPipeline pipeline; GrPipeline::InitArgs args; - args.fXPInputColor = fAnalysisColor; - args.fXPInputCoverage = coverage; - args.fAppliedClip = clip; + args.fAppliedClip = state->drawOpArgs().fAppliedClip; args.fCaps = &state->caps(); args.fProcessors = &fProcessors; args.fFlags = GrAATypeIsHW(fInfo.aaType()) ? GrPipeline::kHWAntialias_Flag : 0; diff --git a/src/gpu/instanced/InstancedRendering.h b/src/gpu/instanced/InstancedRendering.h index 3ec8214afc..a8b9530228 100644 --- a/src/gpu/instanced/InstancedRendering.h +++ b/src/gpu/instanced/InstancedRendering.h @@ -151,7 +151,6 @@ protected: OpInfo fInfo; SkScalar fPixelLoad; GrProcessorSet fProcessors; - GrProcessorAnalysisColor fAnalysisColor; SkSTArray<5, ParamsTexel, true> fParams; bool fIsTracked : 1; bool fRequiresBarrierOnOverlap : 1; diff --git a/src/gpu/ops/GrDrawOp.h b/src/gpu/ops/GrDrawOp.h index 0458370bcd..dbdd9d87a0 100644 --- a/src/gpu/ops/GrDrawOp.h +++ b/src/gpu/ops/GrDrawOp.h @@ -76,7 +76,8 @@ public: * This is called after the GrAppliedClip has been computed and just prior to recording the op * or combining it with a previously recorded op. It is used to determine whether a copy of the * destination (or destination texture itself) needs to be provided to the xp when this op - * executes. + * executes. This is guaranteed to be called before an op is recorded. However, this is also + * called on ops that are not recorded because they combine with a previously recorded op. */ virtual bool xpRequiresDstTexture(const GrCaps&, const GrAppliedClip*) = 0; diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp index 1c68fdf8a1..3632787e06 100644 --- a/src/gpu/ops/GrDrawPathOp.cpp +++ b/src/gpu/ops/GrDrawPathOp.cpp @@ -12,13 +12,15 @@ #include "SkTemplates.h" GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint, - GrPathRendering::FillType fill, GrAA aa) + GrPathRendering::FillType fill, GrAAType aaType) : INHERITED(classID) , fViewMatrix(viewMatrix) + , fInputColor(paint.getColor()) , fProcessorSet(std::move(paint)) - , fAnalysis(paint.getColor()) , fFillType(fill) - , fAA(aa) {} + , fAAType(aaType) { + SkASSERT(fAAType != GrAAType::kCoverage); +} SkString GrDrawPathOp::dumpInfo() const { SkString string; @@ -38,16 +40,13 @@ void GrDrawPathOpBase::initPipeline(const GrOpFlushState& state, GrPipeline* pip 0xffff>() }; GrPipeline::InitArgs args; - auto analysis = this->processorAnalysis(); args.fProcessors = &this->processors(); - args.fFlags = GrAA::kYes == fAA ? GrPipeline::kHWAntialias_Flag : 0; + args.fFlags = GrAATypeIsHW(fAAType) ? GrPipeline::kHWAntialias_Flag : 0; args.fUserStencil = &kCoverPass; args.fAppliedClip = state.drawOpArgs().fAppliedClip; args.fRenderTarget = state.drawOpArgs().fRenderTarget; args.fCaps = &state.caps(); args.fDstTexture = state.drawOpArgs().fDstTexture; - args.fXPInputColor = analysis.outputColor(); - args.fXPInputCoverage = analysis.outputCoverage(); return pipeline->init(args); } @@ -90,9 +89,9 @@ SkString GrDrawPathRangeOp::dumpInfo() const { GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill, - GrAA aa, GrPathRange* range, const InstanceData* instanceData, - const SkRect& bounds) - : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aa) + GrAAType aaType, GrPathRange* range, + const InstanceData* instanceData, const SkRect& bounds) + : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aaType) , fPathRange(range) , fTotalPathCount(instanceData->count()) , fScale(scale) { diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h index 0631adcdf6..8995de4bbd 100644 --- a/src/gpu/ops/GrDrawPathOp.h +++ b/src/gpu/ops/GrDrawPathOp.h @@ -23,31 +23,33 @@ class GrPaint; class GrDrawPathOpBase : public GrDrawOp { protected: - GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint, - GrPathRendering::FillType fill, GrAA aa); + GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&, + GrPathRendering::FillType, GrAAType); FixedFunctionFlags fixedFunctionFlags() const override { - return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil; + if (GrAATypeIsHW(fAAType)) { + return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil; + } + return FixedFunctionFlags::kUsesStencil; } bool xpRequiresDstTexture(const GrCaps& caps, const GrAppliedClip* clip) override { return this->doProcessorAnalysis(caps, clip).requiresDstTexture(); } - void wasRecorded() override { fProcessorSet.makePendingExecution(); } - protected: const SkMatrix& viewMatrix() const { return fViewMatrix; } - GrColor color() const { return fAnalysis.inputColor(); } + GrColor color() const { return fInputColor; } GrPathRendering::FillType fillType() const { return fFillType; } const GrProcessorSet& processors() const { return fProcessorSet; } void initPipeline(const GrOpFlushState&, GrPipeline*); const GrProcessorSet::Analysis& doProcessorAnalysis(const GrCaps& caps, const GrAppliedClip* clip) { - fProcessorSet.analyzeAndEliminateFragmentProcessors( - &fAnalysis, fAnalysis.inputColor(), GrProcessorAnalysisCoverage::kNone, clip, caps); + bool isMixedSamples = GrAAType::kMixedSamples == fAAType; + fAnalysis = fProcessorSet.finalize(fInputColor, GrProcessorAnalysisCoverage::kNone, clip, + isMixedSamples, caps, &fInputColor); return fAnalysis; } const GrProcessorSet::Analysis& processorAnalysis() const { - SkASSERT(fAnalysis.isInitializedWithProcessorSet()); + SkASSERT(fAnalysis.isInitialized()); return fAnalysis; } @@ -55,10 +57,11 @@ private: void onPrepare(GrOpFlushState*) final {} SkMatrix fViewMatrix; + GrColor fInputColor; GrProcessorSet fProcessorSet; GrProcessorSet::Analysis fAnalysis; GrPathRendering::FillType fFillType; - GrAA fAA; + GrAAType fAAType; typedef GrDrawOp INHERITED; }; @@ -67,9 +70,10 @@ class GrDrawPathOp final : public GrDrawPathOpBase { public: DEFINE_OP_CLASS_ID - static std::unique_ptr Make(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, - GrPath* path) { - return std::unique_ptr(new GrDrawPathOp(viewMatrix, std::move(paint), aa, path)); + static std::unique_ptr Make(const SkMatrix& viewMatrix, GrPaint&& paint, + GrAAType aaType, GrPath* path) { + return std::unique_ptr( + new GrDrawPathOp(viewMatrix, std::move(paint), aaType, path)); } const char* name() const override { return "DrawPath"; } @@ -77,8 +81,8 @@ public: SkString dumpInfo() const override; private: - GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, const GrPath* path) - : GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aa) + GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAAType aaType, const GrPath* path) + : GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aaType) , fPath(path) { this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); } @@ -160,11 +164,12 @@ public: static std::unique_ptr Make(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, GrPaint&& paint, - GrPathRendering::FillType fill, GrAA aa, + GrPathRendering::FillType fill, GrAAType aaType, GrPathRange* range, const InstanceData* instanceData, const SkRect& bounds) { - return std::unique_ptr(new GrDrawPathRangeOp( - viewMatrix, scale, x, y, std::move(paint), fill, aa, range, instanceData, bounds)); + return std::unique_ptr(new GrDrawPathRangeOp(viewMatrix, scale, x, y, + std::move(paint), fill, aaType, + range, instanceData, bounds)); } const char* name() const override { return "DrawPathRange"; } @@ -173,8 +178,8 @@ public: private: GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x, SkScalar y, - GrPaint&& paint, GrPathRendering::FillType fill, GrAA aa, GrPathRange* range, - const InstanceData* instanceData, const SkRect& bounds); + GrPaint&& paint, GrPathRendering::FillType fill, GrAAType aaType, + GrPathRange* range, const InstanceData* instanceData, const SkRect& bounds); TransformType transformType() const { return fDraws.head()->fInstanceData->transformType(); } diff --git a/src/gpu/ops/GrMeshDrawOp.h b/src/gpu/ops/GrMeshDrawOp.h index 41d3848666..8fbd30d280 100644 --- a/src/gpu/ops/GrMeshDrawOp.h +++ b/src/gpu/ops/GrMeshDrawOp.h @@ -101,20 +101,22 @@ public: * Performs analysis of the fragment processors in GrProcessorSet and GrAppliedClip using the * initial color and coverage from this op's geometry processor. */ - void analyzeProcessors(GrProcessorSet::Analysis* analysis, - GrPipelineBuilder* pipelineBuilder, - const GrAppliedClip* appliedClip, - const GrCaps& caps) const { + GrProcessorSet::Analysis analyzeUpdateAndRecordProcessors(GrPipelineBuilder* pipelineBuilder, + const GrAppliedClip* appliedClip, + bool isMixedSamples, + const GrCaps& caps, + GrColor* overrideColor) const { GrProcessorAnalysisColor inputColor; GrProcessorAnalysisCoverage inputCoverage; this->getProcessorAnalysisInputs(&inputColor, &inputCoverage); - pipelineBuilder->analyzeAndEliminateFragmentProcessors(analysis, inputColor, inputCoverage, - appliedClip, caps); + return pipelineBuilder->finalizeProcessors(inputColor, inputCoverage, appliedClip, + isMixedSamples, caps, overrideColor); } - void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis) { + void initPipeline(const GrPipeline::InitArgs& args, const GrProcessorSet::Analysis& analysis, + GrColor overrideColor) { fPipeline.init(args); - this->applyPipelineOptimizations(PipelineOptimizations(analysis)); + this->applyPipelineOptimizations(PipelineOptimizations(analysis, overrideColor)); } /** @@ -138,11 +140,11 @@ protected: */ class PipelineOptimizations { public: - PipelineOptimizations(const GrProcessorSet::Analysis& analysis) { + PipelineOptimizations(const GrProcessorSet::Analysis& analysis, GrColor overrideColor) { fFlags = 0; - if (analysis.getInputColorOverrideAndColorProcessorEliminationCount(&fOverrideColor) >= - 0) { + if (analysis.inputColorIsOverridden()) { fFlags |= kUseOverrideColor_Flag; + fOverrideColor = overrideColor; } if (analysis.usesLocalCoords()) { fFlags |= kReadsLocalCoords_Flag; diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp index a4e32acff3..bd5c297cd8 100644 --- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp +++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp @@ -145,9 +145,8 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { std::move(coverOp)); } } else { - GrAA aa = GrBoolToAA(GrAATypeIsHW(args.fAAType)); std::unique_ptr op = - GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), aa, path.get()); + GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get()); args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); } diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp index e572e5d633..0ae4023b1c 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.cpp +++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp @@ -570,9 +570,7 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, SkScalar y, const SkIRect& clipBounds, GrAtlasTextContext* fallbackTextContext, const SkPaint& originalSkPaint) const { - GrAA runAA = this->isAntiAlias(); SkASSERT(fInstanceData); - SkASSERT(renderTargetContext->isStencilBufferMultisampled() || GrAA::kNo == runAA); if (fInstanceData->count()) { static constexpr GrUserStencilSettings kCoverPass( @@ -606,9 +604,18 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, renderTargetContext->height()); // The run's "font" overrides the anti-aliasing of the passed in SkPaint! + GrAAType aaType; + if (this->aa() == GrAA::kYes) { + SkASSERT(renderTargetContext->isStencilBufferMultisampled()); + aaType = renderTargetContext->isUnifiedMultisampled() ? GrAAType::kMSAA + : GrAAType::kMixedSamples; + } else { + aaType = GrAAType::kNone; + } + std::unique_ptr op = GrDrawPathRangeOp::Make( viewMatrix, fTextRatio, fTextInverseRatio * x, fTextInverseRatio * y, - std::move(grPaint), GrPathRendering::kWinding_FillType, runAA, glyphs.get(), + std::move(grPaint), GrPathRendering::kWinding_FillType, aaType, glyphs.get(), fInstanceData.get(), bounds); renderTargetContext->addDrawOp(clip, std::move(op)); diff --git a/src/gpu/text/GrStencilAndCoverTextContext.h b/src/gpu/text/GrStencilAndCoverTextContext.h index f06442b1be..54c0a9d758 100644 --- a/src/gpu/text/GrStencilAndCoverTextContext.h +++ b/src/gpu/text/GrStencilAndCoverTextContext.h @@ -83,7 +83,7 @@ private: size_t computeSizeInCache() const; - GrAA isAntiAlias() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; } + GrAA aa() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; } private: typedef GrDrawPathRangeOp::InstanceData InstanceData; -- cgit v1.2.3