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