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