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