• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrColor.h"
12 
13 class GrDrawOp;
14 class GrFragmentProcessor;
15 class GrPrimitiveProcessor;
16 
17 class GrProcessorAnalysisColor {
18 public:
19     enum class Opaque {
20         kNo,
21         kYes,
22     };
23 
24     constexpr GrProcessorAnalysisColor(Opaque opaque = Opaque::kNo)
25             : fFlags(opaque == Opaque::kYes ? kIsOpaque_Flag : 0), fColor(0) {}
26 
GrProcessorAnalysisColor(GrColor color)27     GrProcessorAnalysisColor(GrColor color) { this->setToConstant(color); }
28 
setToConstant(GrColor color)29     void setToConstant(GrColor color) {
30         fColor = color;
31         if (GrColorIsOpaque(color)) {
32             fFlags = kColorIsKnown_Flag | kIsOpaque_Flag;
33         } else {
34             fFlags = kColorIsKnown_Flag;
35         }
36     }
37 
setToUnknown()38     void setToUnknown() { fFlags = 0; }
39 
setToUnknownOpaque()40     void setToUnknownOpaque() { fFlags = kIsOpaque_Flag; }
41 
isOpaque()42     bool isOpaque() const { return SkToBool(kIsOpaque_Flag & fFlags); }
43 
44     bool isConstant(GrColor* color = nullptr) const {
45         if (kColorIsKnown_Flag & fFlags) {
46             if (color) {
47                 *color = fColor;
48             }
49             return true;
50         }
51         return false;
52     }
53 
54     bool operator==(const GrProcessorAnalysisColor& that) const {
55         if (fFlags != that.fFlags) {
56             return false;
57         }
58         return (kColorIsKnown_Flag & fFlags) ? fColor == that.fColor : true;
59     }
60 
61     /** The returned value reflects the common properties of the two inputs. */
Combine(const GrProcessorAnalysisColor & a,const GrProcessorAnalysisColor & b)62     static GrProcessorAnalysisColor Combine(const GrProcessorAnalysisColor& a,
63                                             const GrProcessorAnalysisColor& b) {
64         GrProcessorAnalysisColor result;
65         uint32_t commonFlags = a.fFlags & b.fFlags;
66         if ((kColorIsKnown_Flag & commonFlags) && a.fColor == b.fColor) {
67             result.fColor = a.fColor;
68             result.fFlags = a.fFlags;
69         } else if (kIsOpaque_Flag & commonFlags) {
70             result.fFlags = kIsOpaque_Flag;
71         }
72         return result;
73     }
74 
75 private:
76     enum Flags {
77         kColorIsKnown_Flag = 0x1,
78         kIsOpaque_Flag = 0x2,
79     };
80     uint32_t fFlags;
81     GrColor fColor;
82 };
83 
84 enum class GrProcessorAnalysisCoverage { kNone, kSingleChannel, kLCD };
85 
86 /**
87  * GrColorFragmentProcessorAnalysis gathers invariant data from a set of color fragment processor.
88  * It is used to recognize optimizations that can simplify the generated shader or make blending
89  * more effecient.
90  */
91 class GrColorFragmentProcessorAnalysis {
92 public:
93     GrColorFragmentProcessorAnalysis() = default;
94 
GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor & input)95     GrColorFragmentProcessorAnalysis(const GrProcessorAnalysisColor& input)
96             : GrColorFragmentProcessorAnalysis() {
97         fAllProcessorsCompatibleWithCoverageAsAlpha = true;
98         fIsOpaque = input.isOpaque();
99         GrColor color;
100         if (input.isConstant(&color)) {
101             fLastKnownOutputColor = GrColor4f::FromGrColor(color);
102             fProcessorsVisitedWithKnownOutput = 0;
103         }
104     }
105 
reset(const GrProcessorAnalysisColor & input)106     void reset(const GrProcessorAnalysisColor& input) {
107         *this = GrColorFragmentProcessorAnalysis(input);
108     }
109 
110     /**
111      * Runs through a series of processors and updates calculated values. This can be called
112      * repeatedly for cases when the sequence of processors is not in a contiguous array.
113      */
114     void analyzeProcessors(const GrFragmentProcessor* const* processors, int cnt);
115 
isOpaque()116     bool isOpaque() const { return fIsOpaque; }
117 
118     /**
119      * Are all the fragment processors compatible with conflating coverage with color prior to the
120      * the first fragment processor. This result assumes that processors that should be eliminated
121      * as indicated by initialProcessorsToEliminate() are in fact eliminated.
122      */
allProcessorsCompatibleWithCoverageAsAlpha()123     bool allProcessorsCompatibleWithCoverageAsAlpha() const {
124         return fAllProcessorsCompatibleWithCoverageAsAlpha;
125     }
126 
127     /**
128      * Do any of the fragment processors require local coords. This result assumes that
129      * processors that should be eliminated as indicated by initialProcessorsToEliminate() are in
130      * fact eliminated.
131      */
usesLocalCoords()132     bool usesLocalCoords() const { return fUsesLocalCoords; }
133 
134     /**
135      * If we detected that the result after the first N processors is a known color then we
136      * eliminate those N processors and replace the GrDrawOp's color input to the GrPipeline with
137      * the known output of the Nth processor, so that the Nth+1 fragment processor (or the XP if
138      * there are only N processors) sees its expected input. If this returns 0 then there are no
139      * processors to eliminate.
140      */
initialProcessorsToEliminate(GrColor * newPipelineInputColor)141     int initialProcessorsToEliminate(GrColor* newPipelineInputColor) const {
142         if (fProcessorsVisitedWithKnownOutput > 0) {
143             *newPipelineInputColor = fLastKnownOutputColor.toGrColor();
144         }
145         return SkTMax(0, fProcessorsVisitedWithKnownOutput);
146     }
147 
initialProcessorsToEliminate(GrColor4f * newPipelineInputColor)148     int initialProcessorsToEliminate(GrColor4f* newPipelineInputColor) const {
149         if (fProcessorsVisitedWithKnownOutput > 0) {
150             *newPipelineInputColor = fLastKnownOutputColor;
151         }
152         return SkTMax(0, fProcessorsVisitedWithKnownOutput);
153     }
154 
outputColor()155     GrProcessorAnalysisColor outputColor() const {
156         if (fProcessorsVisitedWithKnownOutput != fTotalProcessorsVisited) {
157             return GrProcessorAnalysisColor(fIsOpaque ? GrProcessorAnalysisColor::Opaque::kYes
158                                                       : GrProcessorAnalysisColor::Opaque::kNo);
159         }
160         return GrProcessorAnalysisColor(fLastKnownOutputColor.toGrColor());
161     }
162 
163 private:
164     int fTotalProcessorsVisited = 0;
165     // negative one means even the color is unknown before adding the first processor.
166     int fProcessorsVisitedWithKnownOutput = -1;
167     bool fIsOpaque = false;
168     bool fAllProcessorsCompatibleWithCoverageAsAlpha = true;
169     bool fUsesLocalCoords = false;
170     GrColor4f fLastKnownOutputColor;
171 };
172 
173 #endif
174