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
20static 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
35class PorterDuffXferProcessor : public GrXferProcessor {
36public:
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
46    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
84    PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
85    SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
86
87    GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
88    GrBlendCoeff getDstBlend() const { return fDstBlend; }
89
90private:
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
102    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
113    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
143bool 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
187class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188public:
189    GLPorterDuffXferProcessor(const GrProcessor&) {}
190
191    virtual ~GLPorterDuffXferProcessor() {}
192
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
204private:
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
270    void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
271
272    typedef GrGLXferProcessor INHERITED;
273};
274
275///////////////////////////////////////////////////////////////////////////////
276
277PorterDuffXferProcessor::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
291PorterDuffXferProcessor::~PorterDuffXferProcessor() {
292}
293
294void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
295                                                  GrProcessorKeyBuilder* b) const {
296    GLPorterDuffXferProcessor::GenKey(*this, caps, b);
297}
298
299GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300    return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
301}
302
303GrXferProcessor::OptFlags
304PorterDuffXferProcessor::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
316void 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
360GrXferProcessor::OptFlags
361PorterDuffXferProcessor::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
461bool PorterDuffXferProcessor::hasSecondaryOutput() const {
462    return kNone_SecondaryOutputType != fSecondaryOutputType;
463}
464
465///////////////////////////////////////////////////////////////////////////////
466
467class PDLCDXferProcessor : public GrXferProcessor {
468public:
469    static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
470                                   const GrProcOptInfo& colorPOI);
471
472    ~PDLCDXferProcessor() override;
473
474    const char* name() const override { return "Porter Duff LCD"; }
475
476    GrGLXferProcessor* createGLInstance() const override;
477
478    bool hasSecondaryOutput() const override { return false; }
479
480private:
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
491    void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
492        blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
493        blendInfo->fDstBlend = kISC_GrBlendCoeff;
494        blendInfo->fBlendConstant = fBlendConstant;
495    }
496
497    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
514class GLPDLCDXferProcessor : public GrGLXferProcessor {
515public:
516    GLPDLCDXferProcessor(const GrProcessor&) {}
517
518    virtual ~GLPDLCDXferProcessor() {}
519
520    static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
521                       GrProcessorKeyBuilder* b) {}
522
523private:
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
531    void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
532
533    typedef GrGLXferProcessor INHERITED;
534};
535
536///////////////////////////////////////////////////////////////////////////////
537
538PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539    : fBlendConstant(blendConstant)
540    , fAlpha(alpha) {
541    this->initClassID<PDLCDXferProcessor>();
542}
543
544GrXferProcessor* 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
561PDLCDXferProcessor::~PDLCDXferProcessor() {
562}
563
564void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
565                                             GrProcessorKeyBuilder* b) const {
566    GLPDLCDXferProcessor::GenKey(*this, caps, b);
567}
568
569GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
570    return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
571}
572
573GrXferProcessor::OptFlags
574PDLCDXferProcessor::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///////////////////////////////////////////////////////////////////////////////
588GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
589    : fSrcCoeff(src), fDstCoeff(dst) {
590    this->initClassID<GrPorterDuffXPFactory>();
591}
592
593GrXPFactory* 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
675GrXferProcessor*
676GrPorterDuffXPFactory::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
688bool 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
697void 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
766bool 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
799GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800
801GrXPFactory* 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