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