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