/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrProcessorSet_DEFINED #define GrProcessorSet_DEFINED #include "GrFragmentProcessor.h" #include "GrPaint.h" #include "GrPipelineAnalysis.h" #include "SkTemplates.h" class GrAppliedClip; class GrXPFactory; class GrProcessorSet : private SkNoncopyable { public: GrProcessorSet(GrPaint&& paint); ~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; } int numFragmentProcessors() const { return fFragmentProcessors.count() - fFragmentProcessorOffset; } const GrFragmentProcessor* colorFragmentProcessor(int idx) const { SkASSERT(idx < fColorFragmentProcessorCnt); return fFragmentProcessors[idx + fFragmentProcessorOffset]; } const GrFragmentProcessor* coverageFragmentProcessor(int idx) const { return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset]; } const GrXPFactory* xpFactory() const { return fXPFactory; } bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); } bool disableOutputConversionToSRGB() const { return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); } bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); } 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 fragment processors. */ class FragmentProcessorAnalysis { public: /** * This constructor allows an op to record its initial color in a FragmentProcessorAnalysis * member and 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 FragmentProcessorAnalysis(GrColor initialColor) : FragmentProcessorAnalysis() { fInputColor = initialColor; fValidInputColor = true; } FragmentProcessorAnalysis() : fIsInitializedWithProcessorSet(false) , fCompatibleWithCoverageAsAlpha(true) , fValidInputColor(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. FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrCaps&); void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, 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; } bool usesLocalCoords() const { return fUsesLocalCoords; } bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } bool isOutputColorOpaque() const { return ColorType::kOpaque == this->outputColorType() || ColorType::kOpaqueConstant == this->outputColorType(); } bool hasKnownOutputColor(GrColor* color = nullptr) const { bool constant = ColorType::kConstant == this->outputColorType() || ColorType::kOpaqueConstant == this->outputColorType(); if (constant && color) { *color = fKnownOutputColor; } return constant; } GrPipelineAnalysisCoverage outputCoverageType() const { return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType); } bool hasCoverage() const { return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone; } private: enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque }; ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); } void internalInit(const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage, 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; unsigned fOutputCoverageType : 2; unsigned fOutputColorType : 2; unsigned fInitialColorProcessorsToEliminate : 32 - 8; GrColor fInputColor; GrColor fKnownOutputColor; friend class GrProcessorSet; }; GR_STATIC_ASSERT(sizeof(FragmentProcessorAnalysis) == 2 * sizeof(GrColor) + sizeof(uint32_t)); void analyzeAndEliminateFragmentProcessors(FragmentProcessorAnalysis*, const GrPipelineAnalysisColor& colorInput, const GrPipelineAnalysisCoverage coverageInput, const GrAppliedClip*, const GrCaps&); private: // This absurdly large limit allows FragmentProcessorAnalysis and this to pack fields together. static constexpr int kMaxColorProcessors = UINT8_MAX; enum Flags : uint16_t { kUseDistanceVectorField_Flag = 0x1, kDisableOutputConversionToSRGB_Flag = 0x2, kAllowSRGBInputs_Flag = 0x4, kPendingExecution_Flag = 0x8 }; const GrXPFactory* fXPFactory = nullptr; SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors; uint8_t fColorFragmentProcessorCnt; uint8_t fFragmentProcessorOffset = 0; uint8_t fFlags; }; #endif