LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrPorterDuffXferProcessor.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 274 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2014 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "effects/GrPorterDuffXferProcessor.h"
       9             : 
      10             : #include "GrBlend.h"
      11             : #include "GrCaps.h"
      12             : #include "GrPipeline.h"
      13             : #include "GrProcessor.h"
      14             : #include "GrProcessorAnalysis.h"
      15             : #include "GrTypes.h"
      16             : #include "GrXferProcessor.h"
      17             : #include "glsl/GrGLSLBlend.h"
      18             : #include "glsl/GrGLSLFragmentShaderBuilder.h"
      19             : #include "glsl/GrGLSLProgramDataManager.h"
      20             : #include "glsl/GrGLSLUniformHandler.h"
      21             : #include "glsl/GrGLSLXferProcessor.h"
      22             : 
      23             : /**
      24             :  * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
      25             :  */
      26             : class BlendFormula {
      27             : public:
      28             :     /**
      29             :      * Values the shader can write to primary and secondary outputs. These must all be modulated by
      30             :      * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
      31             :      */
      32             :     enum OutputType {
      33             :         kNone_OutputType,        //<! 0
      34             :         kCoverage_OutputType,    //<! inputCoverage
      35             :         kModulate_OutputType,    //<! inputColor * inputCoverage
      36             :         kSAModulate_OutputType,  //<! inputColor.a * inputCoverage
      37             :         kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
      38             :         kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
      39             : 
      40             :         kLast_OutputType = kISCModulate_OutputType
      41             :     };
      42             : 
      43           0 :     BlendFormula() = default;
      44             : 
      45             :     constexpr BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation,
      46             :                            GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff)
      47             :             : fPrimaryOutputType(primaryOut)
      48             :             , fSecondaryOutputType(secondaryOut)
      49             :             , fBlendEquation(equation)
      50             :             , fSrcCoeff(srcCoeff)
      51             :             , fDstCoeff(dstCoeff)
      52             :             , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {}
      53             : 
      54           0 :     BlendFormula& operator=(const BlendFormula& other) {
      55           0 :         SkDEBUGCODE(other.validatePreoptimized());
      56           0 :         fData = other.fData;
      57           0 :         return *this;
      58             :     }
      59             : 
      60           0 :     bool operator==(const BlendFormula& other) const {
      61           0 :         SkDEBUGCODE(this->validatePreoptimized());
      62           0 :         SkDEBUGCODE(other.validatePreoptimized());
      63           0 :         return fData == other.fData;
      64             :     }
      65             : 
      66           0 :     bool hasSecondaryOutput() const {
      67           0 :         SkDEBUGCODE(this->validatePreoptimized());
      68           0 :         return kNone_OutputType != fSecondaryOutputType;
      69             :     }
      70           0 :     bool modifiesDst() const {
      71           0 :         SkDEBUGCODE(this->validatePreoptimized());
      72           0 :         return SkToBool(fProps & kModifiesDst_Property);
      73             :     }
      74           0 :     bool usesDstColor() const {
      75           0 :         SkDEBUGCODE(this->validatePreoptimized());
      76           0 :         return SkToBool(fProps & kUsesDstColor_Property);
      77             :     }
      78           0 :     bool usesInputColor() const {
      79           0 :         SkDEBUGCODE(this->validatePreoptimized());
      80           0 :         return SkToBool(fProps & kUsesInputColor_Property);
      81             :     }
      82           0 :     bool canTweakAlphaForCoverage() const {
      83           0 :         SkDEBUGCODE(this->validatePreoptimized());
      84           0 :         return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
      85             :     }
      86             : 
      87           0 :     GrBlendEquation equation() const {
      88           0 :         SkDEBUGCODE(this->validatePreoptimized());
      89           0 :         return fBlendEquation;
      90             :     }
      91             : 
      92           0 :     GrBlendCoeff srcCoeff() const {
      93           0 :         SkDEBUGCODE(this->validatePreoptimized());
      94           0 :         return fSrcCoeff;
      95             :     }
      96             : 
      97           0 :     GrBlendCoeff dstCoeff() const {
      98           0 :         SkDEBUGCODE(this->validatePreoptimized());
      99           0 :         return fDstCoeff;
     100             :     }
     101             : 
     102           0 :     OutputType primaryOutput() const {
     103           0 :         SkDEBUGCODE(this->validatePreoptimized());
     104           0 :         return fPrimaryOutputType;
     105             :     }
     106             : 
     107           0 :     OutputType secondaryOutput() const {
     108           0 :         SkDEBUGCODE(this->validatePreoptimized());
     109           0 :         return fSecondaryOutputType;
     110             :     }
     111             : 
     112             : private:
     113             :     enum Properties {
     114             :         kModifiesDst_Property              = 1,
     115             :         kUsesDstColor_Property             = 1 << 1,
     116             :         kUsesInputColor_Property           = 1 << 2,
     117             :         kCanTweakAlphaForCoverage_Property = 1 << 3,
     118             : 
     119             :         kLast_Property = kCanTweakAlphaForCoverage_Property
     120             :     };
     121             :     GR_DECL_BITFIELD_OPS_FRIENDS(Properties)
     122             : 
     123             : #ifdef SK_DEBUG
     124           0 :     void validatePreoptimized() const {
     125             :         // The provided formula should already be optimized before a BlendFormula is constructed.
     126             :         // Preferably these asserts would be done statically in the constexpr constructor, but this
     127             :         // is not allowed in C++11.
     128           0 :         SkASSERT((kNone_OutputType == fPrimaryOutputType) ==
     129             :                  !GrBlendCoeffsUseSrcColor(fSrcCoeff, fDstCoeff));
     130           0 :         SkASSERT(!GrBlendCoeffRefsSrc2(fSrcCoeff));
     131           0 :         SkASSERT((kNone_OutputType == fSecondaryOutputType) == !GrBlendCoeffRefsSrc2(fDstCoeff));
     132           0 :         SkASSERT(fPrimaryOutputType != fSecondaryOutputType ||
     133             :                  kNone_OutputType == fPrimaryOutputType);
     134           0 :         SkASSERT(kNone_OutputType != fPrimaryOutputType ||
     135             :                  kNone_OutputType == fSecondaryOutputType);
     136           0 :     }
     137             : #endif
     138             : 
     139             :     /**
     140             :      * Deduce the properties of a BlendFormula.
     141             :      */
     142             :     static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut,
     143             :                                               GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff,
     144             :                                               GrBlendCoeff DstCoeff);
     145             : 
     146             :     union {
     147             :         struct {
     148             :             // We allot the enums one more bit than they require because MSVC seems to sign-extend
     149             :             // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
     150             :             OutputType        fPrimaryOutputType    : 4;
     151             :             OutputType        fSecondaryOutputType  : 4;
     152             :             GrBlendEquation   fBlendEquation        : 6;
     153             :             GrBlendCoeff      fSrcCoeff             : 6;
     154             :             GrBlendCoeff      fDstCoeff             : 6;
     155             :             Properties        fProps                : 32 - (4 + 4 + 6 + 6 + 6);
     156             :         };
     157             :         uint32_t fData;
     158             :     };
     159             : 
     160             :     GR_STATIC_ASSERT(kLast_OutputType      < (1 << 3));
     161             :     GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
     162             :     GR_STATIC_ASSERT(kLast_GrBlendCoeff    < (1 << 5));
     163             :     GR_STATIC_ASSERT(kLast_Property        < (1 << 6));
     164             : };
     165             : 
     166             : GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
     167             : 
     168           0 : GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
     169             : 
     170             : constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut,
     171             :                                                                OutputType SecondaryOut,
     172             :                                                                GrBlendEquation BlendEquation,
     173             :                                                                GrBlendCoeff SrcCoeff,
     174             :                                                                GrBlendCoeff DstCoeff) {
     175             :     return static_cast<Properties>(
     176             :             (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) |
     177             :             (GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff) ? kUsesDstColor_Property : 0) |
     178             :             ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) ||
     179             :                              (SecondaryOut >= kModulate_OutputType &&
     180             :                               GrBlendCoeffRefsSrc2(DstCoeff))
     181             :                      ? kUsesInputColor_Property
     182             :                      : 0) |  // We assert later that SrcCoeff doesn't ref src2.
     183             :             ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
     184             :                              kNone_OutputType == SecondaryOut &&
     185             :                              GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff)
     186             :                      ? kCanTweakAlphaForCoverage_Property
     187             :                      : 0));
     188             : }
     189             : 
     190             : /**
     191             :  * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
     192             :  * Porter Duff formula.
     193             :  */
     194             : static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
     195             :     // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none.
     196             :     return (kZero_GrBlendCoeff == srcCoeff &&
     197             :             (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff))
     198             :            ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType,
     199             :                           kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff)
     200             :            : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType,
     201             :                         kAdd_GrBlendEquation, srcCoeff, dstCoeff);
     202             : }
     203             : 
     204             : /**
     205             :  * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in
     206             :  * LCD dst-out.
     207             :  */
     208             : static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
     209             :     return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType,
     210             :                         kAdd_GrBlendEquation, srcCoeff, dstCoeff);
     211             : }
     212             : 
     213             : /**
     214             :  * When there is coverage, the equation with f=coverage is:
     215             :  *
     216             :  *   D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
     217             :  *
     218             :  * This can be rewritten as:
     219             :  *
     220             :  *   D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
     221             :  *
     222             :  * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
     223             :  * HW dst coeff with IS2C.
     224             :  *
     225             :  * Xfer modes: dst-atop (Sa!=1)
     226             :  */
     227             : static constexpr BlendFormula MakeCoverageFormula(
     228             :         BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) {
     229             :     return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput,
     230             :                         kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff);
     231             : }
     232             : 
     233             : /**
     234             :  * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
     235             :  *
     236             :  *   D' = f * D * dstCoeff + (1-f) * D
     237             :  *
     238             :  * This can be rewritten as:
     239             :  *
     240             :  *   D' = D - D * [f * (1 - dstCoeff)]
     241             :  *
     242             :  * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
     243             :  * subtract HW blend equation with coeffs of (DC, One).
     244             :  *
     245             :  * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
     246             :  */
     247             : static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula(
     248             :         BlendFormula::OutputType oneMinusDstCoeffModulateOutput) {
     249             :     return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType,
     250             :                         kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff);
     251             : }
     252             : 
     253             : /**
     254             :  * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
     255             :  *
     256             :  *   D' = f * S * srcCoeff + (1-f) * D
     257             :  *
     258             :  * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
     259             :  * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
     260             :  *
     261             :  * Xfer modes (Sa!=1): src, src-in, src-out
     262             :  */
     263             : static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) {
     264             :     return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType,
     265             :                         kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff);
     266             : }
     267             : 
     268             : // Older GCC won't like the constexpr arrays because of
     269             : // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61484.
     270             : // MSVC crashes with an internal compiler error.
     271             : #if !defined(__clang__) && ((defined(__GNUC__) && __GNUC__ < 5) || defined(_MSC_VER))
     272             : #   define MAYBE_CONSTEXPR const
     273             : #else
     274             : #   define MAYBE_CONSTEXPR constexpr
     275             : #endif
     276             : 
     277             : /**
     278             :  * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
     279             :  * with and without an opaque input color. Optimization properties are deduced at compile time so we
     280             :  * can make runtime decisions quickly. RGB coverage is not supported.
     281             :  */
     282             : static MAYBE_CONSTEXPR BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
     283             :                      /*>> No coverage, input color unknown <<*/ {{
     284             : 
     285             :     /* clear */      MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
     286             :     /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
     287             :     /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     288             :     /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
     289             :     /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     290             :     /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
     291             :     /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff),
     292             :     /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
     293             :     /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
     294             :     /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
     295             :     /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kSA_GrBlendCoeff),
     296             :     /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
     297             :     /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
     298             :     /* modulate */   MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
     299             :     /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
     300             : 
     301             :                      }, /*>> Has coverage, input color unknown <<*/ {
     302             : 
     303             :     /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
     304             :     /* src */        MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff),
     305             :     /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     306             :     /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
     307             :     /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     308             :     /* src-in */     MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff),
     309             :     /* dst-in */     MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
     310             :     /* src-out */    MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff),
     311             :     /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
     312             :     /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
     313             :     /* dst-atop */   MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
     314             :     /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
     315             :     /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
     316             :     /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
     317             :     /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
     318             : 
     319             :                      }}, /*>> No coverage, input color opaque <<*/ {{
     320             : 
     321             :     /* clear */      MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
     322             :     /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
     323             :     /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     324             :     /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kZero_GrBlendCoeff),
     325             :     /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     326             :     /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
     327             :     /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     328             :     /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
     329             :     /* dst-out */    MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
     330             :     /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kZero_GrBlendCoeff),
     331             :     /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     332             :     /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kZero_GrBlendCoeff),
     333             :     /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
     334             :     /* modulate */   MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
     335             :     /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
     336             : 
     337             :                      }, /*>> Has coverage, input color opaque <<*/ {
     338             : 
     339             :     /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
     340             :     /* src */        MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
     341             :     /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     342             :     /* src-over */   MakeCoeffFormula(kOne_GrBlendCoeff,  kISA_GrBlendCoeff),
     343             :     /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     344             :     /* src-in */     MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
     345             :     /* dst-in */     MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     346             :     /* src-out */    MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
     347             :     /* dst-out */    MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
     348             :     /* src-atop */   MakeCoeffFormula(kDA_GrBlendCoeff,   kISA_GrBlendCoeff),
     349             :     /* dst-atop */   MakeCoeffFormula(kIDA_GrBlendCoeff,  kOne_GrBlendCoeff),
     350             :     /* xor */        MakeCoeffFormula(kIDA_GrBlendCoeff,  kISA_GrBlendCoeff),
     351             :     /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff,  kOne_GrBlendCoeff),
     352             :     /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
     353             :     /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff,  kISC_GrBlendCoeff),
     354             : }}};
     355             : 
     356             : static MAYBE_CONSTEXPR BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
     357             :     /* clear */      MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
     358             :     /* src */        MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
     359             :     /* dst */        MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
     360             :     /* src-over */   MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
     361             :     /* dst-over */   MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
     362             :     /* src-in */     MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
     363             :     /* dst-in */     MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
     364             :     /* src-out */    MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
     365             :     /* dst-out */    MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff),
     366             :     /* src-atop */   MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
     367             :     /* dst-atop */   MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
     368             :     /* xor */        MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
     369             :     /* plus */       MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
     370             :     /* modulate */   MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
     371             :     /* screen */     MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
     372             : };
     373             : 
     374             : #undef MAYBE_CONSTEXPR
     375             : 
     376           0 : static BlendFormula get_blend_formula(bool isOpaque,
     377             :                                       bool hasCoverage,
     378             :                                       bool hasMixedSamples,
     379             :                                       SkBlendMode xfermode) {
     380           0 :     SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
     381           0 :     bool conflatesCoverage = hasCoverage || hasMixedSamples;
     382           0 :     return gBlendTable[isOpaque][conflatesCoverage][(int)xfermode];
     383             : }
     384             : 
     385           0 : static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) {
     386           0 :     SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
     387             : 
     388           0 :     return gLCDBlendTable[(int)xfermode];
     389             : }
     390             : 
     391             : ///////////////////////////////////////////////////////////////////////////////
     392             : 
     393           0 : class PorterDuffXferProcessor : public GrXferProcessor {
     394             : public:
     395           0 :     PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
     396           0 :         this->initClassID<PorterDuffXferProcessor>();
     397           0 :     }
     398             : 
     399           0 :     const char* name() const override { return "Porter Duff"; }
     400             : 
     401             :     GrGLSLXferProcessor* createGLSLInstance() const override;
     402             : 
     403           0 :     BlendFormula getBlendFormula() const { return fBlendFormula; }
     404             : 
     405             : private:
     406             :     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
     407             : 
     408           0 :     bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
     409             : 
     410           0 :     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
     411           0 :         blendInfo->fEquation = fBlendFormula.equation();
     412           0 :         blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
     413           0 :         blendInfo->fDstBlend = fBlendFormula.dstCoeff();
     414           0 :         blendInfo->fWriteColor = fBlendFormula.modifiesDst();
     415           0 :     }
     416             : 
     417           0 :     bool onIsEqual(const GrXferProcessor& xpBase) const override {
     418           0 :         const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
     419           0 :         return fBlendFormula == xp.fBlendFormula;
     420             :     }
     421             : 
     422             :     const BlendFormula fBlendFormula;
     423             : 
     424             :     typedef GrXferProcessor INHERITED;
     425             : };
     426             : 
     427             : ///////////////////////////////////////////////////////////////////////////////
     428             : 
     429           0 : static void append_color_output(const PorterDuffXferProcessor& xp,
     430             :                                 GrGLSLXPFragmentBuilder* fragBuilder,
     431             :                                 BlendFormula::OutputType outputType, const char* output,
     432             :                                 const char* inColor, const char* inCoverage) {
     433           0 :     SkASSERT(inCoverage);
     434           0 :     SkASSERT(inColor);
     435           0 :     switch (outputType) {
     436             :         case BlendFormula::kNone_OutputType:
     437           0 :             fragBuilder->codeAppendf("%s = vec4(0.0);", output);
     438           0 :             break;
     439             :         case BlendFormula::kCoverage_OutputType:
     440             :             // We can have a coverage formula while not reading coverage if there are mixed samples.
     441           0 :             fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
     442           0 :             break;
     443             :         case BlendFormula::kModulate_OutputType:
     444           0 :             fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
     445           0 :             break;
     446             :         case BlendFormula::kSAModulate_OutputType:
     447           0 :             fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
     448           0 :             break;
     449             :         case BlendFormula::kISAModulate_OutputType:
     450           0 :             fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
     451           0 :             break;
     452             :         case BlendFormula::kISCModulate_OutputType:
     453           0 :             fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
     454           0 :             break;
     455             :         default:
     456           0 :             SkFAIL("Unsupported output type.");
     457           0 :             break;
     458             :     }
     459           0 : }
     460             : 
     461           0 : class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
     462             : public:
     463           0 :     static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
     464           0 :         const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
     465           0 :         b->add32(xp.getBlendFormula().primaryOutput() |
     466           0 :                  (xp.getBlendFormula().secondaryOutput() << 3));
     467             :         GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
     468           0 :     }
     469             : 
     470             : private:
     471           0 :     void emitOutputsForBlendState(const EmitArgs& args) override {
     472           0 :         const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
     473           0 :         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
     474             : 
     475           0 :         BlendFormula blendFormula = xp.getBlendFormula();
     476           0 :         if (blendFormula.hasSecondaryOutput()) {
     477           0 :             append_color_output(xp, fragBuilder, blendFormula.secondaryOutput(),
     478           0 :                                 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
     479             :         }
     480           0 :         append_color_output(xp, fragBuilder, blendFormula.primaryOutput(), args.fOutputPrimary,
     481           0 :                             args.fInputColor, args.fInputCoverage);
     482           0 :     }
     483             : 
     484           0 :     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
     485             : 
     486             :     typedef GrGLSLXferProcessor INHERITED;
     487             : };
     488             : 
     489             : ///////////////////////////////////////////////////////////////////////////////
     490             : 
     491           0 : void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
     492             :                                                     GrProcessorKeyBuilder* b) const {
     493           0 :     GLPorterDuffXferProcessor::GenKey(*this, b);
     494           0 : }
     495             : 
     496           0 : GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
     497           0 :     return new GLPorterDuffXferProcessor;
     498             : }
     499             : 
     500             : ///////////////////////////////////////////////////////////////////////////////
     501             : 
     502           0 : class ShaderPDXferProcessor : public GrXferProcessor {
     503             : public:
     504           0 :     ShaderPDXferProcessor(bool hasMixedSamples, SkBlendMode xfermode)
     505           0 :             : INHERITED(true, hasMixedSamples), fXfermode(xfermode) {
     506           0 :         this->initClassID<ShaderPDXferProcessor>();
     507           0 :     }
     508             : 
     509           0 :     const char* name() const override { return "Porter Duff Shader"; }
     510             : 
     511             :     GrGLSLXferProcessor* createGLSLInstance() const override;
     512             : 
     513           0 :     SkBlendMode getXfermode() const { return fXfermode; }
     514             : 
     515             : private:
     516             :     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
     517             : 
     518           0 :     bool onIsEqual(const GrXferProcessor& xpBase) const override {
     519           0 :         const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
     520           0 :         return fXfermode == xp.fXfermode;
     521             :     }
     522             : 
     523             :     const SkBlendMode fXfermode;
     524             : 
     525             :     typedef GrXferProcessor INHERITED;
     526             : };
     527             : 
     528             : ///////////////////////////////////////////////////////////////////////////////
     529             : 
     530           0 : class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
     531             : public:
     532           0 :     static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
     533           0 :         const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
     534           0 :         b->add32((int)xp.getXfermode());
     535           0 :     }
     536             : 
     537             : private:
     538           0 :     void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
     539             :                                  GrGLSLUniformHandler* uniformHandler,
     540             :                                  const char* srcColor,
     541             :                                  const char* srcCoverage,
     542             :                                  const char* dstColor,
     543             :                                  const char* outColor,
     544             :                                  const char* outColorSecondary,
     545             :                                  const GrXferProcessor& proc) override {
     546           0 :         const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
     547             : 
     548           0 :         GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
     549             : 
     550             :         // Apply coverage.
     551           0 :         INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
     552           0 :                                              outColorSecondary, xp);
     553           0 :     }
     554             : 
     555           0 :     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
     556             : 
     557             :     typedef GrGLSLXferProcessor INHERITED;
     558             : };
     559             : 
     560             : ///////////////////////////////////////////////////////////////////////////////
     561             : 
     562           0 : void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
     563             :                                                   GrProcessorKeyBuilder* b) const {
     564           0 :     GLShaderPDXferProcessor::GenKey(*this, b);
     565           0 : }
     566             : 
     567           0 : GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
     568           0 :     return new GLShaderPDXferProcessor;
     569             : }
     570             : 
     571             : ///////////////////////////////////////////////////////////////////////////////
     572             : 
     573             : class PDLCDXferProcessor : public GrXferProcessor {
     574             : public:
     575             :     static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
     576             :                                              const GrProcessorAnalysisColor& inputColor);
     577             : 
     578             :     ~PDLCDXferProcessor() override;
     579             : 
     580           0 :     const char* name() const override { return "Porter Duff LCD"; }
     581             : 
     582             :     GrGLSLXferProcessor* createGLSLInstance() const override;
     583             : 
     584           0 :     uint8_t alpha() const { return fAlpha; }
     585             : 
     586             : private:
     587             :     PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
     588             : 
     589             :     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
     590             : 
     591           0 :     void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
     592           0 :         blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
     593           0 :         blendInfo->fDstBlend = kISC_GrBlendCoeff;
     594           0 :         blendInfo->fBlendConstant = fBlendConstant;
     595           0 :     }
     596             : 
     597           0 :     bool onIsEqual(const GrXferProcessor& xpBase) const override {
     598           0 :         const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
     599           0 :         if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) {
     600           0 :             return false;
     601             :         }
     602           0 :         return true;
     603             :     }
     604             : 
     605             :     GrColor fBlendConstant;
     606             :     uint8_t fAlpha;
     607             : 
     608             :     typedef GrXferProcessor INHERITED;
     609             : };
     610             : 
     611             : ///////////////////////////////////////////////////////////////////////////////
     612             : 
     613             : class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
     614             : public:
     615           0 :     GLPDLCDXferProcessor(const GrProcessor&) : fLastAlpha(SK_MaxU32) {}
     616             : 
     617           0 :     ~GLPDLCDXferProcessor() override {}
     618             : 
     619           0 :     static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps,
     620           0 :                        GrProcessorKeyBuilder* b) {}
     621             : 
     622             : private:
     623           0 :     void emitOutputsForBlendState(const EmitArgs& args) override {
     624             :         const char* alpha;
     625           0 :         fAlphaUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
     626           0 :                                                          kDefault_GrSLPrecision, "alpha", &alpha);
     627           0 :         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
     628             :         // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
     629             :         // value of the src color. We know that there are no color stages (or we wouldn't have
     630             :         // created this xp) and the r,g, and b channels of the op's input color are baked into the
     631             :         // blend constant.
     632           0 :         SkASSERT(args.fInputCoverage);
     633           0 :         fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, alpha, args.fInputCoverage);
     634           0 :     }
     635             : 
     636           0 :     void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override {
     637           0 :         uint32_t alpha = SkToU32(xp.cast<PDLCDXferProcessor>().alpha());
     638           0 :         if (fLastAlpha != alpha) {
     639           0 :             pdm.set1f(fAlphaUniform, alpha / 255.f);
     640           0 :             fLastAlpha = alpha;
     641             :         }
     642           0 :     }
     643             : 
     644             :     GrGLSLUniformHandler::UniformHandle fAlphaUniform;
     645             :     uint32_t fLastAlpha;
     646             :     typedef GrGLSLXferProcessor INHERITED;
     647             : };
     648             : 
     649             : ///////////////////////////////////////////////////////////////////////////////
     650             : 
     651           0 : PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
     652             :     : fBlendConstant(blendConstant)
     653           0 :     , fAlpha(alpha) {
     654           0 :     this->initClassID<PDLCDXferProcessor>();
     655           0 : }
     656             : 
     657           0 : sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
     658             :                                                       const GrProcessorAnalysisColor& color) {
     659           0 :     if (SkBlendMode::kSrcOver != mode) {
     660           0 :         return nullptr;
     661             :     }
     662             :     GrColor blendConstant;
     663           0 :     if (!color.isConstant(&blendConstant)) {
     664           0 :         return nullptr;
     665             :     }
     666           0 :     blendConstant = GrUnpremulColor(blendConstant);
     667           0 :     uint8_t alpha = GrColorUnpackA(blendConstant);
     668           0 :     blendConstant |= (0xff << GrColor_SHIFT_A);
     669           0 :     return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstant, alpha));
     670             : }
     671             : 
     672           0 : PDLCDXferProcessor::~PDLCDXferProcessor() {
     673           0 : }
     674             : 
     675           0 : void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
     676             :                                                GrProcessorKeyBuilder* b) const {
     677           0 :     GLPDLCDXferProcessor::GenKey(*this, caps, b);
     678           0 : }
     679             : 
     680           0 : GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
     681           0 :     return new GLPDLCDXferProcessor(*this);
     682             : }
     683             : 
     684             : ///////////////////////////////////////////////////////////////////////////////
     685             : 
     686             : constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
     687             :         : fBlendMode(xfermode) {}
     688             : 
     689           0 : const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
     690           0 :     SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
     691             : 
     692             :     // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are
     693             :     // null.
     694             : #ifdef SK_BUILD_FOR_WIN
     695             : #define _CONSTEXPR_
     696             : #else
     697             : #define _CONSTEXPR_ constexpr
     698             : #endif
     699             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
     700             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
     701             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
     702             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
     703             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
     704             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
     705             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
     706             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
     707             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
     708             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
     709             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
     710             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
     711             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
     712             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
     713             :     static _CONSTEXPR_ const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
     714             : #undef _CONSTEXPR_
     715             : 
     716           0 :     switch (blendMode) {
     717             :         case SkBlendMode::kClear:
     718           0 :             return &gClearPDXPF;
     719             :         case SkBlendMode::kSrc:
     720           0 :             return &gSrcPDXPF;
     721             :         case SkBlendMode::kDst:
     722           0 :             return &gDstPDXPF;
     723             :         case SkBlendMode::kSrcOver:
     724           0 :             return &gSrcOverPDXPF;
     725             :         case SkBlendMode::kDstOver:
     726           0 :             return &gDstOverPDXPF;
     727             :         case SkBlendMode::kSrcIn:
     728           0 :             return &gSrcInPDXPF;
     729             :         case SkBlendMode::kDstIn:
     730           0 :             return &gDstInPDXPF;
     731             :         case SkBlendMode::kSrcOut:
     732           0 :             return &gSrcOutPDXPF;
     733             :         case SkBlendMode::kDstOut:
     734           0 :             return &gDstOutPDXPF;
     735             :         case SkBlendMode::kSrcATop:
     736           0 :             return &gSrcATopPDXPF;
     737             :         case SkBlendMode::kDstATop:
     738           0 :             return &gDstATopPDXPF;
     739             :         case SkBlendMode::kXor:
     740           0 :             return &gXorPDXPF;
     741             :         case SkBlendMode::kPlus:
     742           0 :             return &gPlusPDXPF;
     743             :         case SkBlendMode::kModulate:
     744           0 :             return &gModulatePDXPF;
     745             :         case SkBlendMode::kScreen:
     746           0 :             return &gScreenPDXPF;
     747             :         default:
     748           0 :             SkFAIL("Unexpected blend mode.");
     749           0 :             return nullptr;
     750             :     }
     751             : }
     752             : 
     753           0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
     754             :         const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
     755             :         bool hasMixedSamples, const GrCaps& caps) const {
     756           0 :     BlendFormula blendFormula;
     757           0 :     if (coverage == GrProcessorAnalysisCoverage::kLCD) {
     758           0 :         if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() &&
     759           0 :             !caps.shaderCaps()->dualSourceBlendingSupport() &&
     760           0 :             !caps.shaderCaps()->dstReadInShaderSupport()) {
     761             :             // If we don't have dual source blending or in shader dst reads, we fall back to this
     762             :             // trick for rendering SrcOver LCD text instead of doing a dst copy.
     763           0 :             return PDLCDXferProcessor::Make(fBlendMode, color);
     764             :         }
     765           0 :         blendFormula = get_lcd_blend_formula(fBlendMode);
     766             :     } else {
     767             :         blendFormula =
     768           0 :                 get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage,
     769           0 :                                   hasMixedSamples, fBlendMode);
     770             :     }
     771             : 
     772           0 :     if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
     773           0 :         return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode));
     774             :     }
     775           0 :     return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
     776             : }
     777             : 
     778           0 : static inline GrXPFactory::AnalysisProperties analysis_properties(
     779             :         const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage,
     780             :         const GrCaps& caps, SkBlendMode mode) {
     781             :     using AnalysisProperties = GrXPFactory::AnalysisProperties;
     782           0 :     AnalysisProperties props = AnalysisProperties::kNone;
     783           0 :     bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
     784           0 :     auto formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
     785           0 :     if (formula.canTweakAlphaForCoverage()) {
     786           0 :         props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage;
     787             :     }
     788             :     // With dual-source blending we never need the destination color in the shader.
     789           0 :     if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
     790             :         // Mixed samples implicity computes a fractional coverage from sample coverage. This could
     791             :         // affect the formula used. However, we don't expect to have mixed samples without dual
     792             :         // source blending.
     793           0 :         SkASSERT(!caps.usesMixedSamples());
     794           0 :         if (GrProcessorAnalysisCoverage::kLCD == coverage) {
     795             :             // Check for special case of srcover with a known color which can be done using the
     796             :             // blend constant.
     797           0 :             if (SkBlendMode::kSrcOver == mode && color.isConstant()) {
     798           0 :                 props |= AnalysisProperties::kIgnoresInputColor;
     799             :             } else {
     800           0 :                 if (get_lcd_blend_formula(mode).hasSecondaryOutput()) {
     801           0 :                     props |= AnalysisProperties::kReadsDstInShader;
     802             :                 }
     803             :             }
     804           0 :         } else if (formula.hasSecondaryOutput()) {
     805           0 :             props |= AnalysisProperties::kReadsDstInShader;
     806             :         }
     807             :     }
     808           0 :     if (!formula.modifiesDst() || !formula.usesInputColor()) {
     809           0 :         props |= AnalysisProperties::kIgnoresInputColor;
     810             :     }
     811             :     // Ignore the effect of coverage here for overlap stencil and cover property
     812           0 :     auto colorFormula = gBlendTable[color.isOpaque()][0][(int)mode];
     813           0 :     SkASSERT(kAdd_GrBlendEquation == colorFormula.equation());
     814           0 :     if (!colorFormula.usesDstColor()) {
     815           0 :         props |= AnalysisProperties::kCanCombineOverlappedStencilAndCover;
     816             :     }
     817           0 :     return props;
     818             : }
     819             : 
     820           0 : GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
     821             :         const GrProcessorAnalysisColor& color,
     822             :         const GrProcessorAnalysisCoverage& coverage,
     823             :         const GrCaps& caps) const {
     824           0 :     return analysis_properties(color, coverage, caps, fBlendMode);
     825             : }
     826             : 
     827             : GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
     828             : 
     829             : #if GR_TEST_UTILS
     830           0 : const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
     831           0 :     SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
     832           0 :     return GrPorterDuffXPFactory::Get(mode);
     833             : }
     834             : #endif
     835             : 
     836           0 : void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
     837             :                                                  int* outPrimary,
     838             :                                                  int* outSecondary) {
     839           0 :     if (!!strcmp(xp->name(), "Porter Duff")) {
     840           0 :         *outPrimary = *outSecondary = -1;
     841           0 :         return;
     842             :     }
     843           0 :     BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
     844           0 :     *outPrimary = blendFormula.primaryOutput();
     845           0 :     *outSecondary = blendFormula.secondaryOutput();
     846             : }
     847             : 
     848             : ////////////////////////////////////////////////////////////////////////////////////////////////
     849             : // SrcOver Global functions
     850             : ////////////////////////////////////////////////////////////////////////////////////////////////
     851           0 : const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
     852             :     static BlendFormula gSrcOverBlendFormula =
     853             :             MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
     854           0 :     static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
     855           0 :     return gSrcOverXP;
     856             : }
     857             : 
     858           0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
     859             :         const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
     860             :         bool hasMixedSamples, const GrCaps& caps) {
     861             :     // We want to not make an xfer processor if possible. Thus for the simple case where we are not
     862             :     // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
     863             :     // the general case where we convert a src-over blend that has solid coverage and an opaque
     864             :     // color to src-mode, which allows disabling of blending.
     865           0 :     if (coverage != GrProcessorAnalysisCoverage::kLCD) {
     866             :         // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
     867             :         // We don't simply return the address of that XP here because our caller would have to unref
     868             :         // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
     869             :         // safe.
     870           0 :         return nullptr;
     871             :     }
     872             : 
     873           0 :     if (color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() &&
     874           0 :         !caps.shaderCaps()->dstReadInShaderSupport()) {
     875             :         // If we don't have dual source blending or in shader dst reads, we fall
     876             :         // back to this trick for rendering SrcOver LCD text instead of doing a
     877             :         // dst copy.
     878           0 :         return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color);
     879             :     }
     880             : 
     881           0 :     BlendFormula blendFormula;
     882           0 :     blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
     883           0 :     if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
     884           0 :         return sk_sp<GrXferProcessor>(
     885           0 :                 new ShaderPDXferProcessor(hasMixedSamples, SkBlendMode::kSrcOver));
     886             :     }
     887           0 :     return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
     888             : }
     889             : 
     890           0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
     891           0 :     BlendFormula formula = get_blend_formula(false, false, false, blendmode);
     892           0 :     return sk_make_sp<PorterDuffXferProcessor>(formula);
     893             : }
     894             : 
     895           0 : GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
     896             :         const GrProcessorAnalysisColor& color,
     897             :         const GrProcessorAnalysisCoverage& coverage,
     898             :         const GrCaps& caps) {
     899           0 :     return analysis_properties(color, coverage, caps, SkBlendMode::kSrcOver);
     900             : }

Generated by: LCOV version 1.13