Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2015 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/GrCustomXfermode.h"
      9 
     10 #include "GrCaps.h"
     11 #include "GrCoordTransform.h"
     12 #include "GrFragmentProcessor.h"
     13 #include "GrPipeline.h"
     14 #include "GrProcessor.h"
     15 #include "GrShaderCaps.h"
     16 #include "glsl/GrGLSLBlend.h"
     17 #include "glsl/GrGLSLFragmentProcessor.h"
     18 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     19 #include "glsl/GrGLSLProgramDataManager.h"
     20 #include "glsl/GrGLSLUniformHandler.h"
     21 #include "glsl/GrGLSLXferProcessor.h"
     22 
     23 bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) {
     24     return (int)mode  > (int)SkBlendMode::kLastCoeffMode &&
     25            (int)mode <= (int)SkBlendMode::kLastMode;
     26 }
     27 
     28 ///////////////////////////////////////////////////////////////////////////////
     29 // Static helpers
     30 ///////////////////////////////////////////////////////////////////////////////
     31 
     32 static constexpr GrBlendEquation hw_blend_equation(SkBlendMode mode) {
     33 // In C++14 this could be a constexpr int variable.
     34 #define EQ_OFFSET (kOverlay_GrBlendEquation - (int)SkBlendMode::kOverlay)
     35     GR_STATIC_ASSERT(kOverlay_GrBlendEquation == (int)SkBlendMode::kOverlay + EQ_OFFSET);
     36     GR_STATIC_ASSERT(kDarken_GrBlendEquation == (int)SkBlendMode::kDarken + EQ_OFFSET);
     37     GR_STATIC_ASSERT(kLighten_GrBlendEquation == (int)SkBlendMode::kLighten + EQ_OFFSET);
     38     GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == (int)SkBlendMode::kColorDodge + EQ_OFFSET);
     39     GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == (int)SkBlendMode::kColorBurn + EQ_OFFSET);
     40     GR_STATIC_ASSERT(kHardLight_GrBlendEquation == (int)SkBlendMode::kHardLight + EQ_OFFSET);
     41     GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == (int)SkBlendMode::kSoftLight + EQ_OFFSET);
     42     GR_STATIC_ASSERT(kDifference_GrBlendEquation == (int)SkBlendMode::kDifference + EQ_OFFSET);
     43     GR_STATIC_ASSERT(kExclusion_GrBlendEquation == (int)SkBlendMode::kExclusion + EQ_OFFSET);
     44     GR_STATIC_ASSERT(kMultiply_GrBlendEquation == (int)SkBlendMode::kMultiply + EQ_OFFSET);
     45     GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == (int)SkBlendMode::kHue + EQ_OFFSET);
     46     GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == (int)SkBlendMode::kSaturation + EQ_OFFSET);
     47     GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == (int)SkBlendMode::kColor + EQ_OFFSET);
     48     GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == (int)SkBlendMode::kLuminosity + EQ_OFFSET);
     49     GR_STATIC_ASSERT(kGrBlendEquationCnt == (int)SkBlendMode::kLastMode + 1 + EQ_OFFSET);
     50     return static_cast<GrBlendEquation>((int)mode + EQ_OFFSET);
     51 #undef EQ_OFFSET
     52 }
     53 
     54 static bool can_use_hw_blend_equation(GrBlendEquation equation,
     55                                       GrProcessorAnalysisCoverage coverage, const GrCaps& caps) {
     56     if (!caps.advancedBlendEquationSupport()) {
     57         return false;
     58     }
     59     if (GrProcessorAnalysisCoverage::kLCD == coverage) {
     60         return false; // LCD coverage must be applied after the blend equation.
     61     }
     62     if (caps.canUseAdvancedBlendEquation(equation)) {
     63         return false;
     64     }
     65     return true;
     66 }
     67 
     68 ///////////////////////////////////////////////////////////////////////////////
     69 // Xfer Processor
     70 ///////////////////////////////////////////////////////////////////////////////
     71 
     72 class CustomXP : public GrXferProcessor {
     73 public:
     74     CustomXP(SkBlendMode mode, GrBlendEquation hwBlendEquation)
     75         : fMode(mode)
     76         , fHWBlendEquation(hwBlendEquation) {
     77         this->initClassID<CustomXP>();
     78     }
     79 
     80     CustomXP(bool hasMixedSamples, SkBlendMode mode, GrProcessorAnalysisCoverage coverage)
     81             : INHERITED(true, hasMixedSamples, coverage)
     82             , fMode(mode)
     83             , fHWBlendEquation(static_cast<GrBlendEquation>(-1)) {
     84         this->initClassID<CustomXP>();
     85     }
     86 
     87     const char* name() const override { return "Custom Xfermode"; }
     88 
     89     GrGLSLXferProcessor* createGLSLInstance() const override;
     90 
     91     SkBlendMode mode() const { return fMode; }
     92     bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); }
     93 
     94     GrBlendEquation hwBlendEquation() const {
     95         SkASSERT(this->hasHWBlendEquation());
     96         return fHWBlendEquation;
     97     }
     98 
     99     GrXferBarrierType xferBarrierType(const GrCaps&) const override;
    100 
    101 private:
    102     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
    103 
    104     void onGetBlendInfo(BlendInfo*) const override;
    105 
    106     bool onIsEqual(const GrXferProcessor& xpBase) const override;
    107 
    108     const SkBlendMode      fMode;
    109     const GrBlendEquation  fHWBlendEquation;
    110 
    111     typedef GrXferProcessor INHERITED;
    112 };
    113 
    114 ///////////////////////////////////////////////////////////////////////////////
    115 
    116 class GLCustomXP : public GrGLSLXferProcessor {
    117 public:
    118     GLCustomXP(const GrXferProcessor&) {}
    119     ~GLCustomXP() override {}
    120 
    121     static void GenKey(const GrXferProcessor& p, const GrShaderCaps& caps,
    122                        GrProcessorKeyBuilder* b) {
    123         const CustomXP& xp = p.cast<CustomXP>();
    124         uint32_t key = 0;
    125         if (xp.hasHWBlendEquation()) {
    126             SkASSERT(caps.advBlendEqInteraction() > 0);  // 0 will mean !xp.hasHWBlendEquation().
    127             key |= caps.advBlendEqInteraction();
    128             GR_STATIC_ASSERT(GrShaderCaps::kLast_AdvBlendEqInteraction < 4);
    129         }
    130         if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) {
    131             key |= (int)xp.mode() << 3;
    132         }
    133         b->add32(key);
    134     }
    135 
    136 private:
    137     void emitOutputsForBlendState(const EmitArgs& args) override {
    138         const CustomXP& xp = args.fXP.cast<CustomXP>();
    139         SkASSERT(xp.hasHWBlendEquation());
    140 
    141         GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
    142         fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation());
    143 
    144         // Apply coverage by multiplying it into the src color before blending. Mixed samples will
    145         // "just work" automatically. (See onGetOptimizations())
    146         fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputCoverage,
    147                                  args.fInputColor);
    148     }
    149 
    150     void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
    151                                  GrGLSLUniformHandler* uniformHandler,
    152                                  const char* srcColor,
    153                                  const char* srcCoverage,
    154                                  const char* dstColor,
    155                                  const char* outColor,
    156                                  const char* outColorSecondary,
    157                                  const GrXferProcessor& proc) override {
    158         const CustomXP& xp = proc.cast<CustomXP>();
    159         SkASSERT(!xp.hasHWBlendEquation());
    160 
    161         GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.mode());
    162 
    163         // Apply coverage.
    164         INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
    165                                              outColorSecondary, xp);
    166     }
    167 
    168     void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
    169 
    170     typedef GrGLSLXferProcessor INHERITED;
    171 };
    172 
    173 ///////////////////////////////////////////////////////////////////////////////
    174 
    175 void CustomXP::onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
    176     GLCustomXP::GenKey(*this, caps, b);
    177 }
    178 
    179 GrGLSLXferProcessor* CustomXP::createGLSLInstance() const {
    180     SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
    181     return new GLCustomXP(*this);
    182 }
    183 
    184 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
    185     const CustomXP& s = other.cast<CustomXP>();
    186     return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
    187 }
    188 
    189 GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const {
    190     if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
    191         return kBlend_GrXferBarrierType;
    192     }
    193     return kNone_GrXferBarrierType;
    194 }
    195 
    196 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
    197     if (this->hasHWBlendEquation()) {
    198         blendInfo->fEquation = this->hwBlendEquation();
    199     }
    200 }
    201 
    202 ///////////////////////////////////////////////////////////////////////////////
    203 
    204 // See the comment above GrXPFactory's definition about this warning suppression.
    205 #if defined(__GNUC__) || defined(__clang)
    206 #pragma GCC diagnostic push
    207 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
    208 #endif
    209 class CustomXPFactory : public GrXPFactory {
    210 public:
    211     constexpr CustomXPFactory(SkBlendMode mode)
    212             : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
    213 
    214 private:
    215     sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
    216                                                    GrProcessorAnalysisCoverage,
    217                                                    bool hasMixedSamples,
    218                                                    const GrCaps&) const override;
    219 
    220     AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
    221                                           const GrProcessorAnalysisCoverage&,
    222                                           const GrCaps&) const override;
    223 
    224     GR_DECLARE_XP_FACTORY_TEST
    225 
    226     SkBlendMode fMode;
    227     GrBlendEquation fHWBlendEquation;
    228 
    229     typedef GrXPFactory INHERITED;
    230 };
    231 #if defined(__GNUC__) || defined(__clang)
    232 #pragma GCC diagnostic pop
    233 #endif
    234 
    235 sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor(
    236         const GrProcessorAnalysisColor&,
    237         GrProcessorAnalysisCoverage coverage,
    238         bool hasMixedSamples,
    239         const GrCaps& caps) const {
    240     SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
    241     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
    242         return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));
    243     }
    244     return sk_sp<GrXferProcessor>(new CustomXP(hasMixedSamples, fMode, coverage));
    245 }
    246 
    247 GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
    248         const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage,
    249         const GrCaps& caps) const {
    250     /*
    251       The general SVG blend equation is defined in the spec as follows:
    252 
    253         Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
    254         Da'  = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
    255 
    256       (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
    257        and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
    258        RGB colors.)
    259 
    260       For every blend mode supported by this class, i.e. the "advanced" blend
    261       modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
    262 
    263       It can be shown that when X=Y=Z=1, these equations can modulate alpha for
    264       coverage.
    265 
    266 
    267       == Color ==
    268 
    269       We substitute Y=Z=1 and define a blend() function that calculates Dca' in
    270       terms of premultiplied alpha only:
    271 
    272         blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
    273                                    Sca : if Da == 0,
    274                                    B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if
    275       Sa,Da != 0}
    276 
    277       And for coverage modulation, we use a post blend src-over model:
    278 
    279         Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    280 
    281       (Where f is the fractional coverage.)
    282 
    283       Next we show that canTweakAlphaForCoverage() is true by proving the
    284       following relationship:
    285 
    286         blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    287 
    288       General case (f,Sa,Da != 0):
    289 
    290         f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    291           = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca  [Sa,Da !=
    292       0, definition of blend()]
    293           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
    294           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
    295           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
    296           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
    297           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
    298           = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)  [f!=0]
    299           = blend(f*Sca, Dca, f*Sa, Da)  [definition of blend()]
    300 
    301       Corner cases (Sa=0, Da=0, and f=0):
    302 
    303         Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    304                 = f * Dca + (1-f) * Dca  [Sa=0, definition of blend()]
    305                 = Dca
    306                 = blend(0, Dca, 0, Da)  [definition of blend()]
    307                 = blend(f*Sca, Dca, f*Sa, Da)  [Sa=0]
    308 
    309         Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    310                 = f * Sca + (1-f) * Dca  [Da=0, definition of blend()]
    311                 = f * Sca  [Da=0]
    312                 = blend(f*Sca, 0, f*Sa, 0)  [definition of blend()]
    313                 = blend(f*Sca, Dca, f*Sa, Da)  [Da=0]
    314 
    315         f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    316                = Dca  [f=0]
    317                = blend(0, Dca, 0, Da)  [definition of blend()]
    318                = blend(f*Sca, Dca, f*Sa, Da)  [f=0]
    319 
    320       == Alpha ==
    321 
    322       We substitute X=Y=Z=1 and define a blend() function that calculates Da':
    323 
    324         blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
    325                       = Sa * Da + Sa - Sa * Da + Da - Da * Sa
    326                       = Sa + Da - Sa * Da
    327 
    328       We use the same model for coverage modulation as we did with color:
    329 
    330         Da'' = f * blend(Sa, Da) + (1-f) * Da
    331 
    332       And show that canTweakAlphaForCoverage() is true by proving the following
    333       relationship:
    334 
    335         blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
    336 
    337 
    338         f * blend(Sa, Da) + (1-f) * Da
    339           = f * (Sa + Da - Sa * Da) + (1-f) * Da
    340           = f*Sa + f*Da - f*Sa * Da + Da - f*Da
    341           = f*Sa - f*Sa * Da + Da
    342           = f*Sa + Da - f*Sa * Da
    343           = blend(f*Sa, Da)
    344     */
    345     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
    346         if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) {
    347             return AnalysisProperties::kCompatibleWithAlphaAsCoverage;
    348         } else {
    349             return AnalysisProperties::kCompatibleWithAlphaAsCoverage |
    350                    AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws;
    351         }
    352     }
    353     return AnalysisProperties::kCompatibleWithAlphaAsCoverage |
    354            AnalysisProperties::kReadsDstInShader;
    355 }
    356 
    357 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
    358 #if GR_TEST_UTILS
    359 const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) {
    360     int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1,
    361                                       (int)SkBlendMode::kLastSeparableMode);
    362 
    363     return GrCustomXfermode::Get((SkBlendMode)mode);
    364 }
    365 #endif
    366 
    367 ///////////////////////////////////////////////////////////////////////////////
    368 
    369 const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) {
    370     // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are
    371     // null.
    372 #ifdef SK_BUILD_FOR_WIN
    373 #define _CONSTEXPR_
    374 #else
    375 #define _CONSTEXPR_ constexpr
    376 #endif
    377     static _CONSTEXPR_ const CustomXPFactory gOverlay(SkBlendMode::kOverlay);
    378     static _CONSTEXPR_ const CustomXPFactory gDarken(SkBlendMode::kDarken);
    379     static _CONSTEXPR_ const CustomXPFactory gLighten(SkBlendMode::kLighten);
    380     static _CONSTEXPR_ const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge);
    381     static _CONSTEXPR_ const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn);
    382     static _CONSTEXPR_ const CustomXPFactory gHardLight(SkBlendMode::kHardLight);
    383     static _CONSTEXPR_ const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight);
    384     static _CONSTEXPR_ const CustomXPFactory gDifference(SkBlendMode::kDifference);
    385     static _CONSTEXPR_ const CustomXPFactory gExclusion(SkBlendMode::kExclusion);
    386     static _CONSTEXPR_ const CustomXPFactory gMultiply(SkBlendMode::kMultiply);
    387     static _CONSTEXPR_ const CustomXPFactory gHue(SkBlendMode::kHue);
    388     static _CONSTEXPR_ const CustomXPFactory gSaturation(SkBlendMode::kSaturation);
    389     static _CONSTEXPR_ const CustomXPFactory gColor(SkBlendMode::kColor);
    390     static _CONSTEXPR_ const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity);
    391 #undef _CONSTEXPR_
    392     switch (mode) {
    393         case SkBlendMode::kOverlay:
    394             return &gOverlay;
    395         case SkBlendMode::kDarken:
    396             return &gDarken;
    397         case SkBlendMode::kLighten:
    398             return &gLighten;
    399         case SkBlendMode::kColorDodge:
    400             return &gColorDodge;
    401         case SkBlendMode::kColorBurn:
    402             return &gColorBurn;
    403         case SkBlendMode::kHardLight:
    404             return &gHardLight;
    405         case SkBlendMode::kSoftLight:
    406             return &gSoftLight;
    407         case SkBlendMode::kDifference:
    408             return &gDifference;
    409         case SkBlendMode::kExclusion:
    410             return &gExclusion;
    411         case SkBlendMode::kMultiply:
    412             return &gMultiply;
    413         case SkBlendMode::kHue:
    414             return &gHue;
    415         case SkBlendMode::kSaturation:
    416             return &gSaturation;
    417         case SkBlendMode::kColor:
    418             return &gColor;
    419         case SkBlendMode::kLuminosity:
    420             return &gLuminosity;
    421         default:
    422             SkASSERT(!GrCustomXfermode::IsSupportedMode(mode));
    423             return nullptr;
    424     }
    425 }
    426