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
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(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)
add_sat_function(GrGLSLFragmentBuilder * fsBuilder,SkString * setSatFunction)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
emit_advanced_xfermode_code(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outputColor,SkBlendMode mode)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
append_porterduff_term(GrGLSLFragmentBuilder * fsBuilder,SkBlendModeCoeff coeff,const char * colorName,const char * srcColorName,const char * dstColorName,bool hasPrevious)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
AppendMode(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outColor,SkBlendMode mode)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
AppendRegionOp(GrGLSLFragmentBuilder * fsBuilder,const char * srcColor,const char * dstColor,const char * outColor,SkRegion::Op regionOp)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