blob: 2d1e93c7777a266547fcb0c5eabe8080a5675d3b [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/core/SkBlendModePriv.h"
9#include "src/gpu/glsl/GrGLSLBlend.h"
10#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
11#include "src/gpu/glsl/GrGLSLProgramBuilder.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 {");
Ethan Nicholasf7b88202017-09-18 14:10:39 -040053 fsBuilder->codeAppendf("half d = %s.a - %s.%c;", src, src, component);
bsalomonae4738f2015-09-15 15:33:27 -070054 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) {
Brian Osman1a39d3f2017-08-02 13:00:36 -040073 const char* divisorGuard = "";
74 const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
75 if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
76 divisorGuard = "+ 0.00000001";
77 }
78
bsalomonae4738f2015-09-15 15:33:27 -070079 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 {");
Ethan Nicholasf7b88202017-09-18 14:10:39 -040087 fsBuilder->codeAppendf("half d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / (%s.%c %s));",
Brian Osman1a39d3f2017-08-02 13:00:36 -040088 dst, dst, dst, component, src, src, component, divisorGuard);
bsalomonae4738f2015-09-15 15:33:27 -070089 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.
egdaniel2d721d32015-11-11 13:06:05 -080095static void soft_light_component_pos_dst_alpha(GrGLSLFragmentBuilder* fsBuilder,
bsalomonae4738f2015-09-15 15:33:27 -070096 const char* final,
97 const char* src,
98 const char* dst,
99 const char component) {
Brian Osmandff5d432017-08-01 14:46:18 -0400100 const char* divisorGuard = "";
101 const GrShaderCaps* shaderCaps = fsBuilder->getProgramBuilder()->shaderCaps();
102 if (shaderCaps->mustGuardDivisionEvenAfterExplicitZeroCheck()) {
103 divisorGuard = "+ 0.00000001";
104 }
105
bsalomonae4738f2015-09-15 15:33:27 -0700106 // 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)
Brian Osmandff5d432017-08-01 14:46:18 -0400109 fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / (%s.a %s) +"
bsalomonae4738f2015-09-15 15:33:27 -0700110 "(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,
Brian Osmandff5d432017-08-01 14:46:18 -0400112 component, dst, divisorGuard, dst, src, component, dst, component, src,
113 src, component);
bsalomonae4738f2015-09-15 15:33:27 -0700114 // else if (4D < Da)
115 fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
116 dst, component, dst);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400117 fsBuilder->codeAppendf("half DSqd = %s.%c * %s.%c;",
bsalomonae4738f2015-09-15 15:33:27 -0700118 dst, component, dst, component);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400119 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);
bsalomonae4738f2015-09-15 15:33:27 -0700122 // (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) -"
Brian Osmandff5d432017-08-01 14:46:18 -0400126 " DaCub*%s.%c) / (DaSqd %s);",
bsalomonae4738f2015-09-15 15:33:27 -0700127 final, component, src, component, dst, component,
128 src, src, component, dst, src, src, component, src, src,
Brian Osmandff5d432017-08-01 14:46:18 -0400129 component, src, component, divisorGuard);
bsalomonae4738f2015-09-15 15:33:27 -0700130 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:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400142// float3 set_luminance(float3 hueSatColor, float alpha, float3 lumColor).
egdaniel2d721d32015-11-11 13:06:05 -0800143static void add_lum_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
bsalomonae4738f2015-09-15 15:33:27 -0700144 // Emit a helper that gets the luminance of a color.
145 SkString getFunction;
Brian Salomon99938a82016-11-21 13:41:08 -0500146 GrShaderVar getLumArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400147 GrShaderVar("color", kHalf3_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700148 };
Ethan Nicholase1f55022019-02-05 17:17:40 -0500149 SkString getLumBody("return dot(half3(0.3, 0.59, 0.11), color);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400150 fsBuilder->emitFunction(kHalf_GrSLType,
bsalomonae4738f2015-09-15 15:33:27 -0700151 "luminance",
152 SK_ARRAY_COUNT(getLumArgs), getLumArgs,
153 getLumBody.c_str(),
154 &getFunction);
155
156 // Emit the set luminance function.
Brian Salomon99938a82016-11-21 13:41:08 -0500157 GrShaderVar setLumArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400158 GrShaderVar("hueSat", kHalf3_GrSLType),
159 GrShaderVar("alpha", kHalf_GrSLType),
160 GrShaderVar("lumColor", kHalf3_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700161 };
162 SkString setLumBody;
Michael Ludwig94322dc2019-08-05 16:03:45 -0400163 setLumBody.printf("half outLum = %s(lumColor);", getFunction.c_str());
164 setLumBody.appendf("half3 outColor = outLum - %s(hueSat) + hueSat;", getFunction.c_str());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400165 setLumBody.append("half minComp = min(min(outColor.r, outColor.g), outColor.b);"
166 "half maxComp = max(max(outColor.r, outColor.g), outColor.b);"
bsalomonae4738f2015-09-15 15:33:27 -0700167 "if (minComp < 0.0 && outLum != minComp) {"
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400168 "outColor = outLum + ((outColor - half3(outLum, outLum, outLum)) * outLum) /"
bsalomonae4738f2015-09-15 15:33:27 -0700169 "(outLum - minComp);"
170 "}"
171 "if (maxComp > alpha && maxComp != outLum) {"
172 "outColor = outLum +"
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400173 "((outColor - half3(outLum, outLum, outLum)) * (alpha - outLum)) /"
bsalomonae4738f2015-09-15 15:33:27 -0700174 "(maxComp - outLum);"
175 "}"
176 "return outColor;");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400177 fsBuilder->emitFunction(kHalf3_GrSLType,
bsalomonae4738f2015-09-15 15:33:27 -0700178 "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:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400186// float set_saturation(float3 hueLumColor, float3 satColor)
egdaniel2d721d32015-11-11 13:06:05 -0800187static void add_sat_function(GrGLSLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
bsalomonae4738f2015-09-15 15:33:27 -0700188 // Emit a helper that gets the saturation of a color
189 SkString getFunction;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400190 GrShaderVar getSatArgs[] = { GrShaderVar("color", kHalf3_GrSLType) };
bsalomonae4738f2015-09-15 15:33:27 -0700191 SkString getSatBody;
192 getSatBody.printf("return max(max(color.r, color.g), color.b) - "
193 "min(min(color.r, color.g), color.b);");
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400194 fsBuilder->emitFunction(kHalf_GrSLType,
bsalomonae4738f2015-09-15 15:33:27 -0700195 "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
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400202 // problems on PowerVR drivers. So instead it returns a float3 where r, g ,b are the
bsalomonae4738f2015-09-15 15:33:27 -0700203 // adjusted min, mid, and max inputs, respectively.
204 SkString helperFunction;
Brian Salomon99938a82016-11-21 13:41:08 -0500205 GrShaderVar helperArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400206 GrShaderVar("minComp", kHalf_GrSLType),
207 GrShaderVar("midComp", kHalf_GrSLType),
208 GrShaderVar("maxComp", kHalf_GrSLType),
209 GrShaderVar("sat", kHalf_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700210 };
211 static const char kHelperBody[] = "if (minComp < maxComp) {"
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400212 "half3 result;"
bsalomonae4738f2015-09-15 15:33:27 -0700213 "result.r = 0.0;"
214 "result.g = sat * (midComp - minComp) / (maxComp - minComp);"
215 "result.b = sat;"
216 "return result;"
217 "} else {"
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400218 "return half3(0, 0, 0);"
bsalomonae4738f2015-09-15 15:33:27 -0700219 "}";
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400220 fsBuilder->emitFunction(kHalf3_GrSLType,
bsalomonae4738f2015-09-15 15:33:27 -0700221 "set_saturation_helper",
222 SK_ARRAY_COUNT(helperArgs), helperArgs,
223 kHelperBody,
224 &helperFunction);
225
Brian Salomon99938a82016-11-21 13:41:08 -0500226 GrShaderVar setSatArgs[] = {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400227 GrShaderVar("hueLumColor", kHalf3_GrSLType),
228 GrShaderVar("satColor", kHalf3_GrSLType),
bsalomonae4738f2015-09-15 15:33:27 -0700229 };
230 const char* helpFunc = helperFunction.c_str();
231 SkString setSatBody;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400232 setSatBody.appendf("half sat = %s(satColor);"
bsalomonae4738f2015-09-15 15:33:27 -0700233 "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);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400251 fsBuilder->emitFunction(kHalf3_GrSLType,
bsalomonae4738f2015-09-15 15:33:27 -0700252 "set_saturation",
253 SK_ARRAY_COUNT(setSatArgs), setSatArgs,
254 setSatBody.c_str(),
255 setSatFunction);
256}
257
egdaniel2d721d32015-11-11 13:06:05 -0800258static void emit_advanced_xfermode_code(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
bsalomonae4738f2015-09-15 15:33:27 -0700259 const char* dstColor, const char* outputColor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400260 SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700261 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) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400269 case SkBlendMode::kOverlay:
bsalomonae4738f2015-09-15 15:33:27 -0700270 // Overlay is Hard-Light with the src and dst reversed
271 hard_light(fsBuilder, outputColor, dstColor, srcColor);
272 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400273 case SkBlendMode::kDarken:
bsalomonae4738f2015-09-15 15:33:27 -0700274 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400280 case SkBlendMode::kLighten:
bsalomonae4738f2015-09-15 15:33:27 -0700281 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400287 case SkBlendMode::kColorDodge:
bsalomonae4738f2015-09-15 15:33:27 -0700288 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400292 case SkBlendMode::kColorBurn:
bsalomonae4738f2015-09-15 15:33:27 -0700293 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400297 case SkBlendMode::kHardLight:
bsalomonae4738f2015-09-15 15:33:27 -0700298 hard_light(fsBuilder, outputColor, srcColor, dstColor);
299 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400300 case SkBlendMode::kSoftLight:
bsalomonae4738f2015-09-15 15:33:27 -0700301 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400309 case SkBlendMode::kDifference:
bsalomonae4738f2015-09-15 15:33:27 -0700310 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400315 case SkBlendMode::kExclusion:
bsalomonae4738f2015-09-15 15:33:27 -0700316 fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
317 "2.0 * %s.rgb * %s.rgb;",
318 outputColor, dstColor, srcColor, dstColor, srcColor);
319 break;
Mike Reed7d954ad2016-10-28 15:42:34 -0400320 case SkBlendMode::kMultiply:
bsalomonae4738f2015-09-15 15:33:27 -0700321 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;
Mike Reed7d954ad2016-10-28 15:42:34 -0400327 case SkBlendMode::kHue: {
bsalomonae4738f2015-09-15 15:33:27 -0700328 // 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);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400332 fsBuilder->codeAppendf("half4 dstSrcAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700333 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 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400342 case SkBlendMode::kSaturation: {
bsalomonae4738f2015-09-15 15:33:27 -0700343 // 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);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400347 fsBuilder->codeAppendf("half4 dstSrcAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700348 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 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400357 case SkBlendMode::kColor: {
bsalomonae4738f2015-09-15 15:33:27 -0700358 // SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
359 SkString setLum;
360 add_lum_function(fsBuilder, &setLum);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400361 fsBuilder->codeAppendf("half4 srcDstAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700362 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 }
Mike Reed7d954ad2016-10-28 15:42:34 -0400369 case SkBlendMode::kLuminosity: {
bsalomonae4738f2015-09-15 15:33:27 -0700370 // SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
371 SkString setLum;
372 add_lum_function(fsBuilder, &setLum);
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400373 fsBuilder->codeAppendf("half4 srcDstAlpha = %s * %s.a;",
bsalomonae4738f2015-09-15 15:33:27 -0700374 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:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400382 SK_ABORT("Unknown Custom Xfer mode.");
bsalomonae4738f2015-09-15 15:33:27 -0700383 break;
384 }
385}
386
387//////////////////////////////////////////////////////////////////////////////
388// Porter-Duff blend helper
389//////////////////////////////////////////////////////////////////////////////
390
Mike Reed6b3542a2017-06-06 10:41:18 -0400391static bool append_porterduff_term(GrGLSLFragmentBuilder* fsBuilder, SkBlendModeCoeff coeff,
bsalomonae4738f2015-09-15 15:33:27 -0700392 const char* colorName, const char* srcColorName,
393 const char* dstColorName, bool hasPrevious) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400394 if (SkBlendModeCoeff::kZero == coeff) {
bsalomonae4738f2015-09-15 15:33:27 -0700395 return hasPrevious;
396 } else {
397 if (hasPrevious) {
398 fsBuilder->codeAppend(" + ");
399 }
400 fsBuilder->codeAppendf("%s", colorName);
401 switch (coeff) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400402 case SkBlendModeCoeff::kOne:
bsalomonae4738f2015-09-15 15:33:27 -0700403 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400404 case SkBlendModeCoeff::kSC:
bsalomonae4738f2015-09-15 15:33:27 -0700405 fsBuilder->codeAppendf(" * %s", srcColorName);
406 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400407 case SkBlendModeCoeff::kISC:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400408 fsBuilder->codeAppendf(" * (half4(1.0) - %s)", srcColorName);
bsalomonae4738f2015-09-15 15:33:27 -0700409 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400410 case SkBlendModeCoeff::kDC:
bsalomonae4738f2015-09-15 15:33:27 -0700411 fsBuilder->codeAppendf(" * %s", dstColorName);
412 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400413 case SkBlendModeCoeff::kIDC:
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400414 fsBuilder->codeAppendf(" * (half4(1.0) - %s)", dstColorName);
bsalomonae4738f2015-09-15 15:33:27 -0700415 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400416 case SkBlendModeCoeff::kSA:
bsalomonae4738f2015-09-15 15:33:27 -0700417 fsBuilder->codeAppendf(" * %s.a", srcColorName);
418 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400419 case SkBlendModeCoeff::kISA:
bsalomonae4738f2015-09-15 15:33:27 -0700420 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
421 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400422 case SkBlendModeCoeff::kDA:
bsalomonae4738f2015-09-15 15:33:27 -0700423 fsBuilder->codeAppendf(" * %s.a", dstColorName);
424 break;
Mike Reed6b3542a2017-06-06 10:41:18 -0400425 case SkBlendModeCoeff::kIDA:
bsalomonae4738f2015-09-15 15:33:27 -0700426 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
427 break;
428 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400429 SK_ABORT("Unsupported Blend Coeff");
bsalomonae4738f2015-09-15 15:33:27 -0700430 }
431 return true;
432 }
433}
434
435//////////////////////////////////////////////////////////////////////////////
436
egdaniel2d721d32015-11-11 13:06:05 -0800437void GrGLSLBlend::AppendMode(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
bsalomonae4738f2015-09-15 15:33:27 -0700438 const char* dstColor, const char* outColor,
Mike Reed7d954ad2016-10-28 15:42:34 -0400439 SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700440
Mike Reed6b3542a2017-06-06 10:41:18 -0400441 SkBlendModeCoeff srcCoeff, dstCoeff;
442 if (SkBlendMode_AsCoeff(mode, &srcCoeff, &dstCoeff)) {
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500443 // The only coeff mode that can go out of range is plus.
444 bool clamp = mode == SkBlendMode::kPlus;
445
bsalomonae4738f2015-09-15 15:33:27 -0700446 fsBuilder->codeAppendf("%s = ", outColor);
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500447 if (clamp) {
448 fsBuilder->codeAppend("clamp(");
449 }
bsalomonae4738f2015-09-15 15:33:27 -0700450 // 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)) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 fsBuilder->codeAppend("half4(0, 0, 0, 0)");
bsalomonae4738f2015-09-15 15:33:27 -0700456 }
Brian Salomon5d4cd9e2017-02-09 11:16:46 -0500457 if (clamp) {
458 fsBuilder->codeAppend(", 0, 1);");
459 }
bsalomonae4738f2015-09-15 15:33:27 -0700460 fsBuilder->codeAppend(";");
461 } else {
462 emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
463 }
464}
egdanielf34b2932015-12-01 13:54:06 -0800465
466void GrGLSLBlend::AppendRegionOp(GrGLSLFragmentBuilder* fsBuilder, const char* srcColor,
467 const char* dstColor, const char* outColor,
468 SkRegion::Op regionOp) {
Mike Reed6b3542a2017-06-06 10:41:18 -0400469 SkBlendModeCoeff srcCoeff, dstCoeff;
egdanielf34b2932015-12-01 13:54:06 -0800470 switch (regionOp) {
471 case SkRegion::kReplace_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400472 srcCoeff = SkBlendModeCoeff::kOne;
473 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800474 break;
475 case SkRegion::kIntersect_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400476 srcCoeff = SkBlendModeCoeff::kDC;
477 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800478 break;
479 case SkRegion::kUnion_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400480 srcCoeff = SkBlendModeCoeff::kOne;
481 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800482 break;
483 case SkRegion::kXOR_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400484 srcCoeff = SkBlendModeCoeff::kIDC;
485 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800486 break;
487 case SkRegion::kDifference_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400488 srcCoeff = SkBlendModeCoeff::kZero;
489 dstCoeff = SkBlendModeCoeff::kISC;
egdanielf34b2932015-12-01 13:54:06 -0800490 break;
491 case SkRegion::kReverseDifference_Op:
Mike Reed6b3542a2017-06-06 10:41:18 -0400492 srcCoeff = SkBlendModeCoeff::kIDC;
493 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800494 break;
495 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400496 SK_ABORT("Unsupported Op");
egdanielf34b2932015-12-01 13:54:06 -0800497 // We should never get here but to make compiler happy
Mike Reed6b3542a2017-06-06 10:41:18 -0400498 srcCoeff = SkBlendModeCoeff::kZero;
499 dstCoeff = SkBlendModeCoeff::kZero;
egdanielf34b2932015-12-01 13:54:06 -0800500 }
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)) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400507 fsBuilder->codeAppend("half4(0, 0, 0, 0)");
egdanielf34b2932015-12-01 13:54:06 -0800508 }
509 fsBuilder->codeAppend(";");
510}