• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkBlendModePriv.h"
9 #include "src/gpu/glsl/GrGLSLBlend.h"
10 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
12 
13 //////////////////////////////////////////////////////////////////////////////
14 //  Advanced (non-coeff) blend helpers
15 //////////////////////////////////////////////////////////////////////////////
16 
hard_light(GrGLSLFragmentBuilder * fsBuilder,const char * final,const char * src,const char * dst)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
color_dodge_component(GrGLSLFragmentBuilder * fsBuilder,const char * final,const char * src,const char * dst,const char component)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
color_burn_component(GrGLSLFragmentBuilder * fsBuilder,const char * final,const char * src,const char * dst,const char component)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.
soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder * fsBuilder,const char * final,const char * src,const char * dst,const char component)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).
add_lum_function(GrGLSLFragmentBuilder * fsBuilder,SkString * setLumFunction)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 outLum = %s(lumColor);", getFunction.c_str());
164     setLumBody.appendf("half3 outColor = outLum - %s(hueSat) + hueSat;", getFunction.c_str());
165     setLumBody.append("half minComp = min(min(outColor.r, outColor.g), outColor.b);"
166                       "half maxComp = max(max(outColor.r, outColor.g), outColor.b);"
167                       "if (minComp < 0.0 && outLum != minComp) {"
168                       "outColor = outLum + ((outColor - half3(outLum, outLum, outLum)) * outLum) /"
169                       "(outLum - minComp);"
170                       "}"
171                       "if (maxComp > alpha && maxComp != outLum) {"
172                       "outColor = outLum +"
173                       "((outColor - half3(outLum, outLum, outLum)) * (alpha - outLum)) /"
174                       "(maxComp - outLum);"
175                       "}"
176                       "return outColor;");
177     fsBuilder->emitFunction(kHalf3_GrSLType,
178                             "set_luminance",
179                             SK_ARRAY_COUNT(setLumArgs), setLumArgs,
180                             setLumBody.c_str(),
181                             setLumFunction);
182 }
183 
184 // Adds a function that creates a color with the hue and luminosity of one input color and
185 // the saturation of another color. It will have this signature:
186 //      float set_saturation(float3 hueLumColor, float3 satColor)
add_sat_function(GrGLSLFragmentBuilder * fsBuilder,SkString * setSatFunction)187 static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
188     // Emit a helper that gets the saturation of a color
189     SkString getFunction;
190     GrShaderVar getSatArgs[] = { GrShaderVar("color", kHalf3_GrSLType) };
191     SkString getSatBody;
192     getSatBody.printf("return max(max(color.r, color.g), color.b) - "
193                       "min(min(color.r, color.g), color.b);");
194     fsBuilder->emitFunction(kHalf_GrSLType,
195                             "saturation",
196                             SK_ARRAY_COUNT(getSatArgs), getSatArgs,
197                             getSatBody.c_str(),
198                             &getFunction);
199 
200     // Emit a helper that sets the saturation given sorted input channels. This used
201     // to use inout params for min, mid, and max components but that seems to cause
202     // problems on PowerVR drivers. So instead it returns a float3 where r, g ,b are the
203     // adjusted min, mid, and max inputs, respectively.
204     SkString helperFunction;
205     GrShaderVar helperArgs[] = {
206         GrShaderVar("minComp", kHalf_GrSLType),
207         GrShaderVar("midComp", kHalf_GrSLType),
208         GrShaderVar("maxComp", kHalf_GrSLType),
209         GrShaderVar("sat", kHalf_GrSLType),
210     };
211     static const char kHelperBody[] = "if (minComp < maxComp) {"
212         "half3 result;"
213         "result.r = 0.0;"
214         "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
215         "result.b = sat;"
216         "return result;"
217         "} else {"
218         "return half3(0, 0, 0);"
219         "}";
220     fsBuilder->emitFunction(kHalf3_GrSLType,
221                             "set_saturation_helper",
222                             SK_ARRAY_COUNT(helperArgs), helperArgs,
223                             kHelperBody,
224                             &helperFunction);
225 
226     GrShaderVar setSatArgs[] = {
227         GrShaderVar("hueLumColor", kHalf3_GrSLType),
228         GrShaderVar("satColor", kHalf3_GrSLType),
229     };
230     const char* helpFunc = helperFunction.c_str();
231     SkString setSatBody;
232     setSatBody.appendf("half sat = %s(satColor);"
233                        "if (hueLumColor.r <= hueLumColor.g) {"
234                        "if (hueLumColor.g <= hueLumColor.b) {"
235                        "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
236                        "} else if (hueLumColor.r <= hueLumColor.b) {"
237                        "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
238                        "} else {"
239                        "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
240                        "}"
241                        "} else if (hueLumColor.r <= hueLumColor.b) {"
242                        "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
243                        "} else if (hueLumColor.g <= hueLumColor.b) {"
244                        "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
245                        "} else {"
246                        "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
247                        "}"
248                        "return hueLumColor;",
249                        getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
250                        helpFunc, helpFunc);
251     fsBuilder->emitFunction(kHalf3_GrSLType,
252                             "set_saturation",
253                             SK_ARRAY_COUNT(setSatArgs), setSatArgs,
254                             setSatBody.c_str(),
255                             setSatFunction);
256 }
257 
emit_advanced_xfermode_code(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outputColor,SkBlendMode mode)258 static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
259                                         const char* dstColor, const char* outputColor,
260                                         SkBlendMode mode) {
261     SkASSERT(srcColor);
262     SkASSERT(dstColor);
263     SkASSERT(outputColor);
264     // These all perform src-over on the alpha channel.
265     fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
266                            outputColor, srcColor, srcColor, dstColor);
267 
268     switch (mode) {
269         case SkBlendMode::kOverlay:
270             // Overlay is Hard-Light with the src and dst reversed
271             hard_light(fsBuilder, outputColor, dstColor, srcColor);
272             break;
273         case SkBlendMode::kDarken:
274             fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
275                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
276                                    outputColor,
277                                    srcColor, dstColor, srcColor,
278                                    dstColor, srcColor, dstColor);
279             break;
280         case SkBlendMode::kLighten:
281             fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
282                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
283                                    outputColor,
284                                    srcColor, dstColor, srcColor,
285                                    dstColor, srcColor, dstColor);
286             break;
287         case SkBlendMode::kColorDodge:
288             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
289             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
290             color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
291             break;
292         case SkBlendMode::kColorBurn:
293             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
294             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
295             color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
296             break;
297         case SkBlendMode::kHardLight:
298             hard_light(fsBuilder, outputColor, srcColor, dstColor);
299             break;
300         case SkBlendMode::kSoftLight:
301             fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
302             fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor);
303             fsBuilder->codeAppendf("} else {");
304             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r');
305             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g');
306             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b');
307             fsBuilder->codeAppendf("}");
308             break;
309         case SkBlendMode::kDifference:
310             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
311                                    "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
312                                    outputColor, srcColor, dstColor, srcColor, dstColor,
313                                    dstColor, srcColor);
314             break;
315         case SkBlendMode::kExclusion:
316             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
317                                    "2.0 * %s.rgb * %s.rgb;",
318                                    outputColor, dstColor, srcColor, dstColor, srcColor);
319             break;
320         case SkBlendMode::kMultiply:
321             fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
322                                    "(1.0 - %s.a) * %s.rgb + "
323                                    "%s.rgb * %s.rgb;",
324                                    outputColor, srcColor, dstColor, dstColor, srcColor,
325                                    srcColor, dstColor);
326             break;
327         case SkBlendMode::kHue: {
328             //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
329             SkString setSat, setLum;
330             add_sat_function(fsBuilder, &setSat);
331             add_lum_function(fsBuilder, &setLum);
332             fsBuilder->codeAppendf("half4 dstSrcAlpha = %s * %s.a;",
333                                    dstColor, srcColor);
334             fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
335                                    "dstSrcAlpha.a, dstSrcAlpha.rgb);",
336                                    outputColor, setLum.c_str(), setSat.c_str(), srcColor,
337                                    dstColor);
338             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
339                                    outputColor, srcColor, dstColor, dstColor, srcColor);
340             break;
341         }
342         case SkBlendMode::kSaturation: {
343             // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
344             SkString setSat, setLum;
345             add_sat_function(fsBuilder, &setSat);
346             add_lum_function(fsBuilder, &setLum);
347             fsBuilder->codeAppendf("half4 dstSrcAlpha = %s * %s.a;",
348                                    dstColor, srcColor);
349             fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
350                                    "dstSrcAlpha.a, dstSrcAlpha.rgb);",
351                                    outputColor, setLum.c_str(), setSat.c_str(), srcColor,
352                                    dstColor);
353             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
354                                    outputColor, srcColor, dstColor, dstColor, srcColor);
355             break;
356         }
357         case SkBlendMode::kColor: {
358             //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
359             SkString setLum;
360             add_lum_function(fsBuilder, &setLum);
361             fsBuilder->codeAppendf("half4 srcDstAlpha = %s * %s.a;",
362                                    srcColor, dstColor);
363             fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
364                                    outputColor, setLum.c_str(), dstColor, srcColor);
365             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
366                                    outputColor, srcColor, dstColor, dstColor, srcColor);
367             break;
368         }
369         case SkBlendMode::kLuminosity: {
370             //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
371             SkString setLum;
372             add_lum_function(fsBuilder, &setLum);
373             fsBuilder->codeAppendf("half4 srcDstAlpha = %s * %s.a;",
374                                    srcColor, dstColor);
375             fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
376                                    outputColor, setLum.c_str(), dstColor, srcColor);
377             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
378                                    outputColor, srcColor, dstColor, dstColor, srcColor);
379             break;
380         }
381         default:
382             SK_ABORT("Unknown Custom Xfer mode.");
383             break;
384     }
385 }
386 
387 //////////////////////////////////////////////////////////////////////////////
388 //  Porter-Duff blend helper
389 //////////////////////////////////////////////////////////////////////////////
390 
append_porterduff_term(GrGLSLFragmentBuilder * fsBuilder,SkBlendModeCoeff coeff,const char * colorName,const char * srcColorName,const char * dstColorName,bool hasPrevious)391 static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkBlendModeCoeff coeff,
392                                    const char* colorName, const char* srcColorName,
393                                    const char* dstColorName, bool hasPrevious) {
394     if (SkBlendModeCoeff::kZero == coeff) {
395         return hasPrevious;
396     } else {
397         if (hasPrevious) {
398             fsBuilder->codeAppend(" + ");
399         }
400         fsBuilder->codeAppendf("%s", colorName);
401         switch (coeff) {
402             case SkBlendModeCoeff::kOne:
403                 break;
404             case SkBlendModeCoeff::kSC:
405                 fsBuilder->codeAppendf(" * %s", srcColorName);
406                 break;
407             case SkBlendModeCoeff::kISC:
408                 fsBuilder->codeAppendf(" * (half4(1.0) - %s)", srcColorName);
409                 break;
410             case SkBlendModeCoeff::kDC:
411                 fsBuilder->codeAppendf(" * %s", dstColorName);
412                 break;
413             case SkBlendModeCoeff::kIDC:
414                 fsBuilder->codeAppendf(" * (half4(1.0) - %s)", dstColorName);
415                 break;
416             case SkBlendModeCoeff::kSA:
417                 fsBuilder->codeAppendf(" * %s.a", srcColorName);
418                 break;
419             case SkBlendModeCoeff::kISA:
420                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
421                 break;
422             case SkBlendModeCoeff::kDA:
423                 fsBuilder->codeAppendf(" * %s.a", dstColorName);
424                 break;
425             case SkBlendModeCoeff::kIDA:
426                 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
427                 break;
428             default:
429                 SK_ABORT("Unsupported Blend Coeff");
430         }
431         return true;
432     }
433 }
434 
435 //////////////////////////////////////////////////////////////////////////////
436 
AppendMode(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outColor,SkBlendMode mode)437 void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
438                              const char* dstColor, const char* outColor,
439                              SkBlendMode mode) {
440 
441     SkBlendModeCoeff srcCoeff, dstCoeff;
442     if (SkBlendMode_AsCoeff(mode, &srcCoeff, &dstCoeff)) {
443         // The only coeff mode that can go out of range is plus.
444         bool clamp = mode == SkBlendMode::kPlus;
445 
446         fsBuilder->codeAppendf("%s = ", outColor);
447         if (clamp) {
448             fsBuilder->codeAppend("clamp(");
449         }
450         // append src blend
451         bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
452                                                 false);
453         // append dst blend
454         if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
455             fsBuilder->codeAppend("half4(0, 0, 0, 0)");
456         }
457         if (clamp) {
458             fsBuilder->codeAppend(", 0, 1);");
459         }
460         fsBuilder->codeAppend(";");
461     } else {
462         emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
463     }
464 }
465 
AppendRegionOp(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outColor,SkRegion::Op regionOp)466 void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
467                                  const char* dstColor, const char* outColor,
468                                  SkRegion::Op regionOp) {
469     SkBlendModeCoeff srcCoeff, dstCoeff;
470     switch (regionOp) {
471         case SkRegion::kReplace_Op:
472             srcCoeff = SkBlendModeCoeff::kOne;
473             dstCoeff = SkBlendModeCoeff::kZero;
474             break;
475         case SkRegion::kIntersect_Op:
476             srcCoeff = SkBlendModeCoeff::kDC;
477             dstCoeff = SkBlendModeCoeff::kZero;
478             break;
479         case SkRegion::kUnion_Op:
480             srcCoeff = SkBlendModeCoeff::kOne;
481             dstCoeff = SkBlendModeCoeff::kISC;
482             break;
483         case SkRegion::kXOR_Op:
484             srcCoeff = SkBlendModeCoeff::kIDC;
485             dstCoeff = SkBlendModeCoeff::kISC;
486             break;
487         case SkRegion::kDifference_Op:
488             srcCoeff = SkBlendModeCoeff::kZero;
489             dstCoeff = SkBlendModeCoeff::kISC;
490             break;
491         case SkRegion::kReverseDifference_Op:
492             srcCoeff = SkBlendModeCoeff::kIDC;
493             dstCoeff = SkBlendModeCoeff::kZero;
494             break;
495         default:
496             SK_ABORT("Unsupported Op");
497             // We should never get here but to make compiler happy
498             srcCoeff = SkBlendModeCoeff::kZero;
499             dstCoeff = SkBlendModeCoeff::kZero;
500     }
501     fsBuilder->codeAppendf("%s = ", outColor);
502     // append src blend
503     bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
504                                             false);
505     // append dst blend
506     if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
507         fsBuilder->codeAppend("half4(0, 0, 0, 0)");
508     }
509     fsBuilder->codeAppend(";");
510 }
511