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