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(float3(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