Home | History | Annotate | Download | only in effects
      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 
     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:
     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 
     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 
    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 
    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:
    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 
    204 private:
    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 
    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 
    291 PorterDuffXferProcessor::~PorterDuffXferProcessor() {
    292 }
    293 
    294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
    295                                                   GrProcessorKeyBuilder* b) const {
    296     GLPorterDuffXferProcessor::GenKey(*this, caps, b);
    297 }
    298 
    299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
    300     return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
    301 }
    302 
    303 GrXferProcessor::OptFlags
    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 
    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
    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 
    461 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 
    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 
    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 
    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 
    514 class GLPDLCDXferProcessor : public GrGLXferProcessor {
    515 public:
    516     GLPDLCDXferProcessor(const GrProcessor&) {}
    517 
    518     virtual ~GLPDLCDXferProcessor() {}
    519 
    520     static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
    521                        GrProcessorKeyBuilder* b) {}
    522 
    523 private:
    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 
    538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
    539     : fBlendConstant(blendConstant)
    540     , fAlpha(alpha) {
    541     this->initClassID<PDLCDXferProcessor>();
    542 }
    543 
    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 
    561 PDLCDXferProcessor::~PDLCDXferProcessor() {
    562 }
    563 
    564 void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
    565                                              GrProcessorKeyBuilder* b) const {
    566     GLPDLCDXferProcessor::GenKey(*this, caps, b);
    567 }
    568 
    569 GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
    570     return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
    571 }
    572 
    573 GrXferProcessor::OptFlags
    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 ///////////////////////////////////////////////////////////////////////////////
    588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
    589     : fSrcCoeff(src), fDstCoeff(dst) {
    590     this->initClassID<GrPorterDuffXPFactory>();
    591 }
    592 
    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*
    676 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 
    688 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 
    697 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 
    766 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 
    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