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 "effects/GrPorterDuffXferProcessor.h"
9
10 #include "GrBlend.h"
11 #include "GrCaps.h"
12 #include "GrPipeline.h"
13 #include "GrProcessor.h"
14 #include "GrProcOptInfo.h"
15 #include "GrTypes.h"
16 #include "GrXferProcessor.h"
17 #include "glsl/GrGLSLBlend.h"
18 #include "glsl/GrGLSLFragmentShaderBuilder.h"
19 #include "glsl/GrGLSLProgramDataManager.h"
20 #include "glsl/GrGLSLUniformHandler.h"
21 #include "glsl/GrGLSLXferProcessor.h"
22 #include <utility>
23
24 /**
25 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
26 */
27 struct BlendFormula {
28 public:
29 /**
30 * Values the shader can write to primary and secondary outputs. These must all be modulated by
31 * coverage to support mixed samples. 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
44 enum Properties {
45 kModifiesDst_Property = 1,
46 kUsesDstColor_Property = 1 << 1,
47 kUsesInputColor_Property = 1 << 2,
48 kCanTweakAlphaForCoverage_Property = 1 << 3,
49
50 kLast_Property = kCanTweakAlphaForCoverage_Property
51 };
52
operator =BlendFormula53 BlendFormula& operator =(const BlendFormula& other) {
54 fData = other.fData;
55 return *this;
56 }
57
operator ==BlendFormula58 bool operator ==(const BlendFormula& other) const {
59 return fData == other.fData;
60 }
61
hasSecondaryOutputBlendFormula62 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
modifiesDstBlendFormula63 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
usesDstColorBlendFormula64 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
usesInputColorBlendFormula65 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
canTweakAlphaForCoverageBlendFormula66 bool canTweakAlphaForCoverage() const {
67 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
68 }
69
70 /**
71 * Deduce the properties of a compile-time constant BlendFormula.
72 */
73 template<OutputType PrimaryOut, OutputType SecondaryOut,
74 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
75 struct get_properties : std::integral_constant<Properties, static_cast<Properties>(
76
77 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
78 kModifiesDst_Property : 0) |
79
80 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
81 kUsesDstColor_Property : 0) |
82
83 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
84 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
85 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
86
87 (kModulate_OutputType == PrimaryOut &&
88 kNone_OutputType == SecondaryOut &&
89 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
90 kCanTweakAlphaForCoverage_Property : 0))> {
91
92 // The provided formula should already be optimized.
93 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
94 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
95 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
96 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
97 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
98 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
99 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
100 };
101
102 union {
103 struct {
104 // We allot the enums one more bit than they require because MSVC seems to sign-extend
105 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
106 OutputType fPrimaryOutputType : 4;
107 OutputType fSecondaryOutputType : 4;
108 GrBlendEquation fBlendEquation : 6;
109 GrBlendCoeff fSrcCoeff : 6;
110 GrBlendCoeff fDstCoeff : 6;
111 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
112 };
113 uint32_t fData;
114 };
115
116 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
117 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
118 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
119 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
120 };
121
122 GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
123
124 GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
125
126 /**
127 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
128 */
129 #define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
130 {{{PRIMARY_OUT, \
131 SECONDARY_OUT, \
132 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
133 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
134 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
135
136 /**
137 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
138 * Porter Duff formula.
139 */
140 #define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
141 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
142 BlendFormula::kNone_OutputType, \
143 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
144
145 /**
146 * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
147 * LCD dst-out.
148 */
149 #define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
150 INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
151 BlendFormula::kNone_OutputType, \
152 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
153
154 /**
155 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
156 * the primary output type to none.
157 */
158 #define DST_CLEAR_FORMULA \
159 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
160 BlendFormula::kNone_OutputType, \
161 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
162
163 /**
164 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
165 * so we can set the primary output type to none.
166 */
167 #define NO_DST_WRITE_FORMULA \
168 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
169 BlendFormula::kNone_OutputType, \
170 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
171
172 /**
173 * When there is coverage, the equation with f=coverage is:
174 *
175 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
176 *
177 * This can be rewritten as:
178 *
179 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
180 *
181 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
182 * HW dst coeff with IS2C.
183 *
184 * Xfer modes: dst-atop (Sa!=1)
185 */
186 #define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
187 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
188 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
189 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
190
191 /**
192 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
193 *
194 * D' = f * D * dstCoeff + (1-f) * D
195 *
196 * This can be rewritten as:
197 *
198 * D' = D - D * [f * (1 - dstCoeff)]
199 *
200 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
201 * subtract HW blend equation with coeffs of (DC, One).
202 *
203 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
204 */
205 #define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
206 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
207 BlendFormula::kNone_OutputType, \
208 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
209
210 /**
211 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
212 *
213 * D' = f * S * srcCoeff + (1-f) * D
214 *
215 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
216 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
217 *
218 * Xfer modes (Sa!=1): src, src-in, src-out
219 */
220 #define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
221 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
222 BlendFormula::kCoverage_OutputType, \
223 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
224
225 /**
226 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
227 * with and without an opaque input color. Optimization properties are deduced at compile time so we
228 * can make runtime decisions quickly. RGB coverage is not supported.
229 */
230 static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
231
232 /*>> No coverage, input color unknown <<*/ {{
233
234 /* clear */ DST_CLEAR_FORMULA,
235 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
236 /* dst */ NO_DST_WRITE_FORMULA,
237 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
238 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
239 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
240 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
241 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
242 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
243 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
244 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
245 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
246 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
247 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
248 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
249
250 }, /*>> Has coverage, input color unknown <<*/ {
251
252 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
253 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
254 /* dst */ NO_DST_WRITE_FORMULA,
255 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
256 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
257 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
258 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
259 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
260 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
261 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
262 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
263 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
264 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
265 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
266 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
267
268 }}, /*>> No coverage, input color opaque <<*/ {{
269
270 /* clear */ DST_CLEAR_FORMULA,
271 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
272 /* dst */ NO_DST_WRITE_FORMULA,
273 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
274 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
275 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
276 /* dst-in */ NO_DST_WRITE_FORMULA,
277 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
278 /* dst-out */ DST_CLEAR_FORMULA,
279 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
280 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
281 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
282 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
283 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
284 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
285
286 }, /*>> Has coverage, input color opaque <<*/ {
287
288 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
289 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
290 /* dst */ NO_DST_WRITE_FORMULA,
291 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
292 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
293 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
294 /* dst-in */ NO_DST_WRITE_FORMULA,
295 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
296 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
297 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
298 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
299 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
300 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
301 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
302 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
303 }}};
304
305 static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
306 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
307 /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
308 /* dst */ NO_DST_WRITE_FORMULA,
309 /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
310 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
311 /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
312 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
313 /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
314 /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
315 /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
316 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
317 /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
318 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
319 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
320 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
321 };
322
get_blend_formula(const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI,bool hasMixedSamples,SkXfermode::Mode xfermode)323 static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
324 const GrProcOptInfo& coveragePOI,
325 bool hasMixedSamples,
326 SkXfermode::Mode xfermode) {
327 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
328 SkASSERT(!coveragePOI.isFourChannelOutput());
329
330 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
331 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
332 }
333
get_lcd_blend_formula(const GrProcOptInfo & coveragePOI,SkXfermode::Mode xfermode)334 static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
335 SkXfermode::Mode xfermode) {
336 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
337 SkASSERT(coveragePOI.isFourChannelOutput());
338
339 return gLCDBlendTable[xfermode];
340 }
341
342 ///////////////////////////////////////////////////////////////////////////////
343
344 class PorterDuffXferProcessor : public GrXferProcessor {
345 public:
PorterDuffXferProcessor(BlendFormula blendFormula)346 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
347 this->initClassID<PorterDuffXferProcessor>();
348 }
349
name() const350 const char* name() const override { return "Porter Duff"; }
351
352 GrGLSLXferProcessor* createGLSLInstance() const override;
353
getBlendFormula() const354 BlendFormula getBlendFormula() const { return fBlendFormula; }
355
356 private:
357 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
358 bool doesStencilWrite,
359 GrColor* overrideColor,
360 const GrCaps& caps) const override;
361
362 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
363
onHasSecondaryOutput() const364 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
365
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const366 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
367 blendInfo->fEquation = fBlendFormula.fBlendEquation;
368 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
369 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
370 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
371 }
372
onIsEqual(const GrXferProcessor & xpBase) const373 bool onIsEqual(const GrXferProcessor& xpBase) const override {
374 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
375 return fBlendFormula == xp.fBlendFormula;
376 }
377
378 const BlendFormula fBlendFormula;
379
380 typedef GrXferProcessor INHERITED;
381 };
382
383 ///////////////////////////////////////////////////////////////////////////////
384
append_color_output(const PorterDuffXferProcessor & xp,GrGLSLXPFragmentBuilder * fragBuilder,BlendFormula::OutputType outputType,const char * output,const char * inColor,const char * inCoverage)385 static void append_color_output(const PorterDuffXferProcessor& xp,
386 GrGLSLXPFragmentBuilder* fragBuilder,
387 BlendFormula::OutputType outputType, const char* output,
388 const char* inColor, const char* inCoverage) {
389 switch (outputType) {
390 case BlendFormula::kNone_OutputType:
391 fragBuilder->codeAppendf("%s = vec4(0.0);", output);
392 break;
393 case BlendFormula::kCoverage_OutputType:
394 // We can have a coverage formula while not reading coverage if there are mixed samples.
395 if (inCoverage) {
396 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
397 } else {
398 fragBuilder->codeAppendf("%s = vec4(1.0);", output);
399 }
400 break;
401 case BlendFormula::kModulate_OutputType:
402 if (inCoverage) {
403 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
404 } else {
405 fragBuilder->codeAppendf("%s = %s;", output, inColor);
406 }
407 break;
408 case BlendFormula::kSAModulate_OutputType:
409 if (inCoverage) {
410 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
411 } else {
412 fragBuilder->codeAppendf("%s = %s;", output, inColor);
413 }
414 break;
415 case BlendFormula::kISAModulate_OutputType:
416 if (inCoverage) {
417 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
418 } else {
419 fragBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
420 }
421 break;
422 case BlendFormula::kISCModulate_OutputType:
423 if (inCoverage) {
424 fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
425 } else {
426 fragBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
427 }
428 break;
429 default:
430 SkFAIL("Unsupported output type.");
431 break;
432 }
433 }
434
435 class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
436 public:
GenKey(const GrProcessor & processor,GrProcessorKeyBuilder * b)437 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
438 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
439 b->add32(xp.getBlendFormula().fPrimaryOutputType |
440 (xp.getBlendFormula().fSecondaryOutputType << 3));
441 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
442 };
443
444 private:
emitOutputsForBlendState(const EmitArgs & args)445 void emitOutputsForBlendState(const EmitArgs& args) override {
446 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
447 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
448
449 BlendFormula blendFormula = xp.getBlendFormula();
450 if (blendFormula.hasSecondaryOutput()) {
451 append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType,
452 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
453 }
454 append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType,
455 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
456 }
457
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)458 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
459
460 typedef GrGLSLXferProcessor INHERITED;
461 };
462
463 ///////////////////////////////////////////////////////////////////////////////
464
onGetGLSLProcessorKey(const GrGLSLCaps &,GrProcessorKeyBuilder * b) const465 void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
466 GrProcessorKeyBuilder* b) const {
467 GLPorterDuffXferProcessor::GenKey(*this, b);
468 }
469
createGLSLInstance() const470 GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
471 return new GLPorterDuffXferProcessor;
472 }
473
474 GrXferProcessor::OptFlags
onGetOptimizations(const GrPipelineOptimizations & optimizations,bool doesStencilWrite,GrColor * overrideColor,const GrCaps & caps) const475 PorterDuffXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
476 bool doesStencilWrite,
477 GrColor* overrideColor,
478 const GrCaps& caps) const {
479 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
480 if (!fBlendFormula.modifiesDst()) {
481 if (!doesStencilWrite) {
482 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
483 }
484 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
485 GrXferProcessor::kIgnoreCoverage_OptFlag |
486 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
487 } else {
488 if (!fBlendFormula.usesInputColor()) {
489 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
490 }
491 if (optimizations.fCoveragePOI.isSolidWhite()) {
492 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
493 }
494 if (optimizations.fColorPOI.allStagesMultiplyInput() &&
495 fBlendFormula.canTweakAlphaForCoverage() &&
496 !optimizations.fCoveragePOI.isFourChannelOutput()) {
497 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
498 }
499 }
500 return optFlags;
501 }
502
503 ///////////////////////////////////////////////////////////////////////////////
504
505 class ShaderPDXferProcessor : public GrXferProcessor {
506 public:
ShaderPDXferProcessor(const DstTexture * dstTexture,bool hasMixedSamples,SkXfermode::Mode xfermode)507 ShaderPDXferProcessor(const DstTexture* dstTexture,
508 bool hasMixedSamples,
509 SkXfermode::Mode xfermode)
510 : INHERITED(dstTexture, true, hasMixedSamples)
511 , fXfermode(xfermode) {
512 this->initClassID<ShaderPDXferProcessor>();
513 }
514
name() const515 const char* name() const override { return "Porter Duff Shader"; }
516
517 GrGLSLXferProcessor* createGLSLInstance() const override;
518
getXfermode() const519 SkXfermode::Mode getXfermode() const { return fXfermode; }
520
521 private:
onGetOptimizations(const GrPipelineOptimizations &,bool,GrColor *,const GrCaps &) const522 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*,
523 const GrCaps&) const override {
524 return kNone_OptFlags;
525 }
526
527 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
528
onIsEqual(const GrXferProcessor & xpBase) const529 bool onIsEqual(const GrXferProcessor& xpBase) const override {
530 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
531 return fXfermode == xp.fXfermode;
532 }
533
534 const SkXfermode::Mode fXfermode;
535
536 typedef GrXferProcessor INHERITED;
537 };
538
539 ///////////////////////////////////////////////////////////////////////////////
540
541 class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
542 public:
GenKey(const GrProcessor & processor,GrProcessorKeyBuilder * b)543 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
544 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
545 b->add32(xp.getXfermode());
546 }
547
548 private:
emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const char * srcColor,const char * srcCoverage,const char * dstColor,const char * outColor,const char * outColorSecondary,const GrXferProcessor & proc)549 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
550 GrGLSLUniformHandler* uniformHandler,
551 const char* srcColor,
552 const char* srcCoverage,
553 const char* dstColor,
554 const char* outColor,
555 const char* outColorSecondary,
556 const GrXferProcessor& proc) override {
557 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
558
559 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
560
561 // Apply coverage.
562 INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
563 outColorSecondary, xp);
564 }
565
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)566 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
567
568 typedef GrGLSLXferProcessor INHERITED;
569 };
570
571 ///////////////////////////////////////////////////////////////////////////////
572
onGetGLSLProcessorKey(const GrGLSLCaps &,GrProcessorKeyBuilder * b) const573 void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
574 GrProcessorKeyBuilder* b) const {
575 GLShaderPDXferProcessor::GenKey(*this, b);
576 }
577
createGLSLInstance() const578 GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
579 return new GLShaderPDXferProcessor;
580 }
581
582 ///////////////////////////////////////////////////////////////////////////////
583
584 class PDLCDXferProcessor : public GrXferProcessor {
585 public:
586 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
587
588 ~PDLCDXferProcessor() override;
589
name() const590 const char* name() const override { return "Porter Duff LCD"; }
591
592 GrGLSLXferProcessor* createGLSLInstance() const override;
593
594 private:
595 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
596
597 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
598 bool doesStencilWrite,
599 GrColor* overrideColor,
600 const GrCaps& caps) const override;
601
602 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
603
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const604 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
605 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
606 blendInfo->fDstBlend = kISC_GrBlendCoeff;
607 blendInfo->fBlendConstant = fBlendConstant;
608 }
609
onIsEqual(const GrXferProcessor & xpBase) const610 bool onIsEqual(const GrXferProcessor& xpBase) const override {
611 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
612 if (fBlendConstant != xp.fBlendConstant ||
613 fAlpha != xp.fAlpha) {
614 return false;
615 }
616 return true;
617 }
618
619 GrColor fBlendConstant;
620 uint8_t fAlpha;
621
622 typedef GrXferProcessor INHERITED;
623 };
624
625 ///////////////////////////////////////////////////////////////////////////////
626
627 class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
628 public:
GLPDLCDXferProcessor(const GrProcessor &)629 GLPDLCDXferProcessor(const GrProcessor&) {}
630
~GLPDLCDXferProcessor()631 virtual ~GLPDLCDXferProcessor() {}
632
GenKey(const GrProcessor & processor,const GrGLSLCaps & caps,GrProcessorKeyBuilder * b)633 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
634 GrProcessorKeyBuilder* b) {}
635
636 private:
emitOutputsForBlendState(const EmitArgs & args)637 void emitOutputsForBlendState(const EmitArgs& args) override {
638 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
639 SkASSERT(args.fInputCoverage);
640 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
641 args.fInputCoverage);
642 }
643
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)644 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {};
645
646 typedef GrGLSLXferProcessor INHERITED;
647 };
648
649 ///////////////////////////////////////////////////////////////////////////////
650
PDLCDXferProcessor(GrColor blendConstant,uint8_t alpha)651 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
652 : fBlendConstant(blendConstant)
653 , fAlpha(alpha) {
654 this->initClassID<PDLCDXferProcessor>();
655 }
656
Create(SkXfermode::Mode xfermode,const GrProcOptInfo & colorPOI)657 GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
658 const GrProcOptInfo& colorPOI) {
659 if (SkXfermode::kSrcOver_Mode != xfermode) {
660 return nullptr;
661 }
662
663 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
664 return nullptr;
665 }
666
667 GrColor blendConstant = GrUnpremulColor(colorPOI.color());
668 uint8_t alpha = GrColorUnpackA(blendConstant);
669 blendConstant |= (0xff << GrColor_SHIFT_A);
670
671 return new PDLCDXferProcessor(blendConstant, alpha);
672 }
673
~PDLCDXferProcessor()674 PDLCDXferProcessor::~PDLCDXferProcessor() {
675 }
676
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const677 void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
678 GrProcessorKeyBuilder* b) const {
679 GLPDLCDXferProcessor::GenKey(*this, caps, b);
680 }
681
createGLSLInstance() const682 GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
683 return new GLPDLCDXferProcessor(*this);
684 }
685
686 GrXferProcessor::OptFlags
onGetOptimizations(const GrPipelineOptimizations & optimizations,bool doesStencilWrite,GrColor * overrideColor,const GrCaps & caps) const687 PDLCDXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
688 bool doesStencilWrite,
689 GrColor* overrideColor,
690 const GrCaps& caps) const {
691 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
692 // value of the blend the constant. We should already have valid blend coeff's if we are at
693 // a point where we have RGB coverage. We don't need any color stages since the known color
694 // output is already baked into the blendConstant.
695 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
696 return GrXferProcessor::kOverrideColor_OptFlag;
697 }
698
699 ///////////////////////////////////////////////////////////////////////////////
700
GrPorterDuffXPFactory(SkXfermode::Mode xfermode)701 GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
702 : fXfermode(xfermode) {
703 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
704 this->initClassID<GrPorterDuffXPFactory>();
705 }
706
Create(SkXfermode::Mode xfermode)707 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
708 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
709 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
710 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
711 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
712 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
713 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
714 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
715 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
716 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
717 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
718 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
719 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
720 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
721 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
722 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
723
724 static GrPorterDuffXPFactory* gFactories[] = {
725 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
726 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
727 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
728 };
729 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
730
731 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
732 return nullptr;
733 }
734 return SkRef(gFactories[xfermode]);
735 }
736
737 GrXferProcessor*
onCreateXferProcessor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples,const DstTexture * dstTexture) const738 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
739 const GrPipelineOptimizations& optimizations,
740 bool hasMixedSamples,
741 const DstTexture* dstTexture) const {
742 if (optimizations.fOverrides.fUsePLSDstRead) {
743 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
744 }
745 BlendFormula blendFormula;
746 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
747 if (SkXfermode::kSrcOver_Mode == fXfermode &&
748 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
749 !caps.shaderCaps()->dualSourceBlendingSupport() &&
750 !caps.shaderCaps()->dstReadInShaderSupport()) {
751 // If we don't have dual source blending or in shader dst reads, we fall back to this
752 // trick for rendering SrcOver LCD text instead of doing a dst copy.
753 SkASSERT(!dstTexture || !dstTexture->texture());
754 return PDLCDXferProcessor::Create(fXfermode, optimizations.fColorPOI);
755 }
756 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode);
757 } else {
758 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
759 hasMixedSamples, fXfermode);
760 }
761
762 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
763 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
764 }
765
766 SkASSERT(!dstTexture || !dstTexture->texture());
767 return new PorterDuffXferProcessor(blendFormula);
768 }
769
getInvariantBlendedColor(const GrProcOptInfo & colorPOI,InvariantBlendedColor * blendedColor) const770 void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
771 InvariantBlendedColor* blendedColor) const {
772 // Find the blended color info based on the formula that does not have coverage.
773 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
774 if (colorFormula.usesDstColor()) {
775 blendedColor->fWillBlendWithDst = true;
776 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
777 return;
778 }
779
780 blendedColor->fWillBlendWithDst = false;
781
782 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
783
784 switch (colorFormula.fSrcCoeff) {
785 case kZero_GrBlendCoeff:
786 blendedColor->fKnownColor = 0;
787 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
788 return;
789
790 case kOne_GrBlendCoeff:
791 blendedColor->fKnownColor = colorPOI.color();
792 blendedColor->fKnownColorFlags = colorPOI.validFlags();
793 return;
794
795 default:
796 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
797 return;
798 }
799 }
800
onWillReadDstColor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples) const801 bool GrPorterDuffXPFactory::onWillReadDstColor(const GrCaps& caps,
802 const GrPipelineOptimizations& optimizations,
803 bool hasMixedSamples) const {
804 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
805 return false;
806 }
807
808 // When we have four channel coverage we always need to read the dst in order to correctly
809 // blend. The one exception is when we are using srcover mode and we know the input color into
810 // the XP.
811 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
812 if (SkXfermode::kSrcOver_Mode == fXfermode &&
813 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
814 !caps.shaderCaps()->dstReadInShaderSupport()) {
815 return false;
816 }
817 return get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode).hasSecondaryOutput();
818 }
819 // We fallback on the shader XP when the blend formula would use dual source blending but we
820 // don't have support for it.
821 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, hasMixedSamples,
822 fXfermode).hasSecondaryOutput();
823 }
824
825 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
826
TestCreate(GrProcessorTestData * d)827 const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
828 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
829 return GrPorterDuffXPFactory::Create(mode);
830 }
831
TestGetXPOutputTypes(const GrXferProcessor * xp,int * outPrimary,int * outSecondary)832 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
833 int* outPrimary,
834 int* outSecondary) {
835 if (!!strcmp(xp->name(), "Porter Duff")) {
836 *outPrimary = *outSecondary = -1;
837 return;
838 }
839 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
840 *outPrimary = blendFormula.fPrimaryOutputType;
841 *outSecondary = blendFormula.fSecondaryOutputType;
842 }
843
844
845 ////////////////////////////////////////////////////////////////////////////////////////////////
846 // SrcOver Global functions
847 ////////////////////////////////////////////////////////////////////////////////////////////////
SimpleSrcOverXP()848 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
849 static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
850 kISA_GrBlendCoeff);
851 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
852 return gSrcOverXP;
853 }
854
CreateSrcOverXferProcessor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples,const GrXferProcessor::DstTexture * dstTexture)855 GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
856 const GrCaps& caps,
857 const GrPipelineOptimizations& optimizations,
858 bool hasMixedSamples,
859 const GrXferProcessor::DstTexture* dstTexture) {
860 if (optimizations.fOverrides.fUsePLSDstRead) {
861 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
862 }
863 if (!optimizations.fCoveragePOI.isFourChannelOutput() &&
864 !(optimizations.fCoveragePOI.isSolidWhite() &&
865 !hasMixedSamples &&
866 optimizations.fColorPOI.isOpaque())) {
867 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
868 // We don't simply return the address of that XP here because our caller would have to unref
869 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
870 // safe.
871 return nullptr;
872 }
873
874 BlendFormula blendFormula;
875 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
876 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
877 !caps.shaderCaps()->dualSourceBlendingSupport() &&
878 !caps.shaderCaps()->dstReadInShaderSupport()) {
879 // If we don't have dual source blending or in shader dst reads, we fall
880 // back to this trick for rendering SrcOver LCD text instead of doing a
881 // dst copy.
882 SkASSERT(!dstTexture || !dstTexture->texture());
883 return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, optimizations.fColorPOI);
884 }
885 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, SkXfermode::kSrcOver_Mode);
886 } else {
887 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
888 hasMixedSamples, SkXfermode::kSrcOver_Mode);
889 }
890
891 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
892 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
893 }
894
895 SkASSERT(!dstTexture || !dstTexture->texture());
896 return new PorterDuffXferProcessor(blendFormula);
897 }
898
SrcOverWillNeedDstTexture(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples)899 bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
900 const GrPipelineOptimizations& optimizations,
901 bool hasMixedSamples) {
902 if (caps.shaderCaps()->dstReadInShaderSupport() ||
903 caps.shaderCaps()->dualSourceBlendingSupport()) {
904 return false;
905 }
906
907 // When we have four channel coverage we always need to read the dst in order to correctly
908 // blend. The one exception is when we are using srcover mode and we know the input color
909 // into the XP.
910 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
911 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
912 !caps.shaderCaps()->dstReadInShaderSupport()) {
913 return false;
914 }
915 return get_lcd_blend_formula(optimizations.fCoveragePOI,
916 SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
917 }
918 // We fallback on the shader XP when the blend formula would use dual source blending but we
919 // don't have support for it.
920 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
921 hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
922 }
923
924