Home | History | Annotate | Download | only in glsl
      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 "GrGLSLBlend.h"
      9 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     10 #include "SkBlendModePriv.h"
     11 
     12 //////////////////////////////////////////////////////////////////////////////
     13 //  Advanced (non-coeff) blend helpers
     14 //////////////////////////////////////////////////////////////////////////////
     15 
     16 static void hard_light(GrGLSLFragmentBuilder* fsBuilder,
     17                        const char* final,
     18                        const char* src,
     19                        const char* dst) {
     20     static const char kComponents[] = { 'r', 'g', 'b' };
     21     for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
     22         char component = kComponents[i];
     23         fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
     24         fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
     25                                final, component, src, component, dst, component);
     26         fsBuilder->codeAppend("} else {");
     27         fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
     28                                final, component, src, dst, dst, dst, component, src, src,
     29                                component);
     30         fsBuilder->codeAppend("}");
     31     }
     32     fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
     33                            final, src, dst, dst, src);
     34 }
     35 
     36 // Does one component of color-dodge
     37 static void color_dodge_component(GrGLSLFragmentBuilder* fsBuilder,
     38                                   const char* final,
     39                                   const char* src,
     40                                   const char* dst,
     41                                   const char component) {
     42     fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
     43     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
     44                            final, component, src, component, dst);
     45     fsBuilder->codeAppend("} else {");
     46     fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
     47     fsBuilder->codeAppend("if (0.0 == d) {");
     48     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     49                            final, component, src, dst, src, component, dst, dst, component,
     50                            src);
     51     fsBuilder->codeAppend("} else {");
     52     fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
     53                            dst, dst, component, src);
     54     fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     55                            final, component, src, src, component, dst, dst, component, src);
     56     fsBuilder->codeAppend("}");
     57     fsBuilder->codeAppend("}");
     58 }
     59 
     60 // Does one component of color-burn
     61 static void color_burn_component(GrGLSLFragmentBuilder* fsBuilder,
     62                                  const char* final,
     63                                  const char* src,
     64                                  const char* dst,
     65                                  const char component) {
     66     fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
     67     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     68                            final, component, src, dst, src, component, dst, dst, component,
     69                            src);
     70     fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
     71     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
     72                            final, component, dst, component, src);
     73     fsBuilder->codeAppend("} else {");
     74     fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
     75                            dst, dst, dst, component, src, src, component);
     76     fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
     77                            final, component, src, src, component, dst, dst, component, src);
     78     fsBuilder->codeAppend("}");
     79 }
     80 
     81 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
     82 static void soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder* fsBuilder,
     83                                                const char* final,
     84                                                const char* src,
     85                                                const char* dst,
     86                                                const char component) {
     87     // if (2S < Sa)
     88     fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
     89     // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
     90     fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
     91                            "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
     92                            final, component, dst, component, dst, component, src, src,
     93                            component, dst, dst, src, component, dst, component, src, src,
     94                            component);
     95     // else if (4D < Da)
     96     fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
     97                            dst, component, dst);
     98     fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
     99                            dst, component, dst, component);
    100     fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
    101     fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
    102     fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
    103     // (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
    104     fsBuilder->codeAppendf("%s.%c ="
    105                            "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
    106                            " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
    107                            " DaCub*%s.%c) / DaSqd;",
    108                            final, component, src, component, dst, component,
    109                            src, src, component, dst, src, src, component, src, src,
    110                            component, src, component);
    111     fsBuilder->codeAppendf("} else {");
    112     // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
    113     fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
    114                            " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
    115                            final, component, dst, component, src, src, component, src, component,
    116                            dst, dst, component, src, src, component, dst, src, component);
    117     fsBuilder->codeAppendf("}");
    118 }
    119 
    120 // Adds a function that takes two colors and an alpha as input. It produces a color with the
    121 // hue and saturation of the first color, the luminosity of the second color, and the input
    122 // alpha. It has this signature:
    123 //      vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
    124 static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
    125     // Emit a helper that gets the luminance of a color.
    126     SkString getFunction;
    127     GrShaderVar getLumArgs[] = {
    128         GrShaderVar("color", kVec3f_GrSLType),
    129     };
    130     SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
    131     fsBuilder->emitFunction(kFloat_GrSLType,
    132                             "luminance",
    133                             SK_ARRAY_COUNT(getLumArgs), getLumArgs,
    134                             getLumBody.c_str(),
    135                             &getFunction);
    136 
    137     // Emit the set luminance function.
    138     GrShaderVar setLumArgs[] = {
    139         GrShaderVar("hueSat", kVec3f_GrSLType),
    140         GrShaderVar("alpha", kFloat_GrSLType),
    141         GrShaderVar("lumColor", kVec3f_GrSLType),
    142     };
    143     SkString setLumBody;
    144     setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
    145     setLumBody.append("vec3 outColor = hueSat + diff;");
    146     setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
    147     setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
    148                       "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
    149                       "if (minComp < 0.0 && outLum != minComp) {"
    150                       "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
    151                       "(outLum - minComp);"
    152                       "}"
    153                       "if (maxComp > alpha && maxComp != outLum) {"
    154                       "outColor = outLum +"
    155                       "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
    156                       "(maxComp - outLum);"
    157                       "}"
    158                       "return outColor;");
    159     fsBuilder->emitFunction(kVec3f_GrSLType,
    160                             "set_luminance",
    161                             SK_ARRAY_COUNT(setLumArgs), setLumArgs,
    162                             setLumBody.c_str(),
    163                             setLumFunction);
    164 }
    165 
    166 // Adds a function that creates a color with the hue and luminosity of one input color and
    167 // the saturation of another color. It will have this signature:
    168 //      float set_saturation(vec3 hueLumColor, vec3 satColor)
    169 static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
    170     // Emit a helper that gets the saturation of a color
    171     SkString getFunction;
    172     GrShaderVar getSatArgs[] = { GrShaderVar("color", kVec3f_GrSLType) };
    173     SkString getSatBody;
    174     getSatBody.printf("return max(max(color.r, color.g), color.b) - "
    175                       "min(min(color.r, color.g), color.b);");
    176     fsBuilder->emitFunction(kFloat_GrSLType,
    177                             "saturation",
    178                             SK_ARRAY_COUNT(getSatArgs), getSatArgs,
    179                             getSatBody.c_str(),
    180                             &getFunction);
    181 
    182     // Emit a helper that sets the saturation given sorted input channels. This used
    183     // to use inout params for min, mid, and max components but that seems to cause
    184     // problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
    185     // adjusted min, mid, and max inputs, respectively.
    186     SkString helperFunction;
    187     GrShaderVar helperArgs[] = {
    188         GrShaderVar("minComp", kFloat_GrSLType),
    189         GrShaderVar("midComp", kFloat_GrSLType),
    190         GrShaderVar("maxComp", kFloat_GrSLType),
    191         GrShaderVar("sat", kFloat_GrSLType),
    192     };
    193     static const char kHelperBody[] = "if (minComp < maxComp) {"
    194         "vec3 result;"
    195         "result.r = 0.0;"
    196         "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
    197         "result.b = sat;"
    198         "return result;"
    199         "} else {"
    200         "return vec3(0, 0, 0);"
    201         "}";
    202     fsBuilder->emitFunction(kVec3f_GrSLType,
    203                             "set_saturation_helper",
    204                             SK_ARRAY_COUNT(helperArgs), helperArgs,
    205                             kHelperBody,
    206                             &helperFunction);
    207 
    208     GrShaderVar setSatArgs[] = {
    209         GrShaderVar("hueLumColor", kVec3f_GrSLType),
    210         GrShaderVar("satColor", kVec3f_GrSLType),
    211     };
    212     const char* helpFunc = helperFunction.c_str();
    213     SkString setSatBody;
    214     setSatBody.appendf("float sat = %s(satColor);"
    215                        "if (hueLumColor.r <= hueLumColor.g) {"
    216                        "if (hueLumColor.g <= hueLumColor.b) {"
    217                        "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
    218                        "} else if (hueLumColor.r <= hueLumColor.b) {"
    219                        "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
    220                        "} else {"
    221                        "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
    222                        "}"
    223                        "} else if (hueLumColor.r <= hueLumColor.b) {"
    224                        "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
    225                        "} else if (hueLumColor.g <= hueLumColor.b) {"
    226                        "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
    227                        "} else {"
    228                        "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
    229                        "}"
    230                        "return hueLumColor;",
    231                        getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
    232                        helpFunc, helpFunc);
    233     fsBuilder->emitFunction(kVec3f_GrSLType,
    234                             "set_saturation",
    235                             SK_ARRAY_COUNT(setSatArgs), setSatArgs,
    236                             setSatBody.c_str(),
    237                             setSatFunction);
    238 }
    239 
    240 static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
    241                                         const char* dstColor, const char* outputColor,
    242                                         SkBlendMode mode) {
    243     SkASSERT(srcColor);
    244     SkASSERT(dstColor);
    245     SkASSERT(outputColor);
    246     // These all perform src-over on the alpha channel.
    247     fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
    248                            outputColor, srcColor, srcColor, dstColor);
    249 
    250     switch (mode) {
    251         case SkBlendMode::kOverlay:
    252             // Overlay is Hard-Light with the src and dst reversed
    253             hard_light(fsBuilder, outputColor, dstColor, srcColor);
    254             break;
    255         case SkBlendMode::kDarken:
    256             fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
    257                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
    258                                    outputColor,
    259                                    srcColor, dstColor, srcColor,
    260                                    dstColor, srcColor, dstColor);
    261             break;
    262         case SkBlendMode::kLighten:
    263             fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
    264                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
    265                                    outputColor,
    266                                    srcColor, dstColor, srcColor,
    267                                    dstColor, srcColor, dstColor);
    268             break;
    269         case SkBlendMode::kColorDodge:
    270             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
    271             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
    272             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
    273             break;
    274         case SkBlendMode::kColorBurn:
    275             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
    276             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
    277             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
    278             break;
    279         case SkBlendMode::kHardLight:
    280             hard_light(fsBuilder, outputColor, srcColor, dstColor);
    281             break;
    282         case SkBlendMode::kSoftLight:
    283             fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
    284             fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor);
    285             fsBuilder->codeAppendf("} else {");
    286             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r');
    287             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g');
    288             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b');
    289             fsBuilder->codeAppendf("}");
    290             break;
    291         case SkBlendMode::kDifference:
    292             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
    293                                    "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
    294                                    outputColor, srcColor, dstColor, srcColor, dstColor,
    295                                    dstColor, srcColor);
    296             break;
    297         case SkBlendMode::kExclusion:
    298             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
    299                                    "2.0 * %s.rgb * %s.rgb;",
    300                                    outputColor, dstColor, srcColor, dstColor, srcColor);
    301             break;
    302         case SkBlendMode::kMultiply:
    303             fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
    304                                    "(1.0 - %s.a) * %s.rgb + "
    305                                    "%s.rgb * %s.rgb;",
    306                                    outputColor, srcColor, dstColor, dstColor, srcColor,
    307                                    srcColor, dstColor);
    308             break;
    309         case SkBlendMode::kHue: {
    310             //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
    311             SkString setSat, setLum;
    312             add_sat_function(fsBuilder, &setSat);
    313             add_lum_function(fsBuilder, &setLum);
    314             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
    315                                    dstColor, srcColor);
    316             fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
    317                                    "dstSrcAlpha.a, dstSrcAlpha.rgb);",
    318                                    outputColor, setLum.c_str(), setSat.c_str(), srcColor,
    319                                    dstColor);
    320             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    321                                    outputColor, srcColor, dstColor, dstColor, srcColor);
    322             break;
    323         }
    324         case SkBlendMode::kSaturation: {
    325             // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
    326             SkString setSat, setLum;
    327             add_sat_function(fsBuilder, &setSat);
    328             add_lum_function(fsBuilder, &setLum);
    329             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
    330                                    dstColor, srcColor);
    331             fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
    332                                    "dstSrcAlpha.a, dstSrcAlpha.rgb);",
    333                                    outputColor, setLum.c_str(), setSat.c_str(), srcColor,
    334                                    dstColor);
    335             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    336                                    outputColor, srcColor, dstColor, dstColor, srcColor);
    337             break;
    338         }
    339         case SkBlendMode::kColor: {
    340             //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
    341             SkString setLum;
    342             add_lum_function(fsBuilder, &setLum);
    343             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
    344                                    srcColor, dstColor);
    345             fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
    346                                    outputColor, setLum.c_str(), dstColor, srcColor);
    347             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    348                                    outputColor, srcColor, dstColor, dstColor, srcColor);
    349             break;
    350         }
    351         case SkBlendMode::kLuminosity: {
    352             //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
    353             SkString setLum;
    354             add_lum_function(fsBuilder, &setLum);
    355             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
    356                                    srcColor, dstColor);
    357             fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
    358                                    outputColor, setLum.c_str(), dstColor, srcColor);
    359             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
    360                                    outputColor, srcColor, dstColor, dstColor, srcColor);
    361             break;
    362         }
    363         default:
    364             SkFAIL("Unknown Custom Xfer mode.");
    365             break;
    366     }
    367 }
    368 
    369 //////////////////////////////////////////////////////////////////////////////
    370 //  Porter-Duff blend helper
    371 //////////////////////////////////////////////////////////////////////////////
    372 
    373 static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkBlendModeCoeff coeff,
    374                                    const char* colorName, const char* srcColorName,
    375                                    const char* dstColorName, bool hasPrevious) {
    376     if (SkBlendModeCoeff::kZero == coeff) {
    377         return hasPrevious;
    378     } else {
    379         if (hasPrevious) {
    380             fsBuilder->codeAppend(" + ");
    381         }
    382         fsBuilder->codeAppendf("%s", colorName);
    383         switch (coeff) {
    384             case SkBlendModeCoeff::kOne:
    385                 break;
    386             case SkBlendModeCoeff::kSC:
    387                 fsBuilder->codeAppendf(" * %s", srcColorName);
    388                 break;
    389             case SkBlendModeCoeff::kISC:
    390                 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
    391                 break;
    392             case SkBlendModeCoeff::kDC:
    393                 fsBuilder->codeAppendf(" * %s", dstColorName);
    394                 break;
    395             case SkBlendModeCoeff::kIDC:
    396                 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
    397                 break;
    398             case SkBlendModeCoeff::kSA:
    399                 fsBuilder->codeAppendf(" * %s.a", srcColorName);
    400                 break;
    401             case SkBlendModeCoeff::kISA:
    402                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
    403                 break;
    404             case SkBlendModeCoeff::kDA:
    405                 fsBuilder->codeAppendf(" * %s.a", dstColorName);
    406                 break;
    407             case SkBlendModeCoeff::kIDA:
    408                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
    409                 break;
    410             default:
    411                 SkFAIL("Unsupported Blend Coeff");
    412         }
    413         return true;
    414     }
    415 }
    416 
    417 //////////////////////////////////////////////////////////////////////////////
    418 
    419 void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
    420                              const char* dstColor, const char* outColor,
    421                              SkBlendMode mode) {
    422 
    423     SkBlendModeCoeff srcCoeff, dstCoeff;
    424     if (SkBlendMode_AsCoeff(mode, &srcCoeff, &dstCoeff)) {
    425         // The only coeff mode that can go out of range is plus.
    426         bool clamp = mode == SkBlendMode::kPlus;
    427 
    428         fsBuilder->codeAppendf("%s = ", outColor);
    429         if (clamp) {
    430             fsBuilder->codeAppend("clamp(");
    431         }
    432         // append src blend
    433         bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
    434                                                 false);
    435         // append dst blend
    436         if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
    437             fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
    438         }
    439         if (clamp) {
    440             fsBuilder->codeAppend(", 0, 1);");
    441         }
    442         fsBuilder->codeAppend(";");
    443     } else {
    444         emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
    445     }
    446 }
    447 
    448 void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
    449                                  const char* dstColor, const char* outColor,
    450                                  SkRegion::Op regionOp) {
    451     SkBlendModeCoeff srcCoeff, dstCoeff;
    452     switch (regionOp) {
    453         case SkRegion::kReplace_Op:
    454             srcCoeff = SkBlendModeCoeff::kOne;
    455             dstCoeff = SkBlendModeCoeff::kZero;
    456             break;
    457         case SkRegion::kIntersect_Op:
    458             srcCoeff = SkBlendModeCoeff::kDC;
    459             dstCoeff = SkBlendModeCoeff::kZero;
    460             break;
    461         case SkRegion::kUnion_Op:
    462             srcCoeff = SkBlendModeCoeff::kOne;
    463             dstCoeff = SkBlendModeCoeff::kISC;
    464             break;
    465         case SkRegion::kXOR_Op:
    466             srcCoeff = SkBlendModeCoeff::kIDC;
    467             dstCoeff = SkBlendModeCoeff::kISC;
    468             break;
    469         case SkRegion::kDifference_Op:
    470             srcCoeff = SkBlendModeCoeff::kZero;
    471             dstCoeff = SkBlendModeCoeff::kISC;
    472             break;
    473         case SkRegion::kReverseDifference_Op:
    474             srcCoeff = SkBlendModeCoeff::kIDC;
    475             dstCoeff = SkBlendModeCoeff::kZero;
    476             break;
    477         default:
    478             SkFAIL("Unsupported Op");
    479             // We should never get here but to make compiler happy
    480             srcCoeff = SkBlendModeCoeff::kZero;
    481             dstCoeff = SkBlendModeCoeff::kZero;
    482     }
    483     fsBuilder->codeAppendf("%s = ", outColor);
    484     // append src blend
    485     bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
    486                                             false);
    487     // append dst blend
    488     if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
    489         fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
    490     }
    491     fsBuilder->codeAppend(";");
    492 }
    493