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