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 #include "effects/GrCustomXfermodePriv.h"
     10 
     11 #include "GrCoordTransform.h"
     12 #include "GrContext.h"
     13 #include "GrFragmentProcessor.h"
     14 #include "GrInvariantOutput.h"
     15 #include "GrProcessor.h"
     16 #include "GrTexture.h"
     17 #include "GrTextureAccess.h"
     18 #include "SkXfermode.h"
     19 #include "gl/GrGLCaps.h"
     20 #include "gl/GrGLGpu.h"
     21 #include "gl/GrGLProcessor.h"
     22 #include "gl/GrGLProgramDataManager.h"
     23 #include "gl/builders/GrGLProgramBuilder.h"
     24 
     25 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) {
     26     return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
     27 }
     28 
     29 ///////////////////////////////////////////////////////////////////////////////
     30 // Static helpers
     31 ///////////////////////////////////////////////////////////////////////////////
     32 
     33 static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) {
     34     enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode };
     35     return static_cast<GrBlendEquation>(mode + kOffset);
     36 
     37     GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset);
     38     GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset);
     39     GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset);
     40     GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset);
     41     GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset);
     42     GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset);
     43     GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset);
     44     GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset);
     45     GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset);
     46     GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset);
     47     GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset);
     48     GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset);
     49     GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset);
     50     GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset);
     51     GR_STATIC_ASSERT(kGrBlendEquationCnt == SkXfermode::kLastMode + 1 + kOffset);
     52 }
     53 
     54 static void hard_light(GrGLFragmentBuilder* fsBuilder,
     55                        const char* final,
     56                        const char* src,
     57                        const char* dst) {
     58     static const char kComponents[] = {'r', 'g', 'b'};
     59     for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
     60         char component = kComponents[i];
     61         fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
     62         fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
     63                                final, component, src, component, dst, component);
     64         fsBuilder->codeAppend("} else {");
     65         fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
     66                                final, component, src, dst, dst, dst, component, src, src,
     67                                component);
     68         fsBuilder->codeAppend("}");
     69     }
     70     fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
     71                            final, src, dst, dst, src);
     72 }
     73 
     74 // Does one component of color-dodge
     75 static void color_dodge_component(GrGLFragmentBuilder* fsBuilder,
     76                                   const char* final,
     77                                   const char* src,
     78                                   const char* dst,
     79                                   const char component) {
     80     fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
     81     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
     82                            final, component, src, component, dst);
     83     fsBuilder->codeAppend("} else {");
     84     fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
     85     fsBuilder->codeAppend("if (0.0 == d) {");
     86     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     87                            final, component, src, dst, src, component, dst, dst, component,
     88                            src);
     89     fsBuilder->codeAppend("} else {");
     90     fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
     91                            dst, dst, component, src);
     92     fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     93                            final, component, src, src, component, dst, dst, component, src);
     94     fsBuilder->codeAppend("}");
     95     fsBuilder->codeAppend("}");
     96 }
     97 
     98 // Does one component of color-burn
     99 static void color_burn_component(GrGLFragmentBuilder* fsBuilder,
    100                                  const char* final,
    101                                  const char* src,
    102                                  const char* dst,
    103                                  const char component) {
    104     fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
    105     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
    106                            final, component, src, dst, src, component, dst, dst, component,
    107                            src);
    108     fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
    109     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
    110                            final, component, dst, component, src);
    111     fsBuilder->codeAppend("} else {");
    112     fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
    113                            dst, dst, dst, component, src, src, component);
    114     fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
    115                            final, component, src, src, component, dst, dst, component, src);
    116     fsBuilder->codeAppend("}");
    117 }
    118 
    119 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
    120 static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder,
    121                                                const char* final,
    122                                                const char* src,
    123                                                const char* dst,
    124                                                const char component) {
    125     // if (2S < Sa)
    126     fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
    127     // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
    128     fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
    129                                    "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
    130                            final, component, dst, component, dst, component, src, src,
    131                            component, dst, dst, src, component, dst, component, src, src,
    132                            component);
    133     // else if (4D < Da)
    134     fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
    135                            dst, component, dst);
    136     fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
    137                            dst, component, dst, component);
    138     fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
    139     fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
    140     fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
    141     // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
    142     fsBuilder->codeAppendf("%s.%c ="
    143                            "(-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
    144                            " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) /"
    145                            "DaSqd;",
    146                            final, component, src, component, src, component, dst, component,
    147                            src, src, component, dst, src, src, component, src, src,
    148                            component);
    149     fsBuilder->codeAppendf("} else {");
    150     // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
    151     fsBuilder->codeAppendf("%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c +"
    152                                    "%s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;",
    153                            final, component, dst, dst, component, src, src, component, dst,
    154                            src, component, dst, component, src, src, component, src,
    155                            component);
    156     fsBuilder->codeAppendf("}");
    157 }
    158 
    159 // Adds a function that takes two colors and an alpha as input. It produces a color with the
    160 // hue and saturation of the first color, the luminosity of the second color, and the input
    161 // alpha. It has this signature:
    162 //      vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
    163 static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
    164     // Emit a helper that gets the luminance of a color.
    165     SkString getFunction;
    166     GrGLShaderVar getLumArgs[] = {
    167         GrGLShaderVar("color", kVec3f_GrSLType),
    168     };
    169     SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
    170     fsBuilder->emitFunction(kFloat_GrSLType,
    171                             "luminance",
    172                             SK_ARRAY_COUNT(getLumArgs), getLumArgs,
    173                             getLumBody.c_str(),
    174                             &getFunction);
    175 
    176     // Emit the set luminance function.
    177     GrGLShaderVar setLumArgs[] = {
    178         GrGLShaderVar("hueSat", kVec3f_GrSLType),
    179         GrGLShaderVar("alpha", kFloat_GrSLType),
    180         GrGLShaderVar("lumColor", kVec3f_GrSLType),
    181     };
    182     SkString setLumBody;
    183     setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
    184     setLumBody.append("vec3 outColor = hueSat + diff;");
    185     setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
    186     setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
    187                       "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
    188                       "if (minComp < 0.0 && outLum != minComp) {"
    189                       "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
    190                                           "(outLum - minComp);"
    191                       "}"
    192                       "if (maxComp > alpha && maxComp != outLum) {"
    193                       "outColor = outLum +"
    194                                  "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
    195                                  "(maxComp - outLum);"
    196                       "}"
    197                       "return outColor;");
    198     fsBuilder->emitFunction(kVec3f_GrSLType,
    199                             "set_luminance",
    200                             SK_ARRAY_COUNT(setLumArgs), setLumArgs,
    201                             setLumBody.c_str(),
    202                             setLumFunction);
    203 }
    204 
    205 // Adds a function that creates a color with the hue and luminosity of one input color and
    206 // the saturation of another color. It will have this signature:
    207 //      float set_saturation(vec3 hueLumColor, vec3 satColor)
    208 static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
    209     // Emit a helper that gets the saturation of a color
    210     SkString getFunction;
    211     GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
    212     SkString getSatBody;
    213     getSatBody.printf("return max(max(color.r, color.g), color.b) - "
    214                       "min(min(color.r, color.g), color.b);");
    215     fsBuilder->emitFunction(kFloat_GrSLType,
    216                             "saturation",
    217                             SK_ARRAY_COUNT(getSatArgs), getSatArgs,
    218                             getSatBody.c_str(),
    219                             &getFunction);
    220 
    221     // Emit a helper that sets the saturation given sorted input channels. This used
    222     // to use inout params for min, mid, and max components but that seems to cause
    223     // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
    224     // adjusted min, mid, and max inputs, respectively.
    225     SkString helperFunction;
    226     GrGLShaderVar helperArgs[] = {
    227         GrGLShaderVar("minComp", kFloat_GrSLType),
    228         GrGLShaderVar("midComp", kFloat_GrSLType),
    229         GrGLShaderVar("maxComp", kFloat_GrSLType),
    230         GrGLShaderVar("sat", kFloat_GrSLType),
    231     };
    232     static const char kHelperBody[] = "if (minComp < maxComp) {"
    233         "vec3 result;"
    234         "result.r = 0.0;"
    235         "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
    236         "result.b = sat;"
    237         "return result;"
    238         "} else {"
    239         "return vec3(0, 0, 0);"
    240         "}";
    241     fsBuilder->emitFunction(kVec3f_GrSLType,
    242                             "set_saturation_helper",
    243                             SK_ARRAY_COUNT(helperArgs), helperArgs,
    244                             kHelperBody,
    245                             &helperFunction);
    246 
    247     GrGLShaderVar setSatArgs[] = {
    248         GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
    249         GrGLShaderVar("satColor", kVec3f_GrSLType),
    250     };
    251     const char* helpFunc = helperFunction.c_str();
    252     SkString setSatBody;
    253     setSatBody.appendf("float sat = %s(satColor);"
    254                        "if (hueLumColor.r <= hueLumColor.g) {"
    255                        "if (hueLumColor.g <= hueLumColor.b) {"
    256                        "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
    257                        "} else if (hueLumColor.r <= hueLumColor.b) {"
    258                        "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
    259                        "} else {"
    260                        "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
    261                        "}"
    262                        "} else if (hueLumColor.r <= hueLumColor.b) {"
    263                        "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
    264                        "} else if (hueLumColor.g <= hueLumColor.b) {"
    265                        "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
    266                        "} else {"
    267                        "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
    268                        "}"
    269                        "return hueLumColor;",
    270                        getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
    271                        helpFunc, helpFunc);
    272     fsBuilder->emitFunction(kVec3f_GrSLType,
    273                             "set_saturation",
    274                             SK_ARRAY_COUNT(setSatArgs), setSatArgs,
    275                             setSatBody.c_str(),
    276                             setSatFunction);
    277 
    278 }
    279 
    280 static void emit_custom_xfermode_code(SkXfermode::Mode mode,
    281                                       GrGLFragmentBuilder* fsBuilder,
    282                                       const char* outputColor,
    283                                       const char* inputColor,
    284                                       const char* dstColor) {
    285     // We don't try to optimize for this case at all
    286     if (NULL == inputColor) {
    287         fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
    288         inputColor = "ones";
    289     }
    290     fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
    291 
    292     // These all perform src-over on the alpha channel.
    293     fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
    294                            outputColor, inputColor, inputColor, dstColor);
    295 
    296     switch (mode) {
    297         case SkXfermode::kOverlay_Mode:
    298             // Overlay is Hard-Light with the src and dst reversed
    299             hard_light(fsBuilder, outputColor, dstColor, inputColor);
    300             break;
    301         case SkXfermode::kDarken_Mode:
    302             fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
    303                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
    304                                    outputColor,
    305                                    inputColor, dstColor, inputColor,
    306                                    dstColor, inputColor, dstColor);
    307             break;
    308         case SkXfermode::kLighten_Mode:
    309             fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
    310                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
    311                                    outputColor,
    312                                    inputColor, dstColor, inputColor,
    313                                    dstColor, inputColor, dstColor);
    314             break;
    315         case SkXfermode::kColorDodge_Mode:
    316             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
    317             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
    318             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
    319             break;
    320         case SkXfermode::kColorBurn_Mode:
    321             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
    322             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
    323             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
    324             break;
    325         case SkXfermode::kHardLight_Mode:
    326             hard_light(fsBuilder, outputColor, inputColor, dstColor);
    327             break;
    328         case SkXfermode::kSoftLight_Mode:
    329             fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
    330             fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor);
    331             fsBuilder->codeAppendf("} else {");
    332             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
    333             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
    334             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
    335             fsBuilder->codeAppendf("}");
    336             break;
    337         case SkXfermode::kDifference_Mode:
    338             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
    339                                    "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
    340                                    outputColor, inputColor, dstColor, inputColor, dstColor,
    341                                    dstColor, inputColor);
    342             break;
    343         case SkXfermode::kExclusion_Mode:
    344             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
    345                                    "2.0 * %s.rgb * %s.rgb;",
    346                                    outputColor, dstColor, inputColor, dstColor, inputColor);
    347             break;
    348         case SkXfermode::kMultiply_Mode:
    349             fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
    350                                    "(1.0 - %s.a) * %s.rgb + "
    351                                    "%s.rgb * %s.rgb;",
    352                                    outputColor, inputColor, dstColor, dstColor, inputColor,
    353                                    inputColor, dstColor);
    354             break;
    355         case SkXfermode::kHue_Mode: {
    356             //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
    357             SkString setSat, setLum;
    358             add_sat_function(fsBuilder, &setSat);
    359             add_lum_function(fsBuilder, &setLum);
    360             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
    361                                    dstColor, inputColor);
    362             fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
    363                                                "dstSrcAlpha.a, dstSrcAlpha.rgb);",
    364                                    outputColor, setLum.c_str(), setSat.c_str(), inputColor,
    365                                    dstColor);
    366             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    367                                    outputColor, inputColor, dstColor, dstColor, inputColor);
    368             break;
    369         }
    370         case SkXfermode::kSaturation_Mode: {
    371             // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
    372             SkString setSat, setLum;
    373             add_sat_function(fsBuilder, &setSat);
    374             add_lum_function(fsBuilder, &setLum);
    375             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
    376                                    dstColor, inputColor);
    377             fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
    378                                                "dstSrcAlpha.a, dstSrcAlpha.rgb);",
    379                                    outputColor, setLum.c_str(), setSat.c_str(), inputColor,
    380                                    dstColor);
    381             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    382                                    outputColor, inputColor, dstColor, dstColor, inputColor);
    383             break;
    384         }
    385         case SkXfermode::kColor_Mode: {
    386             //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
    387             SkString setLum;
    388             add_lum_function(fsBuilder, &setLum);
    389             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
    390                                    inputColor, dstColor);
    391             fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
    392                                    outputColor, setLum.c_str(), dstColor, inputColor);
    393             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    394                                    outputColor, inputColor, dstColor, dstColor, inputColor);
    395             break;
    396         }
    397         case SkXfermode::kLuminosity_Mode: {
    398             //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
    399             SkString setLum;
    400             add_lum_function(fsBuilder, &setLum);
    401             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
    402                                    inputColor, dstColor);
    403             fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
    404                                    outputColor, setLum.c_str(), dstColor, inputColor);
    405             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    406                                    outputColor, inputColor, dstColor, dstColor, inputColor);
    407             break;
    408         }
    409         default:
    410             SkFAIL("Unknown Custom Xfer mode.");
    411             break;
    412     }
    413 }
    414 
    415 ///////////////////////////////////////////////////////////////////////////////
    416 // Fragment Processor
    417 ///////////////////////////////////////////////////////////////////////////////
    418 
    419 GrFragmentProcessor* GrCustomXfermode::CreateFP(SkXfermode::Mode mode, GrTexture* background) {
    420     if (!GrCustomXfermode::IsSupportedMode(mode)) {
    421         return NULL;
    422     } else {
    423         return SkNEW_ARGS(GrCustomXferFP, (mode, background));
    424     }
    425 }
    426 
    427 ///////////////////////////////////////////////////////////////////////////////
    428 
    429 class GLCustomXferFP : public GrGLFragmentProcessor {
    430 public:
    431     GLCustomXferFP(const GrFragmentProcessor&) {}
    432     ~GLCustomXferFP() override {};
    433 
    434     void emitCode(GrGLFPBuilder* builder,
    435                   const GrFragmentProcessor& fp,
    436                   const char* outputColor,
    437                   const char* inputColor,
    438                   const TransformedCoordsArray& coords,
    439                   const TextureSamplerArray& samplers) override {
    440         SkXfermode::Mode mode = fp.cast<GrCustomXferFP>().mode();
    441         GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
    442         const char* dstColor = "bgColor";
    443         fsBuilder->codeAppendf("vec4 %s = ", dstColor);
    444         fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
    445         fsBuilder->codeAppendf(";");
    446 
    447         emit_custom_xfermode_code(mode, fsBuilder, outputColor, inputColor, dstColor);
    448     }
    449 
    450     void setData(const GrGLProgramDataManager&, const GrProcessor&) override {}
    451 
    452     static void GenKey(const GrFragmentProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
    453         // The background may come from the dst or from a texture.
    454         uint32_t key = proc.numTextures();
    455         SkASSERT(key <= 1);
    456         key |= proc.cast<GrCustomXferFP>().mode() << 1;
    457         b->add32(key);
    458     }
    459 
    460 private:
    461     typedef GrGLFragmentProcessor INHERITED;
    462 };
    463 
    464 ///////////////////////////////////////////////////////////////////////////////
    465 
    466 GrCustomXferFP::GrCustomXferFP(SkXfermode::Mode mode, GrTexture* background)
    467     : fMode(mode) {
    468     this->initClassID<GrCustomXferFP>();
    469 
    470     SkASSERT(background);
    471     fBackgroundTransform.reset(kLocal_GrCoordSet, background,
    472                                GrTextureParams::kNone_FilterMode);
    473     this->addCoordTransform(&fBackgroundTransform);
    474     fBackgroundAccess.reset(background);
    475     this->addTextureAccess(&fBackgroundAccess);
    476 }
    477 
    478 void GrCustomXferFP::getGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
    479     GLCustomXferFP::GenKey(*this, caps, b);
    480 }
    481 
    482 GrGLFragmentProcessor* GrCustomXferFP::createGLInstance() const {
    483     return SkNEW_ARGS(GLCustomXferFP, (*this));
    484 }
    485 
    486 bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const {
    487     const GrCustomXferFP& s = other.cast<GrCustomXferFP>();
    488     return fMode == s.fMode;
    489 }
    490 
    491 void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    492     inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
    493 }
    494 
    495 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP);
    496 GrFragmentProcessor* GrCustomXferFP::TestCreate(SkRandom* rand,
    497                                                 GrContext*,
    498                                                 const GrDrawTargetCaps&,
    499                                                 GrTexture* textures[]) {
    500     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
    501 
    502     return SkNEW_ARGS(GrCustomXferFP, (static_cast<SkXfermode::Mode>(mode), textures[0]));
    503 }
    504 
    505 ///////////////////////////////////////////////////////////////////////////////
    506 // Xfer Processor
    507 ///////////////////////////////////////////////////////////////////////////////
    508 
    509 class CustomXP : public GrXferProcessor {
    510 public:
    511     static GrXferProcessor* Create(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy,
    512                                    bool willReadDstColor) {
    513         if (!GrCustomXfermode::IsSupportedMode(mode)) {
    514             return NULL;
    515         } else {
    516             return SkNEW_ARGS(CustomXP, (mode, dstCopy, willReadDstColor));
    517         }
    518     }
    519 
    520     ~CustomXP() override {};
    521 
    522     const char* name() const override { return "Custom Xfermode"; }
    523 
    524     GrGLXferProcessor* createGLInstance() const override;
    525 
    526     bool hasSecondaryOutput() const override { return false; }
    527 
    528     SkXfermode::Mode mode() const { return fMode; }
    529     bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); }
    530 
    531     GrBlendEquation hwBlendEquation() const {
    532         SkASSERT(this->hasHWBlendEquation());
    533         return fHWBlendEquation;
    534     }
    535 
    536 private:
    537     CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
    538 
    539     GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
    540                                                  const GrProcOptInfo& coveragePOI,
    541                                                  bool doesStencilWrite,
    542                                                  GrColor* overrideColor,
    543                                                  const GrDrawTargetCaps& caps) override;
    544 
    545     void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
    546 
    547     bool onWillNeedXferBarrier(const GrRenderTarget* rt,
    548                                const GrDrawTargetCaps& caps,
    549                                GrXferBarrierType* outBarrierType) const override;
    550 
    551     void onGetBlendInfo(BlendInfo*) const override;
    552 
    553     bool onIsEqual(const GrXferProcessor& xpBase) const override;
    554 
    555     SkXfermode::Mode fMode;
    556     GrBlendEquation  fHWBlendEquation;
    557 
    558     typedef GrXferProcessor INHERITED;
    559 };
    560 
    561 ///////////////////////////////////////////////////////////////////////////////
    562 
    563 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
    564     if (!GrCustomXfermode::IsSupportedMode(mode)) {
    565         return NULL;
    566     } else {
    567         return SkNEW_ARGS(GrCustomXPFactory, (mode));
    568     }
    569 }
    570 
    571 ///////////////////////////////////////////////////////////////////////////////
    572 
    573 class GLCustomXP : public GrGLXferProcessor {
    574 public:
    575     GLCustomXP(const GrXferProcessor&) {}
    576     ~GLCustomXP() override {}
    577 
    578     static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
    579         const CustomXP& xp = p.cast<CustomXP>();
    580         uint32_t key = xp.numTextures();
    581         SkASSERT(key <= 1);
    582         key |= xp.readsCoverage() << 1;
    583         if (xp.hasHWBlendEquation()) {
    584             SkASSERT(caps.advBlendEqInteraction() > 0);  // 0 will mean !xp.hasHWBlendEquation().
    585             key |= caps.advBlendEqInteraction() << 2;
    586         }
    587         if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) {
    588             GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4);
    589             key |= xp.mode() << 4;
    590         }
    591         b->add32(key);
    592     }
    593 
    594 private:
    595     void onEmitCode(const EmitArgs& args) override {
    596         const CustomXP& xp = args.fXP.cast<CustomXP>();
    597         GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
    598 
    599         if (xp.hasHWBlendEquation()) {
    600             // The blend mode will be implemented in hardware; only output the src color.
    601             fsBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation());
    602             if (xp.readsCoverage()) {
    603                 // Do coverage modulation by multiplying it into the src color before blending.
    604                 // (See getOptimizations())
    605                 fsBuilder->codeAppendf("%s = %s * %s;",
    606                                        args.fOutputPrimary, args.fInputCoverage, args.fInputColor);
    607             } else {
    608                 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
    609             }
    610         } else {
    611             const char* dstColor = fsBuilder->dstColor();
    612             emit_custom_xfermode_code(xp.mode(), fsBuilder, args.fOutputPrimary, args.fInputColor,
    613                                       dstColor);
    614             if (xp.readsCoverage()) {
    615                 fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
    616                                        args.fOutputPrimary, args.fOutputPrimary,
    617                                        args.fInputCoverage, args.fInputCoverage, dstColor);
    618             }
    619         }
    620     }
    621 
    622     void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
    623 
    624     typedef GrGLFragmentProcessor INHERITED;
    625 };
    626 
    627 ///////////////////////////////////////////////////////////////////////////////
    628 
    629 CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy,
    630                    bool willReadDstColor)
    631     : INHERITED(dstCopy, willReadDstColor),
    632       fMode(mode),
    633       fHWBlendEquation(static_cast<GrBlendEquation>(-1)) {
    634     this->initClassID<CustomXP>();
    635 }
    636 
    637 void CustomXP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
    638     GLCustomXP::GenKey(*this, caps, b);
    639 }
    640 
    641 GrGLXferProcessor* CustomXP::createGLInstance() const {
    642     SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
    643     return SkNEW_ARGS(GLCustomXP, (*this));
    644 }
    645 
    646 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
    647     const CustomXP& s = other.cast<CustomXP>();
    648     return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
    649 }
    650 
    651 GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrProcOptInfo& colorPOI,
    652                                                        const GrProcOptInfo& coveragePOI,
    653                                                        bool doesStencilWrite,
    654                                                        GrColor* overrideColor,
    655                                                        const GrDrawTargetCaps& caps) {
    656   /*
    657     Most the optimizations we do here are based on tweaking alpha for coverage.
    658 
    659     The general SVG blend equation is defined in the spec as follows:
    660 
    661       Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
    662       Da'  = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
    663 
    664     (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
    665      and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
    666      RGB colors.)
    667 
    668     For every blend mode supported by this class, i.e. the "advanced" blend
    669     modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
    670 
    671     It can be shown that when X=Y=Z=1, these equations can modulate alpha for
    672     coverage.
    673 
    674 
    675     == Color ==
    676 
    677     We substitute Y=Z=1 and define a blend() function that calculates Dca' in
    678     terms of premultiplied alpha only:
    679 
    680       blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
    681                                  Sca : if Da == 0,
    682                                  B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0}
    683 
    684     And for coverage modulation, we use a post blend src-over model:
    685 
    686       Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    687 
    688     (Where f is the fractional coverage.)
    689 
    690     Next we show that canTweakAlphaForCoverage() is true by proving the
    691     following relationship:
    692 
    693       blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    694 
    695     General case (f,Sa,Da != 0):
    696 
    697       f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    698         = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca  [Sa,Da != 0, definition of blend()]
    699         = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
    700         = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
    701         = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
    702         = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
    703         = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
    704         = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)  [f!=0]
    705         = blend(f*Sca, Dca, f*Sa, Da)  [definition of blend()]
    706 
    707     Corner cases (Sa=0, Da=0, and f=0):
    708 
    709       Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    710               = f * Dca + (1-f) * Dca  [Sa=0, definition of blend()]
    711               = Dca
    712               = blend(0, Dca, 0, Da)  [definition of blend()]
    713               = blend(f*Sca, Dca, f*Sa, Da)  [Sa=0]
    714 
    715       Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    716               = f * Sca + (1-f) * Dca  [Da=0, definition of blend()]
    717               = f * Sca  [Da=0]
    718               = blend(f*Sca, 0, f*Sa, 0)  [definition of blend()]
    719               = blend(f*Sca, Dca, f*Sa, Da)  [Da=0]
    720 
    721       f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
    722              = Dca  [f=0]
    723              = blend(0, Dca, 0, Da)  [definition of blend()]
    724              = blend(f*Sca, Dca, f*Sa, Da)  [f=0]
    725 
    726     == Alpha ==
    727 
    728     We substitute X=Y=Z=1 and define a blend() function that calculates Da':
    729 
    730       blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
    731                     = Sa * Da + Sa - Sa * Da + Da - Da * Sa
    732                     = Sa + Da - Sa * Da
    733 
    734     We use the same model for coverage modulation as we did with color:
    735 
    736       Da'' = f * blend(Sa, Da) + (1-f) * Da
    737 
    738     And show that canTweakAlphaForCoverage() is true by proving the following
    739     relationship:
    740 
    741       blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
    742 
    743 
    744       f * blend(Sa, Da) + (1-f) * Da
    745         = f * (Sa + Da - Sa * Da) + (1-f) * Da
    746         = f*Sa + f*Da - f*Sa * Da + Da - f*Da
    747         = f*Sa - f*Sa * Da + Da
    748         = f*Sa + Da - f*Sa * Da
    749         = blend(f*Sa, Da)
    750    */
    751 
    752     OptFlags flags = kNone_Opt;
    753     if (colorPOI.allStagesMultiplyInput()) {
    754         flags |= kCanTweakAlphaForCoverage_OptFlag;
    755     }
    756     if (coveragePOI.isSolidWhite()) {
    757         flags |= kIgnoreCoverage_OptFlag;
    758     }
    759     if (caps.advancedBlendEquationSupport() && !coveragePOI.isFourChannelOutput()) {
    760         // This blend mode can be implemented in hardware.
    761         fHWBlendEquation = hw_blend_equation(fMode);
    762     }
    763     return flags;
    764 }
    765 
    766 bool CustomXP::onWillNeedXferBarrier(const GrRenderTarget* rt,
    767                                      const GrDrawTargetCaps& caps,
    768                                      GrXferBarrierType* outBarrierType) const {
    769     if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
    770         *outBarrierType = kBlend_GrXferBarrierType;
    771         return true;
    772     }
    773     return false;
    774 }
    775 
    776 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
    777     if (this->hasHWBlendEquation()) {
    778         blendInfo->fEquation = this->hwBlendEquation();
    779     }
    780 }
    781 
    782 ///////////////////////////////////////////////////////////////////////////////
    783 
    784 GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode)
    785     : fMode(mode) {
    786     this->initClassID<GrCustomXPFactory>();
    787 }
    788 
    789 GrXferProcessor*
    790 GrCustomXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
    791                                          const GrProcOptInfo& colorPOI,
    792                                          const GrProcOptInfo& coveragePOI,
    793                                          const GrDeviceCoordTexture* dstCopy) const {
    794     return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(caps, colorPOI, coveragePOI));
    795 }
    796 
    797 bool GrCustomXPFactory::willReadDstColor(const GrDrawTargetCaps& caps,
    798                                          const GrProcOptInfo& colorPOI,
    799                                          const GrProcOptInfo& coveragePOI) const {
    800     if (!caps.advancedBlendEquationSupport()) {
    801         // No hardware support for advanced blend equations; we will need to do it in the shader.
    802         return true;
    803     }
    804     if (coveragePOI.isFourChannelOutput()) {
    805         // Advanced blend equations can't tweak alpha for RGB coverage.
    806         return true;
    807     }
    808     return false;
    809 }
    810 
    811 void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
    812                                                const GrProcOptInfo& coveragePOI,
    813                                                GrXPFactory::InvariantOutput* output) const {
    814     output->fWillBlendWithDst = true;
    815     output->fBlendedColorFlags = 0;
    816 }
    817 
    818 GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory);
    819 GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand,
    820                                            GrContext*,
    821                                            const GrDrawTargetCaps&,
    822                                            GrTexture*[]) {
    823     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
    824 
    825     return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode)));
    826 }
    827 
    828