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