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 #include "src/gpu/ganesh/effects/GrPorterDuffXferProcessor.h"
9
10 #include "include/gpu/GrTypes.h"
11 #include "include/private/base/SkMacros.h"
12 #include "include/private/base/SkTo.h"
13 #include "src/gpu/Blend.h"
14 #include "src/gpu/KeyBuilder.h"
15 #include "src/gpu/ganesh/GrCaps.h"
16 #include "src/gpu/ganesh/GrPipeline.h"
17 #include "src/gpu/ganesh/GrProcessor.h"
18 #include "src/gpu/ganesh/GrProcessorAnalysis.h"
19 #include "src/gpu/ganesh/GrXferProcessor.h"
20 #include "src/gpu/ganesh/glsl/GrGLSLBlend.h"
21 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
22 #include "src/gpu/ganesh/glsl/GrGLSLProgramDataManager.h"
23 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
24
25 /**
26 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
27 */
28 class BlendFormula {
29 public:
30 /**
31 * Values the shader can write to primary and secondary outputs. These are all modulated by
32 * coverage. The XP will ignore the multiplies when not using coverage.
33 */
34 enum OutputType {
35 kNone_OutputType, //<! 0
36 kCoverage_OutputType, //<! inputCoverage
37 kModulate_OutputType, //<! inputColor * inputCoverage
38 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
39 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
40 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
41
42 kLast_OutputType = kISCModulate_OutputType
43 };
44
BlendFormula(OutputType primaryOut,OutputType secondaryOut,skgpu::BlendEquation equation,skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)45 constexpr BlendFormula(OutputType primaryOut,
46 OutputType secondaryOut,
47 skgpu::BlendEquation equation,
48 skgpu::BlendCoeff srcCoeff,
49 skgpu::BlendCoeff dstCoeff)
50 : fPrimaryOutputType(primaryOut)
51 , fSecondaryOutputType(secondaryOut)
52 , fBlendEquation(SkTo<uint8_t>(equation))
53 , fSrcCoeff(SkTo<uint8_t>(srcCoeff))
54 , fDstCoeff(SkTo<uint8_t>(dstCoeff))
55 , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {}
56
57 BlendFormula(const BlendFormula&) = default;
58 BlendFormula& operator=(const BlendFormula&) = default;
59
operator ==(const BlendFormula & that) const60 bool operator==(const BlendFormula& that) const {
61 return fPrimaryOutputType == that.fPrimaryOutputType &&
62 fSecondaryOutputType == that. fSecondaryOutputType &&
63 fBlendEquation == that.fBlendEquation &&
64 fSrcCoeff == that.fSrcCoeff &&
65 fDstCoeff == that.fDstCoeff &&
66 fProps == that.fProps;
67 }
68
hasSecondaryOutput() const69 bool hasSecondaryOutput() const {
70 return kNone_OutputType != fSecondaryOutputType;
71 }
modifiesDst() const72 bool modifiesDst() const {
73 return SkToBool(fProps & kModifiesDst_Property);
74 }
unaffectedByDst() const75 bool unaffectedByDst() const {
76 return SkToBool(fProps & kUnaffectedByDst_Property);
77 }
78 // We don't always fully optimize the blend formula (e.g., for opaque src-over), so we include
79 // an "IfOpaque" variant to help set AnalysisProperties::kUnaffectedByDstValue in those cases.
unaffectedByDstIfOpaque() const80 bool unaffectedByDstIfOpaque() const {
81 return SkToBool(fProps & kUnaffectedByDstIfOpaque_Property);
82 }
usesInputColor() const83 bool usesInputColor() const {
84 return SkToBool(fProps & kUsesInputColor_Property);
85 }
canTweakAlphaForCoverage() const86 bool canTweakAlphaForCoverage() const {
87 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
88 }
89
equation() const90 skgpu::BlendEquation equation() const {
91 return static_cast<skgpu::BlendEquation>(fBlendEquation);
92 }
93
srcCoeff() const94 skgpu::BlendCoeff srcCoeff() const {
95 return static_cast<skgpu::BlendCoeff>(fSrcCoeff);
96 }
97
dstCoeff() const98 skgpu::BlendCoeff dstCoeff() const {
99 return static_cast<skgpu::BlendCoeff>(fDstCoeff);
100 }
101
primaryOutput() const102 OutputType primaryOutput() const {
103 return fPrimaryOutputType;
104 }
105
secondaryOutput() const106 OutputType secondaryOutput() const {
107 return fSecondaryOutputType;
108 }
109
110 private:
111 enum Properties {
112 kModifiesDst_Property = 1 << 0,
113 kUnaffectedByDst_Property = 1 << 1,
114 kUnaffectedByDstIfOpaque_Property = 1 << 2,
115 kUsesInputColor_Property = 1 << 3,
116 kCanTweakAlphaForCoverage_Property = 1 << 4,
117
118 kLast_Property = kCanTweakAlphaForCoverage_Property
119 };
120 SK_DECL_BITFIELD_OPS_FRIENDS(Properties)
121
122 /**
123 * Deduce the properties of a BlendFormula.
124 */
125 static constexpr Properties GetProperties(OutputType PrimaryOut,
126 OutputType SecondaryOut,
127 skgpu::BlendEquation BlendEquation,
128 skgpu::BlendCoeff SrcCoeff,
129 skgpu::BlendCoeff DstCoeff);
130
131 struct {
132 // We allot the enums one more bit than they require because MSVC seems to sign-extend
133 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
134 OutputType fPrimaryOutputType : 4;
135 OutputType fSecondaryOutputType : 4;
136 uint32_t fBlendEquation : 6;
137 uint32_t fSrcCoeff : 6;
138 uint32_t fDstCoeff : 6;
139 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
140 };
141
142 static_assert(kLast_OutputType < (1 << 3));
143 static_assert(static_cast<int>(skgpu::BlendEquation::kLast) < (1 << 5));
144 static_assert(static_cast<int>(skgpu::BlendCoeff::kLast) < (1 << 5));
145 static_assert(kLast_Property < (1 << 6));
146 };
147
148 static_assert(4 == sizeof(BlendFormula));
149
SK_MAKE_BITFIELD_OPS(BlendFormula::Properties)150 SK_MAKE_BITFIELD_OPS(BlendFormula::Properties)
151
152 constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut,
153 OutputType SecondaryOut,
154 skgpu::BlendEquation BlendEquation,
155 skgpu::BlendCoeff SrcCoeff,
156 skgpu::BlendCoeff DstCoeff) {
157 return
158 // The provided formula should already be optimized before a BlendFormula is constructed.
159 // Assert that here while setting up the properties in the constexpr constructor.
160 SkASSERT((kNone_OutputType == PrimaryOut) ==
161 !skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)),
162 SkASSERT(!skgpu::BlendCoeffRefsSrc2(SrcCoeff)),
163 SkASSERT((kNone_OutputType == SecondaryOut) == !skgpu::BlendCoeffRefsSrc2(DstCoeff)),
164 SkASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut),
165 SkASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut),
166
167 static_cast<Properties>(
168 (skgpu::BlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) |
169 (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, false/*srcColorIsOpaque*/)
170 ? kUnaffectedByDst_Property
171 : 0) |
172 (!skgpu::BlendCoeffsUseDstColor(SrcCoeff, DstCoeff, true/*srcColorIsOpaque*/)
173 ? kUnaffectedByDstIfOpaque_Property
174 : 0) |
175 ((PrimaryOut >= kModulate_OutputType &&
176 skgpu::BlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) ||
177 (SecondaryOut >= kModulate_OutputType &&
178 skgpu::BlendCoeffRefsSrc2(DstCoeff))
179 ? kUsesInputColor_Property
180 : 0) | // We assert later that SrcCoeff doesn't ref src2.
181 ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
182 kNone_OutputType == SecondaryOut &&
183 skgpu::BlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff)
184 ? kCanTweakAlphaForCoverage_Property
185 : 0));
186 }
187
188 /**
189 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
190 * Porter Duff formula.
191 */
MakeCoeffFormula(skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)192 static constexpr BlendFormula MakeCoeffFormula(skgpu::BlendCoeff srcCoeff,
193 skgpu::BlendCoeff dstCoeff) {
194 // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none.
195 return (skgpu::BlendCoeff::kZero == srcCoeff &&
196 (skgpu::BlendCoeff::kZero == dstCoeff || skgpu::BlendCoeff::kOne == dstCoeff))
197 ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType,
198 skgpu::BlendEquation::kAdd, skgpu::BlendCoeff::kZero, dstCoeff)
199 : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType,
200 skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff);
201 }
202
203 /**
204 * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in
205 * LCD dst-out.
206 */
MakeSAModulateFormula(skgpu::BlendCoeff srcCoeff,skgpu::BlendCoeff dstCoeff)207 static constexpr BlendFormula MakeSAModulateFormula(skgpu::BlendCoeff srcCoeff,
208 skgpu::BlendCoeff dstCoeff) {
209 return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType,
210 skgpu::BlendEquation::kAdd, srcCoeff, dstCoeff);
211 }
212
213 /**
214 * When there is coverage, the equation with f=coverage is:
215 *
216 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
217 *
218 * This can be rewritten as:
219 *
220 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
221 *
222 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
223 * HW dst coeff with IS2C.
224 *
225 * Xfer modes: dst-atop (Sa!=1)
226 */
MakeCoverageFormula(BlendFormula::OutputType oneMinusDstCoeffModulateOutput,skgpu::BlendCoeff srcCoeff)227 static constexpr BlendFormula MakeCoverageFormula(
228 BlendFormula::OutputType oneMinusDstCoeffModulateOutput, skgpu::BlendCoeff srcCoeff) {
229 return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput,
230 skgpu::BlendEquation::kAdd, srcCoeff, skgpu::BlendCoeff::kIS2C);
231 }
232
233 /**
234 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
235 *
236 * D' = f * D * dstCoeff + (1-f) * D
237 *
238 * This can be rewritten as:
239 *
240 * D' = D - D * [f * (1 - dstCoeff)]
241 *
242 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
243 * subtract HW blend equation with coeffs of (DC, One).
244 *
245 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
246 */
MakeCoverageSrcCoeffZeroFormula(BlendFormula::OutputType oneMinusDstCoeffModulateOutput)247 static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula(
248 BlendFormula::OutputType oneMinusDstCoeffModulateOutput) {
249 return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType,
250 skgpu::BlendEquation::kReverseSubtract, skgpu::BlendCoeff::kDC,
251 skgpu::BlendCoeff::kOne);
252 }
253
254 /**
255 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
256 *
257 * D' = f * S * srcCoeff + (1-f) * D
258 *
259 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
260 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
261 *
262 * Xfer modes (Sa!=1): src, src-in, src-out
263 */
MakeCoverageDstCoeffZeroFormula(skgpu::BlendCoeff srcCoeff)264 static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(skgpu::BlendCoeff srcCoeff) {
265 return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType,
266 skgpu::BlendEquation::kAdd, srcCoeff, skgpu::BlendCoeff::kIS2A);
267 }
268
269 /**
270 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
271 * with and without an opaque input color. Optimization properties are deduced at compile time so we
272 * can make runtime decisions quickly. RGB coverage is not supported.
273 */
274 static constexpr BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
275 /*>> No coverage, input color unknown <<*/ {{
276
277 /* clear */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
278 /* src */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kZero),
279 /* dst */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
280 /* src-over */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
281 /* dst-over */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
282 /* src-in */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
283 /* dst-in */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSA),
284 /* src-out */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
285 /* dst-out */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
286 /* src-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
287 /* dst-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kSA),
288 /* xor */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
289 /* plus */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
290 /* modulate */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
291 /* screen */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC),
292
293 }, /*>> Has coverage, input color unknown <<*/ {
294
295 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
296 /* src */ MakeCoverageDstCoeffZeroFormula(skgpu::BlendCoeff::kOne),
297 /* dst */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
298 /* src-over */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
299 /* dst-over */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
300 /* src-in */ MakeCoverageDstCoeffZeroFormula(skgpu::BlendCoeff::kDA),
301 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
302 /* src-out */ MakeCoverageDstCoeffZeroFormula(skgpu::BlendCoeff::kIDA),
303 /* dst-out */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kISA),
304 /* src-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
305 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType,
306 skgpu::BlendCoeff::kIDA),
307 /* xor */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
308 /* plus */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
309 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
310 /* screen */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC),
311
312 }}, /*>> No coverage, input color opaque <<*/ {{
313
314 /* clear */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
315 /* src */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kZero),
316 /* dst */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
317 /* src-over */ MakeCoeffFormula(skgpu::BlendCoeff::kOne,
318 skgpu::BlendCoeff::kISA), // see comment below
319 /* dst-over */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
320 /* src-in */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
321 /* dst-in */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
322 /* src-out */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
323 /* dst-out */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kZero),
324 /* src-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kZero),
325 /* dst-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
326 /* xor */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kZero),
327 /* plus */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
328 /* modulate */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kSC),
329 /* screen */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC),
330
331 }, /*>> Has coverage, input color opaque <<*/ {
332
333 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
334 /* src */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
335 /* dst */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
336 /* src-over */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA),
337 /* dst-over */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
338 /* src-in */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
339 /* dst-in */ MakeCoeffFormula(skgpu::BlendCoeff::kZero, skgpu::BlendCoeff::kOne),
340 /* src-out */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
341 /* dst-out */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
342 /* src-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kDA, skgpu::BlendCoeff::kISA),
343 /* dst-atop */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kOne),
344 /* xor */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA, skgpu::BlendCoeff::kISA),
345 /* plus */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kOne),
346 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
347 /* screen */ MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISC),
348 }}};
349 // In the above table src-over is not optimized to src mode when the color is opaque because we
350 // found no advantage to doing so. Also, we are using a global src-over XP in most cases which is
351 // not specialized for opaque input. For GPUs where dropping to src (and thus able to disable
352 // blending) is an advantage we change the blend mode to src before getitng the blend formula from
353 // this table.
354 static constexpr BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
355 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
356 /* src */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType,
357 skgpu::BlendCoeff::kOne),
358 /* dst */ MakeCoeffFormula(skgpu::BlendCoeff::kZero,
359 skgpu::BlendCoeff::kOne),
360 /* src-over */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType,
361 skgpu::BlendCoeff::kOne),
362 /* dst-over */ MakeCoeffFormula(skgpu::BlendCoeff::kIDA,
363 skgpu::BlendCoeff::kOne),
364 /* src-in */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType,
365 skgpu::BlendCoeff::kDA),
366 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
367 /* src-out */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType,
368 skgpu::BlendCoeff::kIDA),
369 /* dst-out */ MakeSAModulateFormula(skgpu::BlendCoeff::kZero,
370 skgpu::BlendCoeff::kISC),
371 /* src-atop */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType,
372 skgpu::BlendCoeff::kDA),
373 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType,
374 skgpu::BlendCoeff::kIDA),
375 /* xor */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType,
376 skgpu::BlendCoeff::kIDA),
377 /* plus */ MakeCoeffFormula(skgpu::BlendCoeff::kOne,
378 skgpu::BlendCoeff::kOne),
379 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
380 /* screen */ MakeCoeffFormula(skgpu::BlendCoeff::kOne,
381 skgpu::BlendCoeff::kISC),
382 };
383
get_blend_formula(bool isOpaque,bool hasCoverage,SkBlendMode xfermode)384 static BlendFormula get_blend_formula(bool isOpaque,
385 bool hasCoverage,
386 SkBlendMode xfermode) {
387 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
388 return gBlendTable[isOpaque][hasCoverage][(int)xfermode];
389 }
390
get_lcd_blend_formula(SkBlendMode xfermode)391 static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) {
392 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
393
394 return gLCDBlendTable[(int)xfermode];
395 }
396
397 ///////////////////////////////////////////////////////////////////////////////
398
399 class PorterDuffXferProcessor : public GrXferProcessor {
400 public:
PorterDuffXferProcessor(BlendFormula blendFormula,GrProcessorAnalysisCoverage coverage)401 PorterDuffXferProcessor(BlendFormula blendFormula, GrProcessorAnalysisCoverage coverage)
402 : INHERITED(kPorterDuffXferProcessor_ClassID, /*willReadDstColor=*/false, coverage)
403 , fBlendFormula(blendFormula) {
404 }
405
name() const406 const char* name() const override { return "Porter Duff"; }
407
408 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
409
getBlendFormula() const410 BlendFormula getBlendFormula() const { return fBlendFormula; }
411
412 private:
413 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
414
onHasSecondaryOutput() const415 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
416
onGetBlendInfo(skgpu::BlendInfo * blendInfo) const417 void onGetBlendInfo(skgpu::BlendInfo* blendInfo) const override {
418 blendInfo->fEquation = fBlendFormula.equation();
419 blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
420 blendInfo->fDstBlend = fBlendFormula.dstCoeff();
421 blendInfo->fWritesColor = fBlendFormula.modifiesDst();
422 }
423
onIsEqual(const GrXferProcessor & xpBase) const424 bool onIsEqual(const GrXferProcessor& xpBase) const override {
425 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
426 return fBlendFormula == xp.fBlendFormula;
427 }
428
429 const BlendFormula fBlendFormula;
430
431 using INHERITED = GrXferProcessor;
432 };
433
434 ///////////////////////////////////////////////////////////////////////////////
435
append_color_output(const PorterDuffXferProcessor & xp,GrGLSLXPFragmentBuilder * fragBuilder,BlendFormula::OutputType outputType,const char * output,const char * inColor,const char * inCoverage)436 static void append_color_output(const PorterDuffXferProcessor& xp,
437 GrGLSLXPFragmentBuilder* fragBuilder,
438 BlendFormula::OutputType outputType, const char* output,
439 const char* inColor, const char* inCoverage) {
440 SkASSERT(inCoverage);
441 SkASSERT(inColor);
442 switch (outputType) {
443 case BlendFormula::kNone_OutputType:
444 fragBuilder->codeAppendf("%s = half4(0.0);", output);
445 break;
446 case BlendFormula::kCoverage_OutputType:
447 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
448 break;
449 case BlendFormula::kModulate_OutputType:
450 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
451 break;
452 case BlendFormula::kSAModulate_OutputType:
453 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
454 break;
455 case BlendFormula::kISAModulate_OutputType:
456 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
457 break;
458 case BlendFormula::kISCModulate_OutputType:
459 fragBuilder->codeAppendf("%s = (half4(1.0) - %s) * %s;", output, inColor, inCoverage);
460 break;
461 default:
462 SK_ABORT("Unsupported output type.");
463 break;
464 }
465 }
466
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const467 void PorterDuffXferProcessor::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
468 b->add32(fBlendFormula.primaryOutput() | (fBlendFormula.secondaryOutput() << 3));
469 static_assert(BlendFormula::kLast_OutputType < 8);
470 }
471
makeProgramImpl() const472 std::unique_ptr<GrXferProcessor::ProgramImpl> PorterDuffXferProcessor::makeProgramImpl() const {
473 class Impl : public ProgramImpl {
474 private:
475 void emitOutputsForBlendState(const EmitArgs& args) override {
476 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
477 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
478
479 const BlendFormula& blendFormula = xp.fBlendFormula;
480 if (blendFormula.hasSecondaryOutput()) {
481 append_color_output(xp,
482 fragBuilder,
483 blendFormula.secondaryOutput(),
484 args.fOutputSecondary,
485 args.fInputColor,
486 args.fInputCoverage);
487 }
488 append_color_output(xp,
489 fragBuilder,
490 blendFormula.primaryOutput(),
491 args.fOutputPrimary,
492 args.fInputColor,
493 args.fInputCoverage);
494 }
495 };
496
497 return std::make_unique<Impl>();
498 }
499
500 ///////////////////////////////////////////////////////////////////////////////
501
502 class ShaderPDXferProcessor : public GrXferProcessor {
503 public:
ShaderPDXferProcessor(SkBlendMode xfermode,GrProcessorAnalysisCoverage coverage)504 ShaderPDXferProcessor(SkBlendMode xfermode, GrProcessorAnalysisCoverage coverage)
505 : INHERITED(kShaderPDXferProcessor_ClassID, /*willReadDstColor=*/true, coverage)
506 , fXfermode(xfermode) {
507 }
508
name() const509 const char* name() const override { return "Porter Duff Shader"; }
510
511 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
512
513 private:
514 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
515
onIsEqual(const GrXferProcessor & xpBase) const516 bool onIsEqual(const GrXferProcessor& xpBase) const override {
517 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
518 return fXfermode == xp.fXfermode;
519 }
520
521 const SkBlendMode fXfermode;
522
523 using INHERITED = GrXferProcessor;
524 };
525
526 ///////////////////////////////////////////////////////////////////////////////
527
528
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const529 void ShaderPDXferProcessor::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
530 b->add32(GrGLSLBlend::BlendKey(fXfermode));
531 }
532
makeProgramImpl() const533 std::unique_ptr<GrXferProcessor::ProgramImpl> ShaderPDXferProcessor::makeProgramImpl() const {
534 class Impl : public ProgramImpl {
535 private:
536 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
537 GrGLSLUniformHandler* uniformHandler,
538 const char* srcColor,
539 const char* srcCoverage,
540 const char* dstColor,
541 const char* outColor,
542 const char* outColorSecondary,
543 const GrXferProcessor& proc) override {
544 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
545
546 std::string blendExpr = GrGLSLBlend::BlendExpression(
547 &xp, uniformHandler, &fBlendUniform, srcColor, dstColor, xp.fXfermode);
548 fragBuilder->codeAppendf("%s = %s;", outColor, blendExpr.c_str());
549
550 // Apply coverage.
551 DefaultCoverageModulation(fragBuilder,
552 srcCoverage,
553 dstColor,
554 outColor,
555 outColorSecondary,
556 xp);
557 }
558
559 void onSetData(const GrGLSLProgramDataManager& pdman,
560 const GrXferProcessor& proc) override {
561 if (fBlendUniform.isValid()) {
562 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
563 GrGLSLBlend::SetBlendModeUniformData(pdman, fBlendUniform, xp.fXfermode);
564 }
565 }
566
567 GrGLSLUniformHandler::UniformHandle fBlendUniform;
568 };
569
570 return std::make_unique<Impl>();
571 }
572
573 ///////////////////////////////////////////////////////////////////////////////
574
575 class PDLCDXferProcessor : public GrXferProcessor {
576 public:
577 static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
578 const GrProcessorAnalysisColor& inputColor);
579
name() const580 const char* name() const override { return "Porter Duff LCD"; }
581
582 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
583
584 private:
585 PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha);
586
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder *) const587 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override {}
588
onGetBlendInfo(skgpu::BlendInfo * blendInfo) const589 void onGetBlendInfo(skgpu::BlendInfo* blendInfo) const override {
590 blendInfo->fSrcBlend = skgpu::BlendCoeff::kConstC;
591 blendInfo->fDstBlend = skgpu::BlendCoeff::kISC;
592 blendInfo->fBlendConstant = fBlendConstant;
593 }
594
onIsEqual(const GrXferProcessor & xpBase) const595 bool onIsEqual(const GrXferProcessor& xpBase) const override {
596 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
597 if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) {
598 return false;
599 }
600 return true;
601 }
602
603 SkPMColor4f fBlendConstant;
604 float fAlpha;
605
606 using INHERITED = GrXferProcessor;
607 };
608
PDLCDXferProcessor(const SkPMColor4f & blendConstant,float alpha)609 PDLCDXferProcessor::PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha)
610 : INHERITED(kPDLCDXferProcessor_ClassID, /*willReadDstColor=*/false,
611 GrProcessorAnalysisCoverage::kLCD)
612 , fBlendConstant(blendConstant)
613 , fAlpha(alpha) {
614 }
615
Make(SkBlendMode mode,const GrProcessorAnalysisColor & color)616 sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
617 const GrProcessorAnalysisColor& color) {
618 if (SkBlendMode::kSrcOver != mode) {
619 return nullptr;
620 }
621 SkPMColor4f blendConstantPM;
622 if (!color.isConstant(&blendConstantPM)) {
623 return nullptr;
624 }
625 SkColor4f blendConstantUPM = blendConstantPM.unpremul();
626 float alpha = blendConstantUPM.fA;
627 blendConstantPM = { blendConstantUPM.fR, blendConstantUPM.fG, blendConstantUPM.fB, 1 };
628 return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstantPM, alpha));
629 }
630
makeProgramImpl() const631 std::unique_ptr<GrXferProcessor::ProgramImpl> PDLCDXferProcessor::makeProgramImpl() const {
632 class Impl : public ProgramImpl {
633 private:
634 void emitOutputsForBlendState(const EmitArgs& args) override {
635 const char* alpha;
636 fAlphaUniform = args.fUniformHandler->addUniform(nullptr,
637 kFragment_GrShaderFlag,
638 SkSLType::kHalf,
639 "alpha",
640 &alpha);
641 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
642 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
643 // value of the src color. We know that there are no color stages (or we wouldn't have
644 // created this xp) and the r,g, and b channels of the op's input color are baked into
645 // the blend constant.
646 SkASSERT(args.fInputCoverage);
647 fragBuilder->codeAppendf("%s = %s * %s;",
648 args.fOutputPrimary,
649 alpha, args.fInputCoverage);
650 }
651
652 void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override {
653 float alpha = xp.cast<PDLCDXferProcessor>().fAlpha;
654 if (fLastAlpha != alpha) {
655 pdm.set1f(fAlphaUniform, alpha);
656 fLastAlpha = alpha;
657 }
658 }
659
660 GrGLSLUniformHandler::UniformHandle fAlphaUniform;
661 float fLastAlpha = SK_FloatNaN;
662 };
663
664 return std::make_unique<Impl>();
665 }
666
667 ///////////////////////////////////////////////////////////////////////////////
668
GrPorterDuffXPFactory(SkBlendMode xfermode)669 constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
670 : fBlendMode(xfermode) {}
671
Get(SkBlendMode blendMode)672 const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
673 SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
674
675 static constexpr const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
676 static constexpr const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
677 static constexpr const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
678 static constexpr const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
679 static constexpr const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
680 static constexpr const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
681 static constexpr const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
682 static constexpr const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
683 static constexpr const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
684 static constexpr const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
685 static constexpr const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
686 static constexpr const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
687 static constexpr const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
688 static constexpr const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
689 static constexpr const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
690
691 switch (blendMode) {
692 case SkBlendMode::kClear:
693 return &gClearPDXPF;
694 case SkBlendMode::kSrc:
695 return &gSrcPDXPF;
696 case SkBlendMode::kDst:
697 return &gDstPDXPF;
698 case SkBlendMode::kSrcOver:
699 return &gSrcOverPDXPF;
700 case SkBlendMode::kDstOver:
701 return &gDstOverPDXPF;
702 case SkBlendMode::kSrcIn:
703 return &gSrcInPDXPF;
704 case SkBlendMode::kDstIn:
705 return &gDstInPDXPF;
706 case SkBlendMode::kSrcOut:
707 return &gSrcOutPDXPF;
708 case SkBlendMode::kDstOut:
709 return &gDstOutPDXPF;
710 case SkBlendMode::kSrcATop:
711 return &gSrcATopPDXPF;
712 case SkBlendMode::kDstATop:
713 return &gDstATopPDXPF;
714 case SkBlendMode::kXor:
715 return &gXorPDXPF;
716 case SkBlendMode::kPlus:
717 return &gPlusPDXPF;
718 case SkBlendMode::kModulate:
719 return &gModulatePDXPF;
720 case SkBlendMode::kScreen:
721 return &gScreenPDXPF;
722 default:
723 SK_ABORT("Unexpected blend mode.");
724 }
725 }
726
makeXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const727 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
728 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
729 const GrCaps& caps, GrClampType clampType) const {
730 bool isLCD = coverage == GrProcessorAnalysisCoverage::kLCD;
731 // See comment in MakeSrcOverXferProcessor about color.isOpaque here
732 if (isLCD &&
733 SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && /*color.isOpaque() &&*/
734 !caps.shaderCaps()->fDualSourceBlendingSupport &&
735 !caps.shaderCaps()->fDstReadInShaderSupport) {
736 // If we don't have dual source blending or in shader dst reads, we fall back to this
737 // trick for rendering SrcOver LCD text instead of doing a dst copy.
738 return PDLCDXferProcessor::Make(fBlendMode, color);
739 }
740 BlendFormula blendFormula = [&](){
741 if (isLCD) {
742 return get_lcd_blend_formula(fBlendMode);
743 }
744 if (fBlendMode == SkBlendMode::kSrcOver && color.isOpaque() &&
745 coverage == GrProcessorAnalysisCoverage::kNone &&
746 caps.shouldCollapseSrcOverToSrcWhenAble())
747 {
748 return get_blend_formula(true, false, SkBlendMode::kSrc);
749 }
750 return get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage,
751 fBlendMode);
752 }();
753
754 // Skia always saturates after the kPlus blend mode, so it requires shader-based blending when
755 // pixels aren't guaranteed to automatically be normalized (i.e. any floating point config).
756 if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport) ||
757 (isLCD && (SkBlendMode::kSrcOver != fBlendMode /*|| !color.isOpaque()*/)) ||
758 (GrClampType::kAuto != clampType && SkBlendMode::kPlus == fBlendMode)) {
759 return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(fBlendMode, coverage));
760 }
761 return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
762 }
763
analysis_properties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType,SkBlendMode mode)764 static inline GrXPFactory::AnalysisProperties analysis_properties(
765 const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage,
766 const GrCaps& caps, GrClampType clampType, SkBlendMode mode) {
767 using AnalysisProperties = GrXPFactory::AnalysisProperties;
768 AnalysisProperties props = AnalysisProperties::kNone;
769 bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
770 bool isLCD = GrProcessorAnalysisCoverage::kLCD == coverage;
771 BlendFormula formula = [&](){
772 if (isLCD) {
773 return gLCDBlendTable[(int)mode];
774 }
775 return get_blend_formula(color.isOpaque(), hasCoverage, mode);
776 }();
777
778 if (formula.canTweakAlphaForCoverage() && !isLCD) {
779 props |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
780 }
781
782 if (isLCD) {
783 // See comment in MakeSrcOverXferProcessor about color.isOpaque here
784 if (SkBlendMode::kSrcOver == mode && color.isConstant() && /*color.isOpaque() &&*/
785 !caps.shaderCaps()->fDualSourceBlendingSupport &&
786 !caps.shaderCaps()->fDstReadInShaderSupport) {
787 props |= AnalysisProperties::kIgnoresInputColor;
788 } else {
789 // For LCD blending, if the color is not opaque we must read the dst in shader even if
790 // we have dual source blending. The opaqueness check must be done after blending so for
791 // simplicity we only allow src-over to not take the dst read path (though src, src-in,
792 // and DstATop would also work). We also fall into the dst read case for src-over if we
793 // do not have dual source blending.
794 if (SkBlendMode::kSrcOver != mode ||
795 /*!color.isOpaque() ||*/ // See comment in MakeSrcOverXferProcessor about isOpaque.
796 (formula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport)) {
797 props |= AnalysisProperties::kReadsDstInShader;
798 }
799 }
800 } else {
801 // With dual-source blending we never need the destination color in the shader.
802 if (!caps.shaderCaps()->fDualSourceBlendingSupport) {
803 if (formula.hasSecondaryOutput()) {
804 props |= AnalysisProperties::kReadsDstInShader;
805 }
806 }
807 }
808
809 if (GrClampType::kAuto != clampType && SkBlendMode::kPlus == mode) {
810 props |= AnalysisProperties::kReadsDstInShader;
811 }
812
813 if (!formula.modifiesDst() || !formula.usesInputColor()) {
814 props |= AnalysisProperties::kIgnoresInputColor;
815 }
816 if (formula.unaffectedByDst() || (formula.unaffectedByDstIfOpaque() && color.isOpaque() &&
817 !hasCoverage)) {
818 props |= AnalysisProperties::kUnaffectedByDstValue;
819 }
820 return props;
821 }
822
analysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const823 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
824 const GrProcessorAnalysisColor& color,
825 const GrProcessorAnalysisCoverage& coverage,
826 const GrCaps& caps,
827 GrClampType clampType) const {
828 return analysis_properties(color, coverage, caps, clampType, fBlendMode);
829 }
830
GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory) const831 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory)
832
833 #if GR_TEST_UTILS
834 const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
835 SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
836 return GrPorterDuffXPFactory::Get(mode);
837 }
838 #endif
839
TestGetXPOutputTypes(const GrXferProcessor * xp,int * outPrimary,int * outSecondary)840 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
841 int* outPrimary,
842 int* outSecondary) {
843 if (!!strcmp(xp->name(), "Porter Duff")) {
844 *outPrimary = *outSecondary = -1;
845 return;
846 }
847 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
848 *outPrimary = blendFormula.primaryOutput();
849 *outSecondary = blendFormula.secondaryOutput();
850 }
851
852 ////////////////////////////////////////////////////////////////////////////////////////////////
853 // SrcOver Global functions
854 ////////////////////////////////////////////////////////////////////////////////////////////////
SimpleSrcOverXP()855 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
856 static BlendFormula gSrcOverBlendFormula =
857 MakeCoeffFormula(skgpu::BlendCoeff::kOne, skgpu::BlendCoeff::kISA);
858 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula,
859 GrProcessorAnalysisCoverage::kSingleChannel);
860 return gSrcOverXP;
861 }
862
MakeSrcOverXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps)863 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
864 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
865 const GrCaps& caps) {
866 // We want to not make an xfer processor if possible. Thus for the simple case where we are not
867 // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
868 // the general case where we convert a src-over blend that has solid coverage and an opaque
869 // color to src-mode, which allows disabling of blending.
870 if (coverage != GrProcessorAnalysisCoverage::kLCD) {
871 if (color.isOpaque() && coverage == GrProcessorAnalysisCoverage::kNone &&
872 caps.shouldCollapseSrcOverToSrcWhenAble()) {
873 BlendFormula blendFormula = get_blend_formula(true, false, SkBlendMode::kSrc);
874 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
875 }
876 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
877 // We don't simply return the address of that XP here because our caller would have to unref
878 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
879 // safe.
880 return nullptr;
881 }
882
883 // Currently up the stack Skia is requiring that the dst is opaque or that the client has said
884 // the opaqueness doesn't matter. Thus for src-over we don't need to worry about the src color
885 // being opaque or not. This allows us to use faster code paths as well as avoid various bugs
886 // that occur with dst reads in the shader blending. For now we disable the check for
887 // opaqueness, but in the future we should pass down the knowledge about dst opaqueness and make
888 // the correct decision here.
889 //
890 // This also fixes a chrome bug on macs where we are getting random fuzziness when doing
891 // blending in the shader for non opaque sources.
892 if (color.isConstant() && /*color.isOpaque() &&*/
893 !caps.shaderCaps()->fDualSourceBlendingSupport &&
894 !caps.shaderCaps()->fDstReadInShaderSupport) {
895 // If we don't have dual source blending or in shader dst reads, we fall
896 // back to this trick for rendering SrcOver LCD text instead of doing a
897 // dst copy.
898 return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color);
899 }
900
901 BlendFormula blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
902 // See comment above regarding why the opaque check is commented out here.
903 if (/*!color.isOpaque() ||*/
904 (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->fDualSourceBlendingSupport)) {
905 return sk_sp<GrXferProcessor>(new ShaderPDXferProcessor(SkBlendMode::kSrcOver, coverage));
906 }
907 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
908 }
909
MakeNoCoverageXP(SkBlendMode blendmode)910 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
911 BlendFormula formula = get_blend_formula(false, false, blendmode);
912 return sk_make_sp<PorterDuffXferProcessor>(formula, GrProcessorAnalysisCoverage::kNone);
913 }
914
SrcOverAnalysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType)915 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
916 const GrProcessorAnalysisColor& color,
917 const GrProcessorAnalysisCoverage& coverage,
918 const GrCaps& caps,
919 GrClampType clampType) {
920 return analysis_properties(color, coverage, caps, clampType, SkBlendMode::kSrcOver);
921 }
922