• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 skgpu_Blend_DEFINED
9 #define skgpu_Blend_DEFINED
10 
11 #include "include/core/SkSpan.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/SkColorData.h"
14 
15 enum class SkBlendMode;
16 class SkString;
17 
18 namespace skgpu {
19 
20 /**
21  * Equations for alpha-blending.
22  */
23 enum class BlendEquation : uint8_t {
24     // Basic blend equations.
25     kAdd,             //<! Cs*S + Cd*D
26     kSubtract,        //<! Cs*S - Cd*D
27     kReverseSubtract, //<! Cd*D - Cs*S
28 
29     // Advanced blend equations. These are described in the SVG and PDF specs.
30     kScreen,
31     kOverlay,
32     kDarken,
33     kLighten,
34     kColorDodge,
35     kColorBurn,
36     kHardLight,
37     kSoftLight,
38     kDifference,
39     kExclusion,
40     kMultiply,
41     kHSLHue,
42     kHSLSaturation,
43     kHSLColor,
44     kHSLLuminosity,
45 
46     kIllegal,
47 
48     kFirstAdvanced = kScreen,
49     kLast = kIllegal,
50 };
51 
52 static const int kBlendEquationCnt = static_cast<int>(BlendEquation::kLast) + 1;
53 
54 /**
55  * Coefficients for alpha-blending.
56  */
57 enum class BlendCoeff : uint8_t {
58     kZero,    //<! 0
59     kOne,     //<! 1
60     kSC,      //<! src color
61     kISC,     //<! one minus src color
62     kDC,      //<! dst color
63     kIDC,     //<! one minus dst color
64     kSA,      //<! src alpha
65     kISA,     //<! one minus src alpha
66     kDA,      //<! dst alpha
67     kIDA,     //<! one minus dst alpha
68     kConstC,  //<! constant color
69     kIConstC, //<! one minus constant color
70     kS2C,
71     kIS2C,
72     kS2A,
73     kIS2A,
74 
75     kIllegal,
76 
77     kLast = kIllegal,
78 };
79 
80 struct BlendInfo {
81     SkDEBUGCODE(SkString dump() const;)
82 
83     bool operator==(const BlendInfo& other) const {
84         return fEquation == other.fEquation &&
85                fSrcBlend == other.fSrcBlend &&
86                fDstBlend == other.fDstBlend &&
87                fBlendConstant == other.fBlendConstant &&
88                fWritesColor == other.fWritesColor;
89     }
90 
91     skgpu::BlendEquation fEquation = skgpu::BlendEquation::kAdd;
92     skgpu::BlendCoeff    fSrcBlend = skgpu::BlendCoeff::kOne;
93     skgpu::BlendCoeff    fDstBlend = skgpu::BlendCoeff::kZero;
94     SkPMColor4f          fBlendConstant = SK_PMColor4fTRANSPARENT;
95     bool                 fWritesColor = true;
96 };
97 
98 static const int kBlendCoeffCnt = static_cast<int>(BlendCoeff::kLast) + 1;
99 
BlendCoeffRefsSrc(const BlendCoeff coeff)100 static constexpr bool BlendCoeffRefsSrc(const BlendCoeff coeff) {
101     return BlendCoeff::kSC == coeff || BlendCoeff::kISC == coeff || BlendCoeff::kSA == coeff ||
102            BlendCoeff::kISA == coeff;
103 }
104 
BlendCoeffRefsDst(const BlendCoeff coeff)105 static constexpr bool BlendCoeffRefsDst(const BlendCoeff coeff) {
106     return BlendCoeff::kDC == coeff || BlendCoeff::kIDC == coeff || BlendCoeff::kDA == coeff ||
107            BlendCoeff::kIDA == coeff;
108 }
109 
BlendCoeffRefsSrc2(const BlendCoeff coeff)110 static constexpr bool BlendCoeffRefsSrc2(const BlendCoeff coeff) {
111     return BlendCoeff::kS2C == coeff || BlendCoeff::kIS2C == coeff ||
112            BlendCoeff::kS2A == coeff || BlendCoeff::kIS2A == coeff;
113 }
114 
BlendCoeffsUseSrcColor(BlendCoeff srcCoeff,BlendCoeff dstCoeff)115 static constexpr bool BlendCoeffsUseSrcColor(BlendCoeff srcCoeff, BlendCoeff dstCoeff) {
116     return BlendCoeff::kZero != srcCoeff || BlendCoeffRefsSrc(dstCoeff);
117 }
118 
BlendCoeffsUseDstColor(BlendCoeff srcCoeff,BlendCoeff dstCoeff,bool srcColorIsOpaque)119 static constexpr bool BlendCoeffsUseDstColor(BlendCoeff srcCoeff,
120                                              BlendCoeff dstCoeff,
121                                              bool srcColorIsOpaque) {
122     return BlendCoeffRefsDst(srcCoeff) ||
123            (dstCoeff != BlendCoeff::kZero && !(dstCoeff == BlendCoeff::kISA && srcColorIsOpaque));
124 }
125 
BlendEquationIsAdvanced(BlendEquation equation)126 static constexpr bool BlendEquationIsAdvanced(BlendEquation equation) {
127     return equation >= BlendEquation::kFirstAdvanced &&
128            equation != BlendEquation::kIllegal;
129 }
130 
BlendModifiesDst(BlendEquation equation,BlendCoeff srcCoeff,BlendCoeff dstCoeff)131 static constexpr bool BlendModifiesDst(BlendEquation equation,
132                                        BlendCoeff srcCoeff,
133                                        BlendCoeff dstCoeff) {
134     return (BlendEquation::kAdd != equation && BlendEquation::kReverseSubtract != equation) ||
135             BlendCoeff::kZero != srcCoeff || BlendCoeff::kOne != dstCoeff;
136 }
137 
BlendCoeffRefsConstant(const BlendCoeff coeff)138 static constexpr bool BlendCoeffRefsConstant(const BlendCoeff coeff) {
139     return coeff == BlendCoeff::kConstC || coeff == BlendCoeff::kIConstC;
140 }
141 
BlendShouldDisable(BlendEquation equation,BlendCoeff srcCoeff,BlendCoeff dstCoeff)142 static constexpr bool BlendShouldDisable(BlendEquation equation,
143                                          BlendCoeff srcCoeff,
144                                          BlendCoeff dstCoeff) {
145     return (BlendEquation::kAdd == equation || BlendEquation::kSubtract == equation) &&
146             BlendCoeff::kOne == srcCoeff && BlendCoeff::kZero == dstCoeff;
147 }
148 
149 /**
150  * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
151  *
152  * For "add" and "reverse subtract" the blend equation with f=coverage is:
153  *
154  *   D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
155  *      = f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
156  *
157  * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the
158  * following relationship holds:
159  *
160  *   (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
161  *
162  * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.)
163  *
164  * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff
165  * does not reference S). For the dst term, this will work as long as the following is true:
166  *|
167  *   dstCoeff' == f * dstCoeff + (1 - f)
168  *   dstCoeff' == 1 - f * (1 - dstCoeff)
169  *
170  * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in
171  * dstCoeff references S.
172  *
173  * Moreover, if the blend doesn't modify the dst at all then it is ok to arbitrarily modify the src
174  * color so folding in coverage is allowed.
175  */
BlendAllowsCoverageAsAlpha(BlendEquation equation,BlendCoeff srcCoeff,BlendCoeff dstCoeff)176 static constexpr bool BlendAllowsCoverageAsAlpha(BlendEquation equation,
177                                                  BlendCoeff srcCoeff,
178                                                  BlendCoeff dstCoeff) {
179     return BlendEquationIsAdvanced(equation) ||
180            !BlendModifiesDst(equation, srcCoeff, dstCoeff) ||
181            ((BlendEquation::kAdd == equation || BlendEquation::kReverseSubtract == equation) &&
182             !BlendCoeffRefsSrc(srcCoeff) &&
183             (BlendCoeff::kOne == dstCoeff || BlendCoeff::kISC == dstCoeff ||
184              BlendCoeff::kISA == dstCoeff));
185 }
186 
187 /**
188  * Returns the name of the SkSL built-in blend function for a SkBlendMode.
189  */
190 const char* BlendFuncName(SkBlendMode mode);
191 
192 /**
193  * If a blend can be represented by `blend_porter_duff`, returns the associated blend constants as
194  * an array of four floats. If not, returns an empty span.
195  */
196 SkSpan<const float> GetPorterDuffBlendConstants(SkBlendMode mode);
197 
198 /**
199  * Returns a pair of "blend function + uniform data" for a particular SkBlendMode.
200  * This allows us to use fewer unique functions when generating shaders, e.g. every Porter-Duff
201  * blend can use the same function.
202  */
203 struct ReducedBlendModeInfo {
204     const char*         fFunction;
205     SkSpan<const float> fUniformData;
206 };
207 ReducedBlendModeInfo GetReducedBlendModeInfo(SkBlendMode mode);
208 
209 } // namespace skgpu
210 
211 #endif // skgpu_Blend_DEFINED
212