• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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