blob: 9d7a064b815db0c38fcc3bd9408eba2c0b24755d [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
bsalomonae4738f2015-09-15 15:33:27 -07008#include "GrGLSLBlend.h"
egdaniel2d721d32015-11-11 13:06:05 -08009#include "glsl/GrGLSLFragmentShaderBuilder.h"
Brian Osmandff5d432017-08-01 14:46:18 -040010#include "glsl/GrGLSLProgramBuilder.h"
Mike Reed6b3542a2017-06-06 10:41:18 -040011#include "SkBlendModePriv.h"
bsalomonae4738f2015-09-15 15:33:27 -070012
13//////////////////////////////////////////////////////////////////////////////
14// Advanced (non-coeff) blend helpers
15//////////////////////////////////////////////////////////////////////////////
16
egdaniel2d721d32015-11-11 13:06:05 -080017static void hard_light(GrGLSLFragmentBuilder* fsBuilder,
bsalomonae4738f2015-09-15 15:33:27 -070018 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
egdaniel2d721d32015-11-11 13:06:05 -080038static void color_dodge_component(GrGLSLFragmentBuilder* fsBuilder,
bsalomonae4738f2015-09-15 15:33:27 -070039 const char* final,
40 const char* src,
41 const char* dst,
42 const char component) {
Brian Osmandff5d432017-08-01 14:46:18 -040043 const char* divisorGuard = "";
44 const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
45 if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
46 divisorGuard = "+ 0.00000001";
47 }
48
bsalomonae4738f2015-09-15 15:33:27 -070049 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("float 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 {");
Brian Osmandff5d432017-08-01 14:46:18 -040059 fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / (d %s));",
60 dst, dst, component, src, divisorGuard);
bsalomonae4738f2015-09-15 15:33:27 -070061 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
egdaniel2d721d32015-11-11 13:06:05 -080068static void color_burn_component(GrGLSLFragmentBuilder* fsBuilder,
bsalomonae4738f2015-09-15 15:33:27 -070069 const char* final,
70 const char* src,
71 const char* dst,
72 const char component) {
73 fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
74 fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
75 final, component, src, dst, src, component, dst, dst, component,
76 src);
77 fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
78 fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
79 final, component, dst, component, src);
80 fsBuilder->codeAppend("} else {");
81 fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
82 dst, dst, dst, component, src, src, component);
83 fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
84 final, component, src, src, component, dst, dst, component, src);
85 fsBuilder->codeAppend("}");
86}
87
88// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
egdaniel2d721d32015-11-11 13:06:05 -080089static void soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder* fsBuilder,
bsalomonae4738f2015-09-15 15:33:27 -070090 const char* final,
91 const char* src,
92 const char* dst,
93 const char component) {
Brian Osmandff5d432017-08-01 14:46:18 -040094 const char* divisorGuard = "";
95 const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
96 if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
97 divisorGuard = "+ 0.00000001";
98 }
99
bsalomonae4738f2015-09-15 15:33:27 -0700100 // if (2S < Sa)
101 fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
102 // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
Brian Osmandff5d432017-08-01 14:46:18 -0400103 fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / (%s.a %s) +"
bsalomonae4738f2015-09-15 15:33:27 -0700104 "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
105 final, component, dst, component, dst, component, src, src,
Brian Osmandff5d432017-08-01 14:46:18 -0400106 component, dst, divisorGuard, dst, src, component, dst, component, src,
107 src, component);
bsalomonae4738f2015-09-15 15:33:27 -0700108 // else if (4D < Da)
109 fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
110 dst, component, dst);
111 fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
112 dst, component, dst, component);
113 fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
114 fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
115 fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
116 // (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
117 fsBuilder->codeAppendf("%s.%c ="
118 "(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
119 " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
Brian Osmandff5d432017-08-01 14:46:18 -0400120 " DaCub*%s.%c) / (DaSqd %s);",
bsalomonae4738f2015-09-15 15:33:27 -0700121 final, component, src, component, dst, component,
122 src, src, component, dst, src, src, component, src, src,
Brian Osmandff5d432017-08-01 14:46:18 -0400123 component, src, component, divisorGuard);
bsalomonae4738f2015-09-15 15:33:27 -0700124 fsBuilder->codeAppendf("} else {");
125 // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
126 fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
127 " sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
128 final, component, dst, component, src, src, component, src, component,
129 dst, dst, component, src, src, component, dst, src, component);
130 fsBuilder->codeAppendf("}");
131}
132
133// Adds a function that takes two colors and an alpha as input. It produces a color with the
134// hue and saturation of the first color, the luminosity of the second color, and the input
135// alpha. It has this signature:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400136// float3 set_luminance(float3 hueSatColor, float alpha, float3 lumColor).
egdaniel2d721d32015-11-11 13:06:05 -0800137static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
bsalomonae4738f2015-09-15 15:33:27 -0700138 // Emit a helper that gets the luminance of a color.
139 SkString getFunction;
Brian Salomon99938a82016-11-21 13:41:08 -0500140 GrShaderVar getLumArgs[] = {
141 GrShaderVar("color", kVec3f_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700142 };
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400143 SkString getLumBody("return dot(float3(0.3, 0.59, 0.11), color);");
bsalomonae4738f2015-09-15 15:33:27 -0700144 fsBuilder->emitFunction(kFloat_GrSLType,
145 "luminance",
146 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
147 getLumBody.c_str(),
148 &getFunction);
149
150 // Emit the set luminance function.
Brian Salomon99938a82016-11-21 13:41:08 -0500151 GrShaderVar setLumArgs[] = {
152 GrShaderVar("hueSat", kVec3f_GrSLType),
153 GrShaderVar("alpha", kFloat_GrSLType),
154 GrShaderVar("lumColor", kVec3f_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700155 };
156 SkString setLumBody;
157 setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400158 setLumBody.append("float3 outColor = hueSat + diff;");
bsalomonae4738f2015-09-15 15:33:27 -0700159 setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
160 setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
161 "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
162 "if (minComp < 0.0 && outLum != minComp) {"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400163 "outColor = outLum + ((outColor - float3(outLum, outLum, outLum)) * outLum) /"
bsalomonae4738f2015-09-15 15:33:27 -0700164 "(outLum - minComp);"
165 "}"
166 "if (maxComp > alpha && maxComp != outLum) {"
167 "outColor = outLum +"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400168 "((outColor - float3(outLum, outLum, outLum)) * (alpha - outLum)) /"
bsalomonae4738f2015-09-15 15:33:27 -0700169 "(maxComp - outLum);"
170 "}"
171 "return outColor;");
172 fsBuilder->emitFunction(kVec3f_GrSLType,
173 "set_luminance",
174 SK_ARRAY_COUNT(setLumArgs), setLumArgs,
175 setLumBody.c_str(),
176 setLumFunction);
177}
178
179// Adds a function that creates a color with the hue and luminosity of one input color and
180// the saturation of another color. It will have this signature:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400181// float set_saturation(float3 hueLumColor, float3 satColor)
egdaniel2d721d32015-11-11 13:06:05 -0800182static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
bsalomonae4738f2015-09-15 15:33:27 -0700183 // Emit a helper that gets the saturation of a color
184 SkString getFunction;
Brian Salomon99938a82016-11-21 13:41:08 -0500185 GrShaderVar getSatArgs[] = { GrShaderVar("color", kVec3f_GrSLType) };
bsalomonae4738f2015-09-15 15:33:27 -0700186 SkString getSatBody;
187 getSatBody.printf("return max(max(color.r, color.g), color.b) - "
188 "min(min(color.r, color.g), color.b);");
189 fsBuilder->emitFunction(kFloat_GrSLType,
190 "saturation",
191 SK_ARRAY_COUNT(getSatArgs), getSatArgs,
192 getSatBody.c_str(),
193 &getFunction);
194
195 // Emit a helper that sets the saturation given sorted input channels. This used
196 // to use inout params for min, mid, and max components but that seems to cause
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400197 // problems on PowerVR drivers. So instead it returns a float3 where r, g ,b are the
bsalomonae4738f2015-09-15 15:33:27 -0700198 // adjusted min, mid, and max inputs, respectively.
199 SkString helperFunction;
Brian Salomon99938a82016-11-21 13:41:08 -0500200 GrShaderVar helperArgs[] = {
201 GrShaderVar("minComp", kFloat_GrSLType),
202 GrShaderVar("midComp", kFloat_GrSLType),
203 GrShaderVar("maxComp", kFloat_GrSLType),
204 GrShaderVar("sat", kFloat_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700205 };
206 static const char kHelperBody[] = "if (minComp < maxComp) {"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400207 "float3 result;"
bsalomonae4738f2015-09-15 15:33:27 -0700208 "result.r = 0.0;"
209 "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
210 "result.b = sat;"
211 "return result;"
212 "} else {"
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400213 "return float3(0, 0, 0);"
bsalomonae4738f2015-09-15 15:33:27 -0700214 "}";
215 fsBuilder->emitFunction(kVec3f_GrSLType,
216 "set_saturation_helper",
217 SK_ARRAY_COUNT(helperArgs), helperArgs,
218 kHelperBody,
219 &helperFunction);
220
Brian Salomon99938a82016-11-21 13:41:08 -0500221 GrShaderVar setSatArgs[] = {
222 GrShaderVar("hueLumColor", kVec3f_GrSLType),
223 GrShaderVar("satColor", kVec3f_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700224 };
225 const char* helpFunc = helperFunction.c_str();
226 SkString setSatBody;
227 setSatBody.appendf("float sat = %s(satColor);"
228 "if (hueLumColor.r <= hueLumColor.g) {"
229 "if (hueLumColor.g <= hueLumColor.b) {"
230 "hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
231 "} else if (hueLumColor.r <= hueLumColor.b) {"
232 "hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
233 "} else {"
234 "hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
235 "}"
236 "} else if (hueLumColor.r <= hueLumColor.b) {"
237 "hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
238 "} else if (hueLumColor.g <= hueLumColor.b) {"
239 "hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
240 "} else {"
241 "hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
242 "}"
243 "return hueLumColor;",
244 getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
245 helpFunc, helpFunc);
246 fsBuilder->emitFunction(kVec3f_GrSLType,
247 "set_saturation",
248 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
249 setSatBody.c_str(),
250 setSatFunction);
251}
252
egdaniel2d721d32015-11-11 13:06:05 -0800253static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
bsalomonae4738f2015-09-15 15:33:27 -0700254 const char* dstColor, const char* outputColor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400255 SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700256 SkASSERT(srcColor);
257 SkASSERT(dstColor);
258 SkASSERT(outputColor);
259 // These all perform src-over on the alpha channel.
260 fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
261 outputColor, srcColor, srcColor, dstColor);
262
263 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400264 case SkBlendMode::kOverlay:
bsalomonae4738f2015-09-15 15:33:27 -0700265 // Overlay is Hard-Light with the src and dst reversed
266 hard_light(fsBuilder, outputColor, dstColor, srcColor);
267 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400268 case SkBlendMode::kDarken:
bsalomonae4738f2015-09-15 15:33:27 -0700269 fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
270 "(1.0 - %s.a) * %s.rgb + %s.rgb);",
271 outputColor,
272 srcColor, dstColor, srcColor,
273 dstColor, srcColor, dstColor);
274 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400275 case SkBlendMode::kLighten:
bsalomonae4738f2015-09-15 15:33:27 -0700276 fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
277 "(1.0 - %s.a) * %s.rgb + %s.rgb);",
278 outputColor,
279 srcColor, dstColor, srcColor,
280 dstColor, srcColor, dstColor);
281 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400282 case SkBlendMode::kColorDodge:
bsalomonae4738f2015-09-15 15:33:27 -0700283 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
284 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
285 color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
286 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400287 case SkBlendMode::kColorBurn:
bsalomonae4738f2015-09-15 15:33:27 -0700288 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
289 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
290 color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
291 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400292 case SkBlendMode::kHardLight:
bsalomonae4738f2015-09-15 15:33:27 -0700293 hard_light(fsBuilder, outputColor, srcColor, dstColor);
294 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400295 case SkBlendMode::kSoftLight:
bsalomonae4738f2015-09-15 15:33:27 -0700296 fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
297 fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor);
298 fsBuilder->codeAppendf("} else {");
299 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r');
300 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g');
301 soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b');
302 fsBuilder->codeAppendf("}");
303 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400304 case SkBlendMode::kDifference:
bsalomonae4738f2015-09-15 15:33:27 -0700305 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
306 "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
307 outputColor, srcColor, dstColor, srcColor, dstColor,
308 dstColor, srcColor);
309 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400310 case SkBlendMode::kExclusion:
bsalomonae4738f2015-09-15 15:33:27 -0700311 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
312 "2.0 * %s.rgb * %s.rgb;",
313 outputColor, dstColor, srcColor, dstColor, srcColor);
314 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400315 case SkBlendMode::kMultiply:
bsalomonae4738f2015-09-15 15:33:27 -0700316 fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
317 "(1.0 - %s.a) * %s.rgb + "
318 "%s.rgb * %s.rgb;",
319 outputColor, srcColor, dstColor, dstColor, srcColor,
320 srcColor, dstColor);
321 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400322 case SkBlendMode::kHue: {
bsalomonae4738f2015-09-15 15:33:27 -0700323 // SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
324 SkString setSat, setLum;
325 add_sat_function(fsBuilder, &setSat);
326 add_lum_function(fsBuilder, &setLum);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400327 fsBuilder->codeAppendf("float4 dstSrcAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700328 dstColor, srcColor);
329 fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
330 "dstSrcAlpha.a, dstSrcAlpha.rgb);",
331 outputColor, setLum.c_str(), setSat.c_str(), srcColor,
332 dstColor);
333 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
334 outputColor, srcColor, dstColor, dstColor, srcColor);
335 break;
336 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400337 case SkBlendMode::kSaturation: {
bsalomonae4738f2015-09-15 15:33:27 -0700338 // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
339 SkString setSat, setLum;
340 add_sat_function(fsBuilder, &setSat);
341 add_lum_function(fsBuilder, &setLum);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400342 fsBuilder->codeAppendf("float4 dstSrcAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700343 dstColor, srcColor);
344 fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
345 "dstSrcAlpha.a, dstSrcAlpha.rgb);",
346 outputColor, setLum.c_str(), setSat.c_str(), srcColor,
347 dstColor);
348 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
349 outputColor, srcColor, dstColor, dstColor, srcColor);
350 break;
351 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400352 case SkBlendMode::kColor: {
bsalomonae4738f2015-09-15 15:33:27 -0700353 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
354 SkString setLum;
355 add_lum_function(fsBuilder, &setLum);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400356 fsBuilder->codeAppendf("float4 srcDstAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700357 srcColor, dstColor);
358 fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
359 outputColor, setLum.c_str(), dstColor, srcColor);
360 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
361 outputColor, srcColor, dstColor, dstColor, srcColor);
362 break;
363 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400364 case SkBlendMode::kLuminosity: {
bsalomonae4738f2015-09-15 15:33:27 -0700365 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
366 SkString setLum;
367 add_lum_function(fsBuilder, &setLum);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400368 fsBuilder->codeAppendf("float4 srcDstAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700369 srcColor, dstColor);
370 fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
371 outputColor, setLum.c_str(), dstColor, srcColor);
372 fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
373 outputColor, srcColor, dstColor, dstColor, srcColor);
374 break;
375 }
376 default:
377 SkFAIL("Unknown Custom Xfer mode.");
378 break;
379 }
380}
381
382//////////////////////////////////////////////////////////////////////////////
383// Porter-Duff blend helper
384//////////////////////////////////////////////////////////////////////////////
385
Mike Reed6b3542a2017-06-06 10:41:18 -0400386static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkBlendModeCoeff coeff,
bsalomonae4738f2015-09-15 15:33:27 -0700387 const char* colorName, const char* srcColorName,
388 const char* dstColorName, bool hasPrevious) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400389 if (SkBlendModeCoeff::kZero == coeff) {
bsalomonae4738f2015-09-15 15:33:27 -0700390 return hasPrevious;
391 } else {
392 if (hasPrevious) {
393 fsBuilder->codeAppend(" + ");
394 }
395 fsBuilder->codeAppendf("%s", colorName);
396 switch (coeff) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400397 case SkBlendModeCoeff::kOne:
bsalomonae4738f2015-09-15 15:33:27 -0700398 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400399 case SkBlendModeCoeff::kSC:
bsalomonae4738f2015-09-15 15:33:27 -0700400 fsBuilder->codeAppendf(" * %s", srcColorName);
401 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400402 case SkBlendModeCoeff::kISC:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400403 fsBuilder->codeAppendf(" * (float4(1.0) - %s)", srcColorName);
bsalomonae4738f2015-09-15 15:33:27 -0700404 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400405 case SkBlendModeCoeff::kDC:
bsalomonae4738f2015-09-15 15:33:27 -0700406 fsBuilder->codeAppendf(" * %s", dstColorName);
407 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400408 case SkBlendModeCoeff::kIDC:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400409 fsBuilder->codeAppendf(" * (float4(1.0) - %s)", dstColorName);
bsalomonae4738f2015-09-15 15:33:27 -0700410 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400411 case SkBlendModeCoeff::kSA:
bsalomonae4738f2015-09-15 15:33:27 -0700412 fsBuilder->codeAppendf(" * %s.a", srcColorName);
413 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400414 case SkBlendModeCoeff::kISA:
bsalomonae4738f2015-09-15 15:33:27 -0700415 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
416 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400417 case SkBlendModeCoeff::kDA:
bsalomonae4738f2015-09-15 15:33:27 -0700418 fsBuilder->codeAppendf(" * %s.a", dstColorName);
419 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400420 case SkBlendModeCoeff::kIDA:
bsalomonae4738f2015-09-15 15:33:27 -0700421 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
422 break;
423 default:
424 SkFAIL("Unsupported Blend Coeff");
425 }
426 return true;
427 }
428}
429
430//////////////////////////////////////////////////////////////////////////////
431
egdaniel2d721d32015-11-11 13:06:05 -0800432void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
bsalomonae4738f2015-09-15 15:33:27 -0700433 const char* dstColor, const char* outColor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400434 SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700435
Mike Reed6b3542a2017-06-06 10:41:18 -0400436 SkBlendModeCoeff srcCoeff, dstCoeff;
437 if (SkBlendMode_AsCoeff(mode, &srcCoeff, &dstCoeff)) {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500438 // The only coeff mode that can go out of range is plus.
439 bool clamp = mode == SkBlendMode::kPlus;
440
bsalomonae4738f2015-09-15 15:33:27 -0700441 fsBuilder->codeAppendf("%s = ", outColor);
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500442 if (clamp) {
443 fsBuilder->codeAppend("clamp(");
444 }
bsalomonae4738f2015-09-15 15:33:27 -0700445 // append src blend
446 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
447 false);
448 // append dst blend
449 if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400450 fsBuilder->codeAppend("float4(0, 0, 0, 0)");
bsalomonae4738f2015-09-15 15:33:27 -0700451 }
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500452 if (clamp) {
453 fsBuilder->codeAppend(", 0, 1);");
454 }
bsalomonae4738f2015-09-15 15:33:27 -0700455 fsBuilder->codeAppend(";");
456 } else {
457 emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
458 }
459}
egdanielf34b2932015-12-01 13:54:06 -0800460
461void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
462 const char* dstColor, const char* outColor,
463 SkRegion::Op regionOp) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400464 SkBlendModeCoeff srcCoeff, dstCoeff;
egdanielf34b2932015-12-01 13:54:06 -0800465 switch (regionOp) {
466 case SkRegion::kReplace_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400467 srcCoeff = SkBlendModeCoeff::kOne;
468 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800469 break;
470 case SkRegion::kIntersect_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400471 srcCoeff = SkBlendModeCoeff::kDC;
472 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800473 break;
474 case SkRegion::kUnion_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400475 srcCoeff = SkBlendModeCoeff::kOne;
476 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800477 break;
478 case SkRegion::kXOR_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400479 srcCoeff = SkBlendModeCoeff::kIDC;
480 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800481 break;
482 case SkRegion::kDifference_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400483 srcCoeff = SkBlendModeCoeff::kZero;
484 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800485 break;
486 case SkRegion::kReverseDifference_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400487 srcCoeff = SkBlendModeCoeff::kIDC;
488 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800489 break;
490 default:
491 SkFAIL("Unsupported Op");
492 // We should never get here but to make compiler happy
Mike Reed6b3542a2017-06-06 10:41:18 -0400493 srcCoeff = SkBlendModeCoeff::kZero;
494 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800495 }
496 fsBuilder->codeAppendf("%s = ", outColor);
497 // append src blend
498 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
499 false);
500 // append dst blend
501 if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400502 fsBuilder->codeAppend("float4(0, 0, 0, 0)");
egdanielf34b2932015-12-01 13:54:06 -0800503 }
504 fsBuilder->codeAppend(";");
505}