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