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 GrInvariantOutput_DEFINED
9 #define GrInvariantOutput_DEFINED
10 
11 #include "GrColor.h"
12 
13 struct GrInitInvariantOutput {
GrInitInvariantOutputGrInitInvariantOutput14     GrInitInvariantOutput()
15         : fValidFlags(0)
16         , fColor(0)
17         , fIsSingleComponent(false)
18         , fIsLCDCoverage(false) {}
19 
setKnownFourComponentsGrInitInvariantOutput20     void setKnownFourComponents(GrColor color) {
21         fColor = color;
22         fValidFlags = kRGBA_GrColorComponentFlags;
23         fIsSingleComponent = false;
24     }
25 
setUnknownFourComponentsGrInitInvariantOutput26     void setUnknownFourComponents() {
27         fValidFlags = 0;
28         fIsSingleComponent = false;
29     }
30 
setUnknownOpaqueFourComponentsGrInitInvariantOutput31     void setUnknownOpaqueFourComponents() {
32         fColor = 0xff << GrColor_SHIFT_A;
33         fValidFlags = kA_GrColorComponentFlag;
34         fIsSingleComponent = false;
35     }
36 
setKnownSingleComponentGrInitInvariantOutput37     void setKnownSingleComponent(uint8_t alpha) {
38         fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
39         fValidFlags = kRGBA_GrColorComponentFlags;
40         fIsSingleComponent = true;
41     }
42 
setUnknownSingleComponentGrInitInvariantOutput43     void setUnknownSingleComponent() {
44         fValidFlags = 0;
45         fIsSingleComponent = true;
46     }
47 
setUsingLCDCoverageGrInitInvariantOutput48     void setUsingLCDCoverage() { fIsLCDCoverage = true; }
49 
50     uint32_t fValidFlags;
51     GrColor fColor;
52     bool fIsSingleComponent;
53     bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated
54 };
55 
56 class GrInvariantOutput {
57 public:
GrInvariantOutput(GrColor color,GrColorComponentFlags flags,bool isSingleComponent)58     GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent)
59         : fColor(color)
60         , fValidFlags(flags)
61         , fIsSingleComponent(isSingleComponent)
62         , fNonMulStageFound(false)
63         , fWillUseInputColor(true)
64         , fIsLCDCoverage(false) {}
65 
GrInvariantOutput(const GrInitInvariantOutput & io)66     GrInvariantOutput(const GrInitInvariantOutput& io)
67         : fColor(io.fColor)
68         , fValidFlags(io.fValidFlags)
69         , fIsSingleComponent(io.fIsSingleComponent)
70         , fNonMulStageFound(false)
71         , fWillUseInputColor(false)
72         , fIsLCDCoverage(io.fIsLCDCoverage) {}
73 
~GrInvariantOutput()74     virtual ~GrInvariantOutput() {}
75 
76     enum ReadInput {
77         kWill_ReadInput,
78         kWillNot_ReadInput,
79     };
80 
mulByUnknownOpaqueFourComponents()81     void mulByUnknownOpaqueFourComponents() {
82         SkDEBUGCODE(this->validate());
83         if (this->isOpaque()) {
84             fValidFlags = kA_GrColorComponentFlag;
85             fIsSingleComponent = false;
86         } else {
87             // Since the current state is not opaque we no longer care if the color being
88             // multiplied is opaque.
89             this->mulByUnknownFourComponents();
90         }
91         SkDEBUGCODE(this->validate());
92     }
93 
mulByUnknownFourComponents()94     void mulByUnknownFourComponents() {
95         SkDEBUGCODE(this->validate());
96         if (this->hasZeroAlpha()) {
97             this->internalSetToTransparentBlack();
98         } else {
99             this->internalSetToUnknown();
100         }
101         SkDEBUGCODE(this->validate());
102     }
103 
mulByUnknownSingleComponent()104     void mulByUnknownSingleComponent() {
105         SkDEBUGCODE(this->validate());
106         if (this->hasZeroAlpha()) {
107             this->internalSetToTransparentBlack();
108         } else {
109             // We don't need to change fIsSingleComponent in this case
110             fValidFlags = 0;
111         }
112         SkDEBUGCODE(this->validate());
113     }
114 
mulByKnownSingleComponent(uint8_t alpha)115     void mulByKnownSingleComponent(uint8_t alpha) {
116         SkDEBUGCODE(this->validate());
117         if (this->hasZeroAlpha() || 0 == alpha) {
118             this->internalSetToTransparentBlack();
119         } else {
120             if (alpha != 255) {
121                 // Multiply color by alpha
122                 fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha),
123                                          SkMulDiv255Round(GrColorUnpackG(fColor), alpha),
124                                          SkMulDiv255Round(GrColorUnpackB(fColor), alpha),
125                                          SkMulDiv255Round(GrColorUnpackA(fColor), alpha));
126                 // We don't need to change fIsSingleComponent in this case
127             }
128         }
129         SkDEBUGCODE(this->validate());
130     }
131 
mulByKnownFourComponents(GrColor color)132     void mulByKnownFourComponents(GrColor color) {
133         SkDEBUGCODE(this->validate());
134         uint32_t a;
135         if (GetAlphaAndCheckSingleChannel(color, &a)) {
136             this->mulByKnownSingleComponent(a);
137         } else {
138             if (color != 0xffffffff) {
139                 fColor = GrColorPackRGBA(
140                     SkMulDiv255Round(GrColorUnpackR(fColor), GrColorUnpackR(color)),
141                     SkMulDiv255Round(GrColorUnpackG(fColor), GrColorUnpackG(color)),
142                     SkMulDiv255Round(GrColorUnpackB(fColor), GrColorUnpackB(color)),
143                     SkMulDiv255Round(GrColorUnpackA(fColor), a));
144                 if (kRGBA_GrColorComponentFlags == fValidFlags) {
145                     fIsSingleComponent = GetAlphaAndCheckSingleChannel(fColor, &a);
146                 }
147             }
148         }
149         SkDEBUGCODE(this->validate());
150     }
151 
152     // Ignores the incoming color's RGB and muls its alpha by color.
mulAlphaByKnownFourComponents(GrColor color)153     void mulAlphaByKnownFourComponents(GrColor color) {
154         SkDEBUGCODE(this->validate());
155         uint32_t a;
156         if (GetAlphaAndCheckSingleChannel(color, &a)) {
157             this->mulAlphaByKnownSingleComponent(a);
158         } else if (fValidFlags & kA_GrColorComponentFlag) {
159             GrColor preAlpha = GrColorUnpackA(fColor);
160             if (0 == preAlpha) {
161                 this->internalSetToTransparentBlack();
162             } else {
163                 // We know that color has different component values
164                 fIsSingleComponent = false;
165                 fColor = GrColorPackRGBA(
166                     SkMulDiv255Round(preAlpha, GrColorUnpackR(color)),
167                     SkMulDiv255Round(preAlpha, GrColorUnpackG(color)),
168                     SkMulDiv255Round(preAlpha, GrColorUnpackB(color)),
169                     SkMulDiv255Round(preAlpha, a));
170                 fValidFlags = kRGBA_GrColorComponentFlags;
171             }
172         } else {
173             fIsSingleComponent = false;
174             fValidFlags = 0;
175         }
176         SkDEBUGCODE(this->validate());
177     }
178 
179     // Ignores the incoming color's RGB and muls its alpha by the alpha param and sets all channels
180     // equal to that value.
mulAlphaByKnownSingleComponent(uint8_t alpha)181     void mulAlphaByKnownSingleComponent(uint8_t alpha) {
182         SkDEBUGCODE(this->validate());
183         if (0 == alpha || this->hasZeroAlpha()) {
184             this->internalSetToTransparentBlack();
185         } else {
186             if (fValidFlags & kA_GrColorComponentFlag) {
187                 GrColor a = GrColorUnpackA(fColor);
188                 a = SkMulDiv255Round(alpha, a);
189                 fColor = GrColorPackRGBA(a, a, a, a);
190                 fValidFlags = kRGBA_GrColorComponentFlags;
191             } else {
192                 fValidFlags = 0;
193             }
194             fIsSingleComponent = true;
195         }
196         SkDEBUGCODE(this->validate());
197     }
198 
invalidateComponents(uint8_t invalidateFlags,ReadInput readsInput)199     void invalidateComponents(uint8_t invalidateFlags, ReadInput readsInput) {
200         SkDEBUGCODE(this->validate());
201         fValidFlags &= ~invalidateFlags;
202         fIsSingleComponent = false;
203         fNonMulStageFound = true;
204         if (kWillNot_ReadInput == readsInput) {
205             fWillUseInputColor = false;
206         }
207         SkDEBUGCODE(this->validate());
208     }
209 
setToOther(uint8_t validFlags,GrColor color,ReadInput readsInput)210     void setToOther(uint8_t validFlags, GrColor color, ReadInput readsInput) {
211         SkDEBUGCODE(this->validate());
212         fValidFlags = validFlags;
213         fColor = color;
214         fIsSingleComponent = false;
215         fNonMulStageFound = true;
216         if (kWillNot_ReadInput == readsInput) {
217             fWillUseInputColor = false;
218         }
219         if (kRGBA_GrColorComponentFlags == fValidFlags) {
220             uint32_t a;
221             if (GetAlphaAndCheckSingleChannel(color, &a)) {
222                 fIsSingleComponent = true;
223             }
224         } else if (kA_GrColorComponentFlag & fValidFlags) {
225             // Assuming fColor is premul means if a is 0 the color must be all 0s.
226             if (!GrColorUnpackA(fColor)) {
227                 this->internalSetToTransparentBlack();
228             }
229         }
230         SkDEBUGCODE(this->validate());
231     }
232 
setToUnknown(ReadInput readsInput)233     void setToUnknown(ReadInput readsInput) {
234         SkDEBUGCODE(this->validate());
235         this->internalSetToUnknown();
236         fNonMulStageFound= true;
237         if (kWillNot_ReadInput == readsInput) {
238             fWillUseInputColor = false;
239         }
240         SkDEBUGCODE(this->validate());
241     }
242 
243     // Temporary setter to handle LCD text correctly until we improve texture pixel config queries
244     // and thus can rely solely on number of coverage components for RGA vs single channel coverage.
setUsingLCDCoverage()245     void setUsingLCDCoverage() {
246         fIsLCDCoverage = true;
247     }
248 
color()249     GrColor color() const { return fColor; }
validFlags()250     uint8_t validFlags() const { return fValidFlags; }
251 
252     /**
253      * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
254      * same. If the flags are all set then all color components must be equal.
255      */
256     SkDEBUGCODE(void validate() const;)
257 
258 private:
259     friend class GrProcOptInfo;
260 
261     /** Extracts the alpha channel and returns true if r,g,b == a. */
GetAlphaAndCheckSingleChannel(GrColor color,uint32_t * alpha)262     static bool GetAlphaAndCheckSingleChannel(GrColor color, uint32_t* alpha) {
263         *alpha = GrColorUnpackA(color);
264         return *alpha == GrColorUnpackR(color) && *alpha == GrColorUnpackG(color) &&
265                *alpha == GrColorUnpackB(color);
266     }
267 
reset(GrColor color,GrColorComponentFlags flags,bool isSingleComponent)268     void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) {
269         fColor = color;
270         fValidFlags = flags;
271         fIsSingleComponent = isSingleComponent;
272         fNonMulStageFound = false;
273         fWillUseInputColor = true;
274     }
275 
reset(const GrInitInvariantOutput & io)276     void reset(const GrInitInvariantOutput& io) {
277         fColor = io.fColor;
278         fValidFlags = io.fValidFlags;
279         fIsSingleComponent = io.fIsSingleComponent;
280         fNonMulStageFound = false;
281         fWillUseInputColor = true;
282         fIsLCDCoverage = io.fIsLCDCoverage;
283     }
284 
internalSetToTransparentBlack()285     void internalSetToTransparentBlack() {
286         fValidFlags = kRGBA_GrColorComponentFlags;
287         fColor = 0;
288         fIsSingleComponent = true;
289     }
290 
internalSetToUnknown()291     void internalSetToUnknown() {
292         fValidFlags = 0;
293         fIsSingleComponent = false;
294     }
295 
hasZeroAlpha()296     bool hasZeroAlpha() const {
297         return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor));
298     }
299 
isOpaque()300     bool isOpaque() const {
301         return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor));
302     }
303 
isSolidWhite()304     bool isSolidWhite() const {
305         return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor);
306     }
307 
isSingleComponent()308     bool isSingleComponent() const { return fIsSingleComponent; }
309 
willUseInputColor()310     bool willUseInputColor() const { return fWillUseInputColor; }
resetWillUseInputColor()311     void resetWillUseInputColor() { fWillUseInputColor = true; }
312 
allStagesMulInput()313     bool allStagesMulInput() const { return !fNonMulStageFound; }
resetNonMulStageFound()314     void resetNonMulStageFound() { fNonMulStageFound = false; }
315 
isLCDCoverage()316     bool isLCDCoverage() const { return fIsLCDCoverage; }
317 
318     SkDEBUGCODE(bool colorComponentsAllEqual() const;)
319     /**
320      * If alpha is valid, check that any valid R,G,B values are <= A
321      */
322     SkDEBUGCODE(bool validPreMulColor() const;)
323 
324     GrColor fColor;
325     uint32_t fValidFlags;
326     bool fIsSingleComponent;
327     bool fNonMulStageFound;
328     bool fWillUseInputColor;
329     bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated
330 
331 };
332 
333 #endif
334 
335