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 | 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 | std::unique_ptr<GrFragmentProcessor> const fps[], |
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 | |