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 "GrDrawTargetCaps.h"
12 #include "GrProcessor.h"
13 #include "GrProcOptInfo.h"
14 #include "GrTypes.h"
15 #include "GrXferProcessor.h"
16 #include "gl/GrGLXferProcessor.h"
17 #include "gl/builders/GrGLFragmentShaderBuilder.h"
18 #include "gl/builders/GrGLProgramBuilder.h"
19
can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff)20 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
21 /*
22 The fractional coverage is f.
23 The src and dst coeffs are Cs and Cd.
24 The dst and src colors are S and D.
25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
26 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
29 */
30 return kOne_GrBlendCoeff == dstCoeff ||
31 kISA_GrBlendCoeff == dstCoeff ||
32 kISC_GrBlendCoeff == dstCoeff;
33 }
34
35 class PorterDuffXferProcessor : public GrXferProcessor {
36 public:
Create(GrBlendCoeff srcBlend,GrBlendCoeff dstBlend,GrColor constant,const GrDeviceCoordTexture * dstCopy,bool willReadDstColor)37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
38 GrColor constant, const GrDeviceCoordTexture* dstCopy,
39 bool willReadDstColor) {
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant, dstCopy,
41 willReadDstColor));
42 }
43
44 ~PorterDuffXferProcessor() override;
45
name() const46 const char* name() const override { return "Porter Duff"; }
47
48 GrGLXferProcessor* createGLInstance() const override;
49
50 bool hasSecondaryOutput() const override;
51
52 ///////////////////////////////////////////////////////////////////////////
53 /// @name Stage Output Types
54 ////
55
56 enum PrimaryOutputType {
57 kNone_PrimaryOutputType,
58 kColor_PrimaryOutputType,
59 kCoverage_PrimaryOutputType,
60 // Modulate color and coverage, write result as the color output.
61 kModulate_PrimaryOutputType,
62 // Custom Porter-Duff output, used for when we explictly are reading the dst and blending
63 // in the shader. Secondary Output must be none if you use this. The custom blend uses the
64 // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D
65 kCustom_PrimaryOutputType
66 };
67
68 enum SecondaryOutputType {
69 // There is no secondary output
70 kNone_SecondaryOutputType,
71 // Writes coverage as the secondary output. Only set if dual source blending is supported
72 // and primary output is kModulate.
73 kCoverage_SecondaryOutputType,
74 // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending
75 // is supported and primary output is kModulate.
76 kCoverageISA_SecondaryOutputType,
77 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source
78 // blending is supported and primary output is kModulate.
79 kCoverageISC_SecondaryOutputType,
80
81 kSecondaryOutputTypeCnt,
82 };
83
primaryOutputType() const84 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
secondaryOutputType() const85 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
86
getSrcBlend() const87 GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
getDstBlend() const88 GrBlendCoeff getDstBlend() const { return fDstBlend; }
89
90 private:
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
92 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
93
94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
95 const GrProcOptInfo& coveragePOI,
96 bool doesStencilWrite,
97 GrColor* overrideColor,
98 const GrDrawTargetCaps& caps) override;
99
100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
101
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
103 if (!this->willReadDstColor()) {
104 blendInfo->fSrcBlend = fSrcBlend;
105 blendInfo->fDstBlend = fDstBlend;
106 } else {
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
108 blendInfo->fDstBlend = kZero_GrBlendCoeff;
109 }
110 blendInfo->fBlendConstant = fBlendConstant;
111 }
112
onIsEqual(const GrXferProcessor & xpBase) const113 bool onIsEqual(const GrXferProcessor& xpBase) const override {
114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
115 if (fSrcBlend != xp.fSrcBlend ||
116 fDstBlend != xp.fDstBlend ||
117 fBlendConstant != xp.fBlendConstant ||
118 fPrimaryOutputType != xp.fPrimaryOutputType ||
119 fSecondaryOutputType != xp.fSecondaryOutputType) {
120 return false;
121 }
122 return true;
123 }
124
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
126 const GrProcOptInfo& coveragePOI,
127 bool doesStencilWrite);
128
129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps,
130 bool hasSolidCoverage);
131
132 GrBlendCoeff fSrcBlend;
133 GrBlendCoeff fDstBlend;
134 GrColor fBlendConstant;
135 PrimaryOutputType fPrimaryOutputType;
136 SecondaryOutputType fSecondaryOutputType;
137
138 typedef GrXferProcessor INHERITED;
139 };
140
141 ///////////////////////////////////////////////////////////////////////////////
142
append_porterduff_term(GrGLXPFragmentBuilder * fsBuilder,GrBlendCoeff coeff,const char * colorName,const char * srcColorName,const char * dstColorName,bool hasPrevious)143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff,
144 const char* colorName, const char* srcColorName,
145 const char* dstColorName, bool hasPrevious) {
146 if (kZero_GrBlendCoeff == coeff) {
147 return hasPrevious;
148 } else {
149 if (hasPrevious) {
150 fsBuilder->codeAppend(" + ");
151 }
152 fsBuilder->codeAppendf("%s", colorName);
153 switch (coeff) {
154 case kOne_GrBlendCoeff:
155 break;
156 case kSC_GrBlendCoeff:
157 fsBuilder->codeAppendf(" * %s", srcColorName);
158 break;
159 case kISC_GrBlendCoeff:
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
161 break;
162 case kDC_GrBlendCoeff:
163 fsBuilder->codeAppendf(" * %s", dstColorName);
164 break;
165 case kIDC_GrBlendCoeff:
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
167 break;
168 case kSA_GrBlendCoeff:
169 fsBuilder->codeAppendf(" * %s.a", srcColorName);
170 break;
171 case kISA_GrBlendCoeff:
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
173 break;
174 case kDA_GrBlendCoeff:
175 fsBuilder->codeAppendf(" * %s.a", dstColorName);
176 break;
177 case kIDA_GrBlendCoeff:
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
179 break;
180 default:
181 SkFAIL("Unsupported Blend Coeff");
182 }
183 return true;
184 }
185 }
186
187 class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188 public:
GLPorterDuffXferProcessor(const GrProcessor &)189 GLPorterDuffXferProcessor(const GrProcessor&) {}
190
~GLPorterDuffXferProcessor()191 virtual ~GLPorterDuffXferProcessor() {}
192
GenKey(const GrProcessor & processor,const GrGLSLCaps & caps,GrProcessorKeyBuilder * b)193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
194 GrProcessorKeyBuilder* b) {
195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
196 b->add32(xp.primaryOutputType());
197 b->add32(xp.secondaryOutputType());
198 if (xp.willReadDstColor()) {
199 b->add32(xp.getSrcBlend());
200 b->add32(xp.getDstBlend());
201 }
202 };
203
204 private:
onEmitCode(const EmitArgs & args)205 void onEmitCode(const EmitArgs& args) override {
206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) {
209 SkASSERT(!xp.willReadDstColor());
210 switch(xp.secondaryOutputType()) {
211 case PorterDuffXferProcessor::kNone_SecondaryOutputType:
212 break;
213 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
214 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary,
215 args.fInputCoverage);
216 break;
217 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
218 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
219 args.fOutputSecondary, args.fInputColor,
220 args.fInputCoverage);
221 break;
222 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
223 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
224 args.fOutputSecondary, args.fInputColor,
225 args.fInputCoverage);
226 break;
227 default:
228 SkFAIL("Unexpected Secondary Output");
229 }
230
231 switch (xp.primaryOutputType()) {
232 case PorterDuffXferProcessor::kNone_PrimaryOutputType:
233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
234 break;
235 case PorterDuffXferProcessor::kColor_PrimaryOutputType:
236 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
237 break;
238 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
239 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
240 break;
241 case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
242 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
243 args.fInputCoverage);
244 break;
245 default:
246 SkFAIL("Unexpected Primary Output");
247 }
248 } else {
249 SkASSERT(xp.willReadDstColor());
250
251 const char* dstColor = fsBuilder->dstColor();
252
253 fsBuilder->codeAppend("vec4 colorBlend =");
254 // append src blend
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(),
256 args.fInputColor, args.fInputColor,
257 dstColor, false);
258 // append dst blend
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(),
260 dstColor, args.fInputColor,
261 dstColor, didAppend));
262 fsBuilder->codeAppend(";");
263
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
265 args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage,
266 dstColor);
267 }
268 }
269
onSetData(const GrGLProgramDataManager &,const GrXferProcessor &)270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
271
272 typedef GrGLXferProcessor INHERITED;
273 };
274
275 ///////////////////////////////////////////////////////////////////////////////
276
PorterDuffXferProcessor(GrBlendCoeff srcBlend,GrBlendCoeff dstBlend,GrColor constant,const GrDeviceCoordTexture * dstCopy,bool willReadDstColor)277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend,
278 GrBlendCoeff dstBlend,
279 GrColor constant,
280 const GrDeviceCoordTexture* dstCopy,
281 bool willReadDstColor)
282 : INHERITED(dstCopy, willReadDstColor)
283 , fSrcBlend(srcBlend)
284 , fDstBlend(dstBlend)
285 , fBlendConstant(constant)
286 , fPrimaryOutputType(kModulate_PrimaryOutputType)
287 , fSecondaryOutputType(kNone_SecondaryOutputType) {
288 this->initClassID<PorterDuffXferProcessor>();
289 }
290
~PorterDuffXferProcessor()291 PorterDuffXferProcessor::~PorterDuffXferProcessor() {
292 }
293
onGetGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
295 GrProcessorKeyBuilder* b) const {
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b);
297 }
298
createGLInstance() const299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
301 }
302
303 GrXferProcessor::OptFlags
onGetOptimizations(const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI,bool doesStencilWrite,GrColor * overrideColor,const GrDrawTargetCaps & caps)304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
305 const GrProcOptInfo& coveragePOI,
306 bool doesStencilWrite,
307 GrColor* overrideColor,
308 const GrDrawTargetCaps& caps) {
309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI,
310 coveragePOI,
311 doesStencilWrite);
312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
313 return optFlags;
314 }
315
calcOutputTypes(GrXferProcessor::OptFlags optFlags,const GrDrawTargetCaps & caps,bool hasSolidCoverage)316 void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
317 const GrDrawTargetCaps& caps,
318 bool hasSolidCoverage) {
319 if (this->willReadDstColor()) {
320 fPrimaryOutputType = kCustom_PrimaryOutputType;
321 return;
322 }
323
324 if (optFlags & kIgnoreColor_OptFlag) {
325 if (optFlags & kIgnoreCoverage_OptFlag) {
326 fPrimaryOutputType = kNone_PrimaryOutputType;
327 return;
328 } else {
329 fPrimaryOutputType = kCoverage_PrimaryOutputType;
330 return;
331 }
332 } else if (optFlags & kIgnoreCoverage_OptFlag) {
333 fPrimaryOutputType = kColor_PrimaryOutputType;
334 return;
335 }
336
337 // If we do have coverage determine whether it matters. Dual source blending is expensive so
338 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
339 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
340 // solid coverage.
341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
342 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
343 if (kZero_GrBlendCoeff == fDstBlend) {
344 // write the coverage value to second color
345 fSecondaryOutputType = kCoverage_SecondaryOutputType;
346 fDstBlend = kIS2C_GrBlendCoeff;
347 } else if (kSA_GrBlendCoeff == fDstBlend) {
348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
350 fDstBlend = kIS2C_GrBlendCoeff;
351 } else if (kSC_GrBlendCoeff == fDstBlend) {
352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
354 fDstBlend = kIS2C_GrBlendCoeff;
355 }
356 }
357 }
358 }
359
360 GrXferProcessor::OptFlags
internalGetOptimizations(const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI,bool doesStencilWrite)361 PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
362 const GrProcOptInfo& coveragePOI,
363 bool doesStencilWrite) {
364 if (this->willReadDstColor()) {
365 return GrXferProcessor::kNone_Opt;
366 }
367
368 bool srcAIsOne = colorPOI.isOpaque();
369 bool hasCoverage = !coveragePOI.isSolidWhite();
370
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
375
376 // When coeffs are (0,1) there is no reason to draw at all, unless
377 // stenciling is enabled. Having color writes disabled is effectively
378 // (0,1).
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
380 if (doesStencilWrite) {
381 return GrXferProcessor::kIgnoreColor_OptFlag |
382 GrXferProcessor::kSetCoverageDrawing_OptFlag;
383 } else {
384 fDstBlend = kOne_GrBlendCoeff;
385 return GrXferProcessor::kSkipDraw_OptFlag;
386 }
387 }
388
389 // if we don't have coverage we can check whether the dst
390 // has to read at all. If not, we'll disable blending.
391 if (!hasCoverage) {
392 if (dstCoeffIsZero) {
393 if (kOne_GrBlendCoeff == fSrcBlend) {
394 // if there is no coverage and coeffs are (1,0) then we
395 // won't need to read the dst at all, it gets replaced by src
396 fDstBlend = kZero_GrBlendCoeff;
397 return GrXferProcessor::kNone_Opt |
398 GrXferProcessor::kIgnoreCoverage_OptFlag;
399 } else if (kZero_GrBlendCoeff == fSrcBlend) {
400 // if the op is "clear" then we don't need to emit a color
401 // or blend, just write transparent black into the dst.
402 fSrcBlend = kOne_GrBlendCoeff;
403 fDstBlend = kZero_GrBlendCoeff;
404 return GrXferProcessor::kIgnoreColor_OptFlag |
405 GrXferProcessor::kIgnoreCoverage_OptFlag;
406 }
407 }
408 return GrXferProcessor::kIgnoreCoverage_OptFlag;
409 }
410
411 // check whether coverage can be safely rolled into alpha
412 // of if we can skip color computation and just emit coverage
413 if (can_tweak_alpha_for_coverage(fDstBlend)) {
414 if (colorPOI.allStagesMultiplyInput()) {
415 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
416 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
417 } else {
418 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
419
420 }
421 }
422 if (dstCoeffIsZero) {
423 if (kZero_GrBlendCoeff == fSrcBlend) {
424 // the source color is not included in the blend
425 // the dst coeff is effectively zero so blend works out to:
426 // (c)(0)D + (1-c)D = (1-c)D.
427 fDstBlend = kISA_GrBlendCoeff;
428 return GrXferProcessor::kIgnoreColor_OptFlag |
429 GrXferProcessor::kSetCoverageDrawing_OptFlag;
430 } else if (srcAIsOne) {
431 // the dst coeff is effectively zero so blend works out to:
432 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
433 // If Sa is 1 then we can replace Sa with c
434 // and set dst coeff to 1-Sa.
435 fDstBlend = kISA_GrBlendCoeff;
436 if (colorPOI.allStagesMultiplyInput()) {
437 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
439 } else {
440 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
441
442 }
443 }
444 } else if (dstCoeffIsOne) {
445 // the dst coeff is effectively one so blend works out to:
446 // cS + (c)(1)D + (1-c)D = cS + D.
447 fDstBlend = kOne_GrBlendCoeff;
448 if (colorPOI.allStagesMultiplyInput()) {
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
451 } else {
452 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
453
454 }
455 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
456 }
457
458 return GrXferProcessor::kNone_Opt;
459 }
460
hasSecondaryOutput() const461 bool PorterDuffXferProcessor::hasSecondaryOutput() const {
462 return kNone_SecondaryOutputType != fSecondaryOutputType;
463 }
464
465 ///////////////////////////////////////////////////////////////////////////////
466
467 class PDLCDXferProcessor : public GrXferProcessor {
468 public:
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
470 const GrProcOptInfo& colorPOI);
471
472 ~PDLCDXferProcessor() override;
473
name() const474 const char* name() const override { return "Porter Duff LCD"; }
475
476 GrGLXferProcessor* createGLInstance() const override;
477
hasSecondaryOutput() const478 bool hasSecondaryOutput() const override { return false; }
479
480 private:
481 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
482
483 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
484 const GrProcOptInfo& coveragePOI,
485 bool doesStencilWrite,
486 GrColor* overrideColor,
487 const GrDrawTargetCaps& caps) override;
488
489 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
490
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const491 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
492 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
493 blendInfo->fDstBlend = kISC_GrBlendCoeff;
494 blendInfo->fBlendConstant = fBlendConstant;
495 }
496
onIsEqual(const GrXferProcessor & xpBase) const497 bool onIsEqual(const GrXferProcessor& xpBase) const override {
498 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
499 if (fBlendConstant != xp.fBlendConstant ||
500 fAlpha != xp.fAlpha) {
501 return false;
502 }
503 return true;
504 }
505
506 GrColor fBlendConstant;
507 uint8_t fAlpha;
508
509 typedef GrXferProcessor INHERITED;
510 };
511
512 ///////////////////////////////////////////////////////////////////////////////
513
514 class GLPDLCDXferProcessor : public GrGLXferProcessor {
515 public:
GLPDLCDXferProcessor(const GrProcessor &)516 GLPDLCDXferProcessor(const GrProcessor&) {}
517
~GLPDLCDXferProcessor()518 virtual ~GLPDLCDXferProcessor() {}
519
GenKey(const GrProcessor & processor,const GrGLSLCaps & caps,GrProcessorKeyBuilder * b)520 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
521 GrProcessorKeyBuilder* b) {}
522
523 private:
onEmitCode(const EmitArgs & args)524 void onEmitCode(const EmitArgs& args) override {
525 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
526
527 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
528 args.fInputCoverage);
529 }
530
onSetData(const GrGLProgramDataManager &,const GrXferProcessor &)531 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
532
533 typedef GrGLXferProcessor INHERITED;
534 };
535
536 ///////////////////////////////////////////////////////////////////////////////
537
PDLCDXferProcessor(GrColor blendConstant,uint8_t alpha)538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539 : fBlendConstant(blendConstant)
540 , fAlpha(alpha) {
541 this->initClassID<PDLCDXferProcessor>();
542 }
543
Create(GrBlendCoeff srcBlend,GrBlendCoeff dstBlend,const GrProcOptInfo & colorPOI)544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
545 const GrProcOptInfo& colorPOI) {
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) {
547 return NULL;
548 }
549
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
551 return NULL;
552 }
553
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
555 uint8_t alpha = GrColorUnpackA(blendConstant);
556 blendConstant |= (0xff << GrColor_SHIFT_A);
557
558 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha));
559 }
560
~PDLCDXferProcessor()561 PDLCDXferProcessor::~PDLCDXferProcessor() {
562 }
563
onGetGLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const564 void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
565 GrProcessorKeyBuilder* b) const {
566 GLPDLCDXferProcessor::GenKey(*this, caps, b);
567 }
568
createGLInstance() const569 GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
570 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
571 }
572
573 GrXferProcessor::OptFlags
onGetOptimizations(const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI,bool doesStencilWrite,GrColor * overrideColor,const GrDrawTargetCaps & caps)574 PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
575 const GrProcOptInfo& coveragePOI,
576 bool doesStencilWrite,
577 GrColor* overrideColor,
578 const GrDrawTargetCaps& caps) {
579 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
580 // value of the blend the constant. We should already have valid blend coeff's if we are at
581 // a point where we have RGB coverage. We don't need any color stages since the known color
582 // output is already baked into the blendConstant.
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
584 return GrXferProcessor::kOverrideColor_OptFlag;
585 }
586
587 ///////////////////////////////////////////////////////////////////////////////
GrPorterDuffXPFactory(GrBlendCoeff src,GrBlendCoeff dst)588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
589 : fSrcCoeff(src), fDstCoeff(dst) {
590 this->initClassID<GrPorterDuffXPFactory>();
591 }
592
Create(SkXfermode::Mode mode)593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
594 switch (mode) {
595 case SkXfermode::kClear_Mode: {
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
597 return SkRef(&gClearPDXPF);
598 break;
599 }
600 case SkXfermode::kSrc_Mode: {
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
602 return SkRef(&gSrcPDXPF);
603 break;
604 }
605 case SkXfermode::kDst_Mode: {
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
607 return SkRef(&gDstPDXPF);
608 break;
609 }
610 case SkXfermode::kSrcOver_Mode: {
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
612 return SkRef(&gSrcOverPDXPF);
613 break;
614 }
615 case SkXfermode::kDstOver_Mode: {
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
617 return SkRef(&gDstOverPDXPF);
618 break;
619 }
620 case SkXfermode::kSrcIn_Mode: {
621 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
622 return SkRef(&gSrcInPDXPF);
623 break;
624 }
625 case SkXfermode::kDstIn_Mode: {
626 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
627 return SkRef(&gDstInPDXPF);
628 break;
629 }
630 case SkXfermode::kSrcOut_Mode: {
631 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
632 return SkRef(&gSrcOutPDXPF);
633 break;
634 }
635 case SkXfermode::kDstOut_Mode: {
636 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
637 return SkRef(&gDstOutPDXPF);
638 break;
639 }
640 case SkXfermode::kSrcATop_Mode: {
641 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
642 return SkRef(&gSrcATopPDXPF);
643 break;
644 }
645 case SkXfermode::kDstATop_Mode: {
646 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
647 return SkRef(&gDstATopPDXPF);
648 break;
649 }
650 case SkXfermode::kXor_Mode: {
651 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
652 return SkRef(&gXorPDXPF);
653 break;
654 }
655 case SkXfermode::kPlus_Mode: {
656 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
657 return SkRef(&gPlusPDXPF);
658 break;
659 }
660 case SkXfermode::kModulate_Mode: {
661 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
662 return SkRef(&gModulatePDXPF);
663 break;
664 }
665 case SkXfermode::kScreen_Mode: {
666 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
667 return SkRef(&gScreenPDXPF);
668 break;
669 }
670 default:
671 return NULL;
672 }
673 }
674
675 GrXferProcessor*
onCreateXferProcessor(const GrDrawTargetCaps & caps,const GrProcOptInfo & colorPOI,const GrProcOptInfo & covPOI,const GrDeviceCoordTexture * dstCopy) const676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
677 const GrProcOptInfo& colorPOI,
678 const GrProcOptInfo& covPOI,
679 const GrDeviceCoordTexture* dstCopy) const {
680 if (covPOI.isFourChannelOutput()) {
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI);
682 } else {
683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
684 this->willReadDstColor(caps, colorPOI, covPOI));
685 }
686 }
687
supportsRGBCoverage(GrColor,uint32_t knownColorFlags) const688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
689 uint32_t knownColorFlags) const {
690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
691 kRGBA_GrColorComponentFlags == knownColorFlags) {
692 return true;
693 }
694 return false;
695 }
696
getInvariantOutput(const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI,GrXPFactory::InvariantOutput * output) const697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
698 const GrProcOptInfo& coveragePOI,
699 GrXPFactory::InvariantOutput* output) const {
700 if (!coveragePOI.isSolidWhite()) {
701 output->fWillBlendWithDst = true;
702 output->fBlendedColorFlags = 0;
703 return;
704 }
705
706 GrBlendCoeff srcCoeff = fSrcCoeff;
707 GrBlendCoeff dstCoeff = fDstCoeff;
708
709 // TODO: figure out to merge this simplify with other current optimization code paths and
710 // eventually remove from GrBlend
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
712 0, 0, 0);
713
714 if (GrBlendCoeffRefsDst(srcCoeff)) {
715 output->fWillBlendWithDst = true;
716 output->fBlendedColorFlags = 0;
717 return;
718 }
719
720 if (kZero_GrBlendCoeff != dstCoeff) {
721 bool srcAIsOne = colorPOI.isOpaque();
722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
723 output->fWillBlendWithDst = true;
724 }
725 output->fBlendedColorFlags = 0;
726 return;
727 }
728
729 switch (srcCoeff) {
730 case kZero_GrBlendCoeff:
731 output->fBlendedColor = 0;
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
733 break;
734
735 case kOne_GrBlendCoeff:
736 output->fBlendedColor = colorPOI.color();
737 output->fBlendedColorFlags = colorPOI.validFlags();
738 break;
739
740 // The src coeff should never refer to the src and if it refers to dst then opaque
741 // should have been false.
742 case kSC_GrBlendCoeff:
743 case kISC_GrBlendCoeff:
744 case kDC_GrBlendCoeff:
745 case kIDC_GrBlendCoeff:
746 case kSA_GrBlendCoeff:
747 case kISA_GrBlendCoeff:
748 case kDA_GrBlendCoeff:
749 case kIDA_GrBlendCoeff:
750 default:
751 SkFAIL("srcCoeff should not refer to src or dst.");
752 break;
753
754 // TODO: update this once GrPaint actually has a const color.
755 case kConstC_GrBlendCoeff:
756 case kIConstC_GrBlendCoeff:
757 case kConstA_GrBlendCoeff:
758 case kIConstA_GrBlendCoeff:
759 output->fBlendedColorFlags = 0;
760 break;
761 }
762
763 output->fWillBlendWithDst = false;
764 }
765
willReadDstColor(const GrDrawTargetCaps & caps,const GrProcOptInfo & colorPOI,const GrProcOptInfo & coveragePOI) const766 bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps,
767 const GrProcOptInfo& colorPOI,
768 const GrProcOptInfo& coveragePOI) const {
769 // We can always blend correctly if we have dual source blending.
770 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
771 return false;
772 }
773
774 if (can_tweak_alpha_for_coverage(fDstCoeff)) {
775 return false;
776 }
777
778 bool srcAIsOne = colorPOI.isOpaque();
779
780 if (kZero_GrBlendCoeff == fDstCoeff) {
781 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
782 return false;
783 }
784 }
785
786 // Reduces to: coeffS * (Cov*S) + D
787 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
788 return false;
789 }
790
791 // We can always blend correctly if we have solid coverage.
792 if (coveragePOI.isSolidWhite()) {
793 return false;
794 }
795
796 return true;
797 }
798
799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800
TestCreate(SkRandom * random,GrContext *,const GrDrawTargetCaps &,GrTexture * [])801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
802 GrContext*,
803 const GrDrawTargetCaps&,
804 GrTexture*[]) {
805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
806 return GrPorterDuffXPFactory::Create(mode);
807 }
808
809