1 /* 2 * Copyright 2014 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 GrProcessorAnalysis_DEFINED 9 #define GrProcessorAnalysis_DEFINED 10 11 #include "include/private/SkColorData.h" 12 13 #include <memory> 14 15 class GrCaps; 16 class GrDrawOp; 17 class GrFragmentProcessor; 18 19 class GrProcessorAnalysisColor { 20 public: 21 enum class Opaque { 22 kNo, 23 kYes, 24 }; 25 26 constexpr GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo) 27 : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0) 28 , fColor(SK_PMColor4fTRANSPARENT) {} 29 GrProcessorAnalysisColor(const SkPMColor4f & color)30 GrProcessorAnalysisColor(const SkPMColor4f& color) { this->setToConstant(color); } 31 setToConstant(const SkPMColor4f & color)32 void setToConstant(const SkPMColor4f& color) { 33 fColor = color; 34 if (color.isOpaque()) { 35 fFlags = kColorIsKnown_Flag | kIsOpaque_Flag; 36 } else { 37 fFlags = kColorIsKnown_Flag; 38 } 39 } 40 setToUnknown()41 void setToUnknown() { fFlags = 0; } 42 setToUnknownOpaque()43 void setToUnknownOpaque() { fFlags = kIsOpaque_Flag; } 44 isUnknown()45 bool isUnknown() const { return SkToBool(fFlags == 0); } 46 isOpaque()47 bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); } 48 49 bool isConstant(SkPMColor4f* color = nullptr) const { 50 if (kColorIsKnown_Flag & fFlags) { 51 if (color) { 52 *color = fColor; 53 } 54 return true; 55 } 56 return false; 57 } 58 59 bool operator==(const GrProcessorAnalysisColor& that) const { 60 if (fFlags != that.fFlags) { 61 return false; 62 } 63 return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true; 64 } 65 66 /** The returned value reflects the common properties of the two inputs. */ Combine(const GrProcessorAnalysisColor & a,const GrProcessorAnalysisColor & b)67 static GrProcessorAnalysisColor Combine(const GrProcessorAnalysisColor& a, 68 const GrProcessorAnalysisColor& b) { 69 GrProcessorAnalysisColor result; 70 uint32_t commonFlags = a.fFlags & b.fFlags; 71 if ((kColorIsKnown_Flag & commonFlags) && a.fColor == b.fColor) { 72 result.fColor = a.fColor; 73 result.fFlags = a.fFlags; 74 } else if (kIsOpaque_Flag & commonFlags) { 75 result.fFlags = kIsOpaque_Flag; 76 } 77 return result; 78 } 79 80 private: 81 enum Flags { 82 kColorIsKnown_Flag = 0x1, 83 kIsOpaque_Flag = 0x2, 84 }; 85 uint32_t fFlags; 86 SkPMColor4f fColor; 87 }; 88 89 enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD }; 90 91 /** 92 * GrColorFragmentProcessorAnalysis gathers invariant data from a set of color fragment processors. 93 * It is used to recognize optimizations that can simplify the generated shader or make blending 94 * more effecient. 95 */ 96 class GrColorFragmentProcessorAnalysis { 97 public: 98 GrColorFragmentProcessorAnalysis() = delete; 99 100 GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor& input, 101 std::unique_ptr<GrFragmentProcessor> const fps[], 102 int count); 103 isOpaque()104 bool isOpaque() const { return fIsOpaque; } 105 106 /** 107 * Are all the fragment processors compatible with conflating coverage with color prior to the 108 * the first fragment processor. This result assumes that processors that should be eliminated 109 * as indicated by initialProcessorsToEliminate() are in fact eliminated. 110 */ allProcessorsCompatibleWithCoverageAsAlpha()111 bool allProcessorsCompatibleWithCoverageAsAlpha() const { 112 return fCompatibleWithCoverageAsAlpha; 113 } 114 115 /** 116 * Do any of the fragment processors require local coords. This result assumes that 117 * processors that should be eliminated as indicated by initialProcessorsToEliminate() are in 118 * fact eliminated. 119 */ usesLocalCoords()120 bool usesLocalCoords() const { return fUsesLocalCoords; } 121 122 /** 123 * Do any of the fragment processors read back the destination color? 124 */ willReadDstColor()125 bool willReadDstColor() const { return fWillReadDstColor; } 126 127 /** 128 * Will we require a destination-surface texture? 129 */ 130 bool requiresDstTexture(const GrCaps& caps) const; 131 132 /** 133 * If we detected that the result after the first N processors is a known color then we 134 * eliminate those N processors and replace the GrDrawOp's color input to the GrPipeline with 135 * the known output of the Nth processor, so that the Nth+1 fragment processor (or the XP if 136 * there are only N processors) sees its expected input. If this returns 0 then there are no 137 * processors to eliminate. 138 */ initialProcessorsToEliminate(SkPMColor4f * newPipelineInputColor)139 int initialProcessorsToEliminate(SkPMColor4f* newPipelineInputColor) const { 140 if (fProcessorsToEliminate > 0) { 141 *newPipelineInputColor = fLastKnownOutputColor; 142 } 143 return fProcessorsToEliminate; 144 } 145 146 /** 147 * Provides known information about the last processor's output color. 148 */ outputColor()149 GrProcessorAnalysisColor outputColor() const { 150 if (fOutputColorKnown) { 151 return fLastKnownOutputColor; 152 } 153 return fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes 154 : GrProcessorAnalysisColor::Opaque::kNo; 155 } 156 157 private: 158 bool fIsOpaque; 159 bool fCompatibleWithCoverageAsAlpha; 160 bool fUsesLocalCoords; 161 bool fWillReadDstColor; 162 bool fOutputColorKnown; 163 int fProcessorsToEliminate; 164 SkPMColor4f fLastKnownOutputColor; 165 }; 166 167 #endif 168