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