1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrProcessorSet_DEFINED 9 #define GrProcessorSet_DEFINED 10 11 #include "GrFragmentProcessor.h" 12 #include "GrPaint.h" 13 #include "GrPipelineAnalysis.h" 14 #include "SkTemplates.h" 15 16 class GrAppliedClip; 17 class GrXPFactory; 18 19 class GrProcessorSet : private SkNoncopyable { 20 public: 21 GrProcessorSet(GrPaint&& paint); 22 23 ~GrProcessorSet(); 24 25 /** 26 * If an op is recorded with this processor set then this must be called to ensure pending 27 * reads and writes are propagated to resources referred to by the processors. Otherwise, 28 * data hazards may occur. 29 */ 30 void makePendingExecution(); isPendingExecution()31 bool isPendingExecution() const { return SkToBool(kPendingExecution_Flag & fFlags); } 32 numColorFragmentProcessors()33 int numColorFragmentProcessors() const { return fColorFragmentProcessorCnt; } numCoverageFragmentProcessors()34 int numCoverageFragmentProcessors() const { 35 return this->numFragmentProcessors() - fColorFragmentProcessorCnt; 36 } numFragmentProcessors()37 int numFragmentProcessors() const { 38 return fFragmentProcessors.count() - fFragmentProcessorOffset; 39 } 40 colorFragmentProcessor(int idx)41 const GrFragmentProcessor* colorFragmentProcessor(int idx) const { 42 SkASSERT(idx < fColorFragmentProcessorCnt); 43 return fFragmentProcessors[idx + fFragmentProcessorOffset]; 44 } coverageFragmentProcessor(int idx)45 const GrFragmentProcessor* coverageFragmentProcessor(int idx) const { 46 return fFragmentProcessors[idx + fColorFragmentProcessorCnt + fFragmentProcessorOffset]; 47 } 48 xpFactory()49 const GrXPFactory* xpFactory() const { return fXPFactory; } 50 usesDistanceVectorField()51 bool usesDistanceVectorField() const { return SkToBool(fFlags & kUseDistanceVectorField_Flag); } disableOutputConversionToSRGB()52 bool disableOutputConversionToSRGB() const { 53 return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); 54 } allowSRGBInputs()55 bool allowSRGBInputs() const { return SkToBool(fFlags & kAllowSRGBInputs_Flag); } 56 57 bool operator==(const GrProcessorSet& that) const; 58 bool operator!=(const GrProcessorSet& that) const { return !(*this == that); } 59 60 /** 61 * This is used to track analysis of color and coverage values through the fragment processors. 62 */ 63 class FragmentProcessorAnalysis { 64 public: 65 /** 66 * This constructor allows an op to record its initial color in a FragmentProcessorAnalysis 67 * member and then run analysis later when the analysis inputs are available. If the 68 * analysis produces color fragment processor elimination then the input color is replaced 69 * by the expected input to the first non-eliminated processor. Otherwise, the original 70 * input color is preserved. The only reason to use this is to save space on the op by not 71 * separately storing the initial color. 72 */ FragmentProcessorAnalysis(GrColor initialColor)73 explicit FragmentProcessorAnalysis(GrColor initialColor) : FragmentProcessorAnalysis() { 74 fInputColor = initialColor; 75 fValidInputColor = true; 76 } 77 FragmentProcessorAnalysis()78 FragmentProcessorAnalysis() 79 : fIsInitializedWithProcessorSet(false) 80 , fCompatibleWithCoverageAsAlpha(true) 81 , fValidInputColor(false) 82 , fOutputCoverageType(static_cast<unsigned>(GrPipelineAnalysisCoverage::kNone)) 83 , fOutputColorType(static_cast<unsigned>(ColorType::kUnknown)) 84 , fInitialColorProcessorsToEliminate(0) {} 85 86 // This version is used by a unit test that assumes no clip, no processors, and no PLS. 87 FragmentProcessorAnalysis(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, 88 const GrCaps&); 89 90 void init(const GrPipelineAnalysisColor&, GrPipelineAnalysisCoverage, const GrProcessorSet&, 91 const GrAppliedClip*, const GrCaps&); 92 isInitializedWithProcessorSet()93 bool isInitializedWithProcessorSet() const { return fIsInitializedWithProcessorSet; } 94 95 /** 96 * If the return is greater than or equal to zero then 'newInputColor' should be used as the 97 * input color to the GrPipeline derived from this processor set, replacing the GrDrawOp's 98 * initial color. If the return is less than zero then newInputColor has not been 99 * modified and no modification need be made to the pipeline's input color by the op. 100 */ getInputColorOverrideAndColorProcessorEliminationCount(GrColor * newInputColor)101 int getInputColorOverrideAndColorProcessorEliminationCount(GrColor* newInputColor) const { 102 if (fValidInputColor) { 103 *newInputColor = fInputColor; 104 return fInitialColorProcessorsToEliminate; 105 } 106 SkASSERT(!fInitialColorProcessorsToEliminate); 107 return -1; 108 } 109 110 /** 111 * Valid if initialProcessorsToEliminate returns true or this analysis was initialized with 112 * a known color via constructor or init(). If color fragment processors are eliminated then 113 * this returns the expected input to the first non-eliminated processors. Otherwise it is 114 * the color passed to the constructor or init(). 115 */ inputColor()116 GrColor inputColor() const { 117 SkASSERT(fValidInputColor); 118 return fInputColor; 119 } 120 usesLocalCoords()121 bool usesLocalCoords() const { return fUsesLocalCoords; } isCompatibleWithCoverageAsAlpha()122 bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } isOutputColorOpaque()123 bool isOutputColorOpaque() const { 124 return ColorType::kOpaque == this->outputColorType() || 125 ColorType::kOpaqueConstant == this->outputColorType(); 126 } 127 bool hasKnownOutputColor(GrColor* color = nullptr) const { 128 bool constant = ColorType::kConstant == this->outputColorType() || 129 ColorType::kOpaqueConstant == this->outputColorType(); 130 if (constant && color) { 131 *color = fKnownOutputColor; 132 } 133 return constant; 134 } outputCoverageType()135 GrPipelineAnalysisCoverage outputCoverageType() const { 136 return static_cast<GrPipelineAnalysisCoverage>(fOutputCoverageType); 137 } hasCoverage()138 bool hasCoverage() const { 139 return this->outputCoverageType() != GrPipelineAnalysisCoverage::kNone; 140 } 141 142 private: 143 enum class ColorType : unsigned { kUnknown, kOpaqueConstant, kConstant, kOpaque }; 144 outputColorType()145 ColorType outputColorType() const { return static_cast<ColorType>(fOutputColorType); } 146 147 void internalInit(const GrPipelineAnalysisColor&, const GrPipelineAnalysisCoverage, 148 const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&); 149 150 // MSVS 2015 won't pack a bool with an unsigned. 151 using PackedBool = unsigned; 152 153 PackedBool fIsInitializedWithProcessorSet : 1; 154 PackedBool fUsesLocalCoords : 1; 155 PackedBool fCompatibleWithCoverageAsAlpha : 1; 156 PackedBool fValidInputColor : 1; 157 unsigned fOutputCoverageType : 2; 158 unsigned fOutputColorType : 2; 159 unsigned fInitialColorProcessorsToEliminate : 32 - 8; 160 161 GrColor fInputColor; 162 GrColor fKnownOutputColor; 163 164 friend class GrProcessorSet; 165 }; 166 GR_STATIC_ASSERT(sizeof(FragmentProcessorAnalysis) == 2 * sizeof(GrColor) + sizeof(uint32_t)); 167 168 void analyzeAndEliminateFragmentProcessors(FragmentProcessorAnalysis*, 169 const GrPipelineAnalysisColor& colorInput, 170 const GrPipelineAnalysisCoverage coverageInput, 171 const GrAppliedClip*, const GrCaps&); 172 173 private: 174 // This absurdly large limit allows FragmentProcessorAnalysis and this to pack fields together. 175 static constexpr int kMaxColorProcessors = UINT8_MAX; 176 177 enum Flags : uint16_t { 178 kUseDistanceVectorField_Flag = 0x1, 179 kDisableOutputConversionToSRGB_Flag = 0x2, 180 kAllowSRGBInputs_Flag = 0x4, 181 kPendingExecution_Flag = 0x8 182 }; 183 184 const GrXPFactory* fXPFactory = nullptr; 185 SkAutoSTArray<4, const GrFragmentProcessor*> fFragmentProcessors; 186 uint8_t fColorFragmentProcessorCnt; 187 uint8_t fFragmentProcessorOffset = 0; 188 uint8_t fFlags; 189 }; 190 191 #endif 192