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