Revert of Use dst copies in porter duffer XP to correctly render certain blends....
[platform/upstream/libSkiaSharp.git] / src / gpu / effects / GrCustomXfermode.cpp
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 "effects/GrCustomXfermode.h"
9 #include "effects/GrCustomXfermodePriv.h"
10
11 #include "GrCoordTransform.h"
12 #include "GrContext.h"
13 #include "GrFragmentProcessor.h"
14 #include "GrInvariantOutput.h"
15 #include "GrProcessor.h"
16 #include "GrTexture.h"
17 #include "GrTextureAccess.h"
18 #include "SkXfermode.h"
19 #include "gl/GrGLCaps.h"
20 #include "gl/GrGLProcessor.h"
21 #include "gl/GrGLProgramDataManager.h"
22 #include "gl/builders/GrGLProgramBuilder.h"
23
24 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) {
25     return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
26 }
27
28 ///////////////////////////////////////////////////////////////////////////////
29 // Static helpers
30 ///////////////////////////////////////////////////////////////////////////////
31
32 static void hard_light(GrGLFPFragmentBuilder* fsBuilder,
33                        const char* final,
34                        const char* src,
35                        const char* dst) {
36     static const char kComponents[] = {'r', 'g', 'b'};
37     for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
38         char component = kComponents[i];
39         fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
40         fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
41                                final, component, src, component, dst, component);
42         fsBuilder->codeAppend("} else {");
43         fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
44                                final, component, src, dst, dst, dst, component, src, src,
45                                component);
46         fsBuilder->codeAppend("}");
47     }
48     fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
49                            final, src, dst, dst, src);
50 }
51
52 // Does one component of color-dodge
53 static void color_dodge_component(GrGLFPFragmentBuilder* fsBuilder,
54                                   const char* final,
55                                   const char* src,
56                                   const char* dst,
57                                   const char component) {
58     fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
59     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
60                            final, component, src, component, dst);
61     fsBuilder->codeAppend("} else {");
62     fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
63     fsBuilder->codeAppend("if (0.0 == d) {");
64     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
65                            final, component, src, dst, src, component, dst, dst, component,
66                            src);
67     fsBuilder->codeAppend("} else {");
68     fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
69                            dst, dst, component, src);
70     fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
71                            final, component, src, src, component, dst, dst, component, src);
72     fsBuilder->codeAppend("}");
73     fsBuilder->codeAppend("}");
74 }
75
76 // Does one component of color-burn
77 static void color_burn_component(GrGLFPFragmentBuilder* fsBuilder,
78                                  const char* final,
79                                  const char* src,
80                                  const char* dst,
81                                  const char component) {
82     fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
83     fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
84                            final, component, src, dst, src, component, dst, dst, component,
85                            src);
86     fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
87     fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
88                            final, component, dst, component, src);
89     fsBuilder->codeAppend("} else {");
90     fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
91                            dst, dst, dst, component, src, src, component);
92     fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
93                            final, component, src, src, component, dst, dst, component, src);
94     fsBuilder->codeAppend("}");
95 }
96
97 // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
98 static void soft_light_component_pos_dst_alpha(GrGLFPFragmentBuilder* fsBuilder,
99                                                const char* final,
100                                                const char* src,
101                                                const char* dst,
102                                                const char component) {
103     // if (2S < Sa)
104     fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
105     // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
106     fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
107                                    "(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
108                            final, component, dst, component, dst, component, src, src,
109                            component, dst, dst, src, component, dst, component, src, src,
110                            component);
111     // else if (4D < Da)
112     fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
113                            dst, component, dst);
114     fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
115                            dst, component, dst, component);
116     fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
117     fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
118     fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
119     // (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
120     fsBuilder->codeAppendf("%s.%c ="
121                            "(-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
122                            " 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) /"
123                            "DaSqd;",
124                            final, component, src, component, src, component, dst, component,
125                            src, src, component, dst, src, src, component, src, src,
126                            component);
127     fsBuilder->codeAppendf("} else {");
128     // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
129     fsBuilder->codeAppendf("%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c +"
130                                    "%s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;",
131                            final, component, dst, dst, component, src, src, component, dst,
132                            src, component, dst, component, src, src, component, src,
133                            component);
134     fsBuilder->codeAppendf("}");
135 }
136
137 // Adds a function that takes two colors and an alpha as input. It produces a color with the
138 // hue and saturation of the first color, the luminosity of the second color, and the input
139 // alpha. It has this signature:
140 //      vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
141 static void add_lum_function(GrGLFPFragmentBuilder* fsBuilder, SkString* setLumFunction) {
142     // Emit a helper that gets the luminance of a color.
143     SkString getFunction;
144     GrGLShaderVar getLumArgs[] = {
145         GrGLShaderVar("color", kVec3f_GrSLType),
146     };
147     SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
148     fsBuilder->emitFunction(kFloat_GrSLType,
149                             "luminance",
150                             SK_ARRAY_COUNT(getLumArgs), getLumArgs,
151                             getLumBody.c_str(),
152                             &getFunction);
153
154     // Emit the set luminance function.
155     GrGLShaderVar setLumArgs[] = {
156         GrGLShaderVar("hueSat", kVec3f_GrSLType),
157         GrGLShaderVar("alpha", kFloat_GrSLType),
158         GrGLShaderVar("lumColor", kVec3f_GrSLType),
159     };
160     SkString setLumBody;
161     setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
162     setLumBody.append("vec3 outColor = hueSat + diff;");
163     setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
164     setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
165                       "float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
166                       "if (minComp < 0.0 && outLum != minComp) {"
167                       "outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
168                                           "(outLum - minComp);"
169                       "}"
170                       "if (maxComp > alpha && maxComp != outLum) {"
171                       "outColor = outLum +"
172                                  "((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
173                                  "(maxComp - outLum);"
174                       "}"
175                       "return outColor;");
176     fsBuilder->emitFunction(kVec3f_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(vec3 hueLumColor, vec3 satColor)
186 static void add_sat_function(GrGLFPFragmentBuilder* fsBuilder, SkString* setSatFunction) {
187     // Emit a helper that gets the saturation of a color
188     SkString getFunction;
189     GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_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(kFloat_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 vec3 where r, g ,b are the
202     // adjusted min, mid, and max inputs, respectively.
203     SkString helperFunction;
204     GrGLShaderVar helperArgs[] = {
205         GrGLShaderVar("minComp", kFloat_GrSLType),
206         GrGLShaderVar("midComp", kFloat_GrSLType),
207         GrGLShaderVar("maxComp", kFloat_GrSLType),
208         GrGLShaderVar("sat", kFloat_GrSLType),
209     };
210     static const char kHelperBody[] = "if (minComp < maxComp) {"
211         "vec3 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 vec3(0, 0, 0);"
218         "}";
219     fsBuilder->emitFunction(kVec3f_GrSLType,
220                             "set_saturation_helper",
221                             SK_ARRAY_COUNT(helperArgs), helperArgs,
222                             kHelperBody,
223                             &helperFunction);
224
225     GrGLShaderVar setSatArgs[] = {
226         GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
227         GrGLShaderVar("satColor", kVec3f_GrSLType),
228     };
229     const char* helpFunc = helperFunction.c_str();
230     SkString setSatBody;
231     setSatBody.appendf("float 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(kVec3f_GrSLType,
251                             "set_saturation",
252                             SK_ARRAY_COUNT(setSatArgs), setSatArgs,
253                             setSatBody.c_str(),
254                             setSatFunction);
255
256 }
257
258 static void emit_custom_xfermode_code(SkXfermode::Mode mode,
259                                       GrGLFPFragmentBuilder* fsBuilder,
260                                       const char* outputColor,
261                                       const char* inputColor,
262                                       const char* dstColor) {
263     // We don't try to optimize for this case at all
264     if (NULL == inputColor) {
265         fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
266         inputColor = "ones";
267     }
268     fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
269
270     // These all perform src-over on the alpha channel.
271     fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
272                            outputColor, inputColor, inputColor, dstColor);
273
274     switch (mode) {
275         case SkXfermode::kOverlay_Mode:
276             // Overlay is Hard-Light with the src and dst reversed
277             hard_light(fsBuilder, outputColor, dstColor, inputColor);
278             break;
279         case SkXfermode::kDarken_Mode:
280             fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
281                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
282                                    outputColor,
283                                    inputColor, dstColor, inputColor,
284                                    dstColor, inputColor, dstColor);
285             break;
286         case SkXfermode::kLighten_Mode:
287             fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
288                                    "(1.0 - %s.a) * %s.rgb + %s.rgb);",
289                                    outputColor,
290                                    inputColor, dstColor, inputColor,
291                                    dstColor, inputColor, dstColor);
292             break;
293         case SkXfermode::kColorDodge_Mode:
294             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
295             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
296             color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
297             break;
298         case SkXfermode::kColorBurn_Mode:
299             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
300             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
301             color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
302             break;
303         case SkXfermode::kHardLight_Mode:
304             hard_light(fsBuilder, outputColor, inputColor, dstColor);
305             break;
306         case SkXfermode::kSoftLight_Mode:
307             fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
308             fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor);
309             fsBuilder->codeAppendf("} else {");
310             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
311             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
312             soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
313             fsBuilder->codeAppendf("}");
314             break;
315         case SkXfermode::kDifference_Mode:
316             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
317                                    "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
318                                    outputColor, inputColor, dstColor, inputColor, dstColor,
319                                    dstColor, inputColor);
320             break;
321         case SkXfermode::kExclusion_Mode:
322             fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
323                                    "2.0 * %s.rgb * %s.rgb;",
324                                    outputColor, dstColor, inputColor, dstColor, inputColor);
325             break;
326         case SkXfermode::kMultiply_Mode:
327             fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
328                                    "(1.0 - %s.a) * %s.rgb + "
329                                    "%s.rgb * %s.rgb;",
330                                    outputColor, inputColor, dstColor, dstColor, inputColor,
331                                    inputColor, dstColor);
332             break;
333         case SkXfermode::kHue_Mode: {
334             //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
335             SkString setSat, setLum;
336             add_sat_function(fsBuilder, &setSat);
337             add_lum_function(fsBuilder, &setLum);
338             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
339                                    dstColor, inputColor);
340             fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
341                                                "dstSrcAlpha.a, dstSrcAlpha.rgb);",
342                                    outputColor, setLum.c_str(), setSat.c_str(), inputColor,
343                                    dstColor);
344             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
345                                    outputColor, inputColor, dstColor, dstColor, inputColor);
346             break;
347         }
348         case SkXfermode::kSaturation_Mode: {
349             // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
350             SkString setSat, setLum;
351             add_sat_function(fsBuilder, &setSat);
352             add_lum_function(fsBuilder, &setLum);
353             fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
354                                    dstColor, inputColor);
355             fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
356                                                "dstSrcAlpha.a, dstSrcAlpha.rgb);",
357                                    outputColor, setLum.c_str(), setSat.c_str(), inputColor,
358                                    dstColor);
359             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
360                                    outputColor, inputColor, dstColor, dstColor, inputColor);
361             break;
362         }
363         case SkXfermode::kColor_Mode: {
364             //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
365             SkString setLum;
366             add_lum_function(fsBuilder, &setLum);
367             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
368                                    inputColor, dstColor);
369             fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
370                                    outputColor, setLum.c_str(), dstColor, inputColor);
371             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
372                                    outputColor, inputColor, dstColor, dstColor, inputColor);
373             break;
374         }
375         case SkXfermode::kLuminosity_Mode: {
376             //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
377             SkString setLum;
378             add_lum_function(fsBuilder, &setLum);
379             fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
380                                    inputColor, dstColor);
381             fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
382                                    outputColor, setLum.c_str(), dstColor, inputColor);
383             fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
384                                    outputColor, inputColor, dstColor, dstColor, inputColor);
385             break;
386         }
387         default:
388             SkFAIL("Unknown Custom Xfer mode.");
389             break;
390     }
391 }
392
393 ///////////////////////////////////////////////////////////////////////////////
394 // Fragment Processor
395 ///////////////////////////////////////////////////////////////////////////////
396
397 GrFragmentProcessor* GrCustomXfermode::CreateFP(SkXfermode::Mode mode, GrTexture* background) {
398     if (!GrCustomXfermode::IsSupportedMode(mode)) {
399         return NULL;
400     } else {
401         return SkNEW_ARGS(GrCustomXferFP, (mode, background));
402     }
403 }
404
405 ///////////////////////////////////////////////////////////////////////////////
406
407 class GLCustomXferFP : public GrGLFragmentProcessor {
408 public:
409     GLCustomXferFP(const GrFragmentProcessor&) {}
410     ~GLCustomXferFP() SK_OVERRIDE {};
411
412     void emitCode(GrGLFPBuilder* builder,
413                   const GrFragmentProcessor& fp,
414                   const char* outputColor,
415                   const char* inputColor,
416                   const TransformedCoordsArray& coords,
417                   const TextureSamplerArray& samplers) SK_OVERRIDE {
418         SkXfermode::Mode mode = fp.cast<GrCustomXferFP>().mode();
419         GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
420         const char* dstColor = "bgColor";
421         fsBuilder->codeAppendf("vec4 %s = ", dstColor);
422         fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType());
423         fsBuilder->codeAppendf(";");
424
425         emit_custom_xfermode_code(mode, fsBuilder, outputColor, inputColor, dstColor); 
426     }
427
428     void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
429
430     static void GenKey(const GrFragmentProcessor& proc, const GrGLCaps&, GrProcessorKeyBuilder* b) {
431         // The background may come from the dst or from a texture.
432         uint32_t key = proc.numTextures();
433         SkASSERT(key <= 1);
434         key |= proc.cast<GrCustomXferFP>().mode() << 1;
435         b->add32(key);
436     }
437
438 private:
439     typedef GrGLFragmentProcessor INHERITED;
440 };
441
442 ///////////////////////////////////////////////////////////////////////////////
443
444 GrCustomXferFP::GrCustomXferFP(SkXfermode::Mode mode, GrTexture* background)
445     : fMode(mode) {
446     this->initClassID<GrCustomXferFP>();
447
448     SkASSERT(background);
449     fBackgroundTransform.reset(kLocal_GrCoordSet, background, 
450                                GrTextureParams::kNone_FilterMode);
451     this->addCoordTransform(&fBackgroundTransform);
452     fBackgroundAccess.reset(background);
453     this->addTextureAccess(&fBackgroundAccess);
454 }
455
456 void GrCustomXferFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
457     GLCustomXferFP::GenKey(*this, caps, b);
458 }
459
460 GrGLFragmentProcessor* GrCustomXferFP::createGLInstance() const {
461     return SkNEW_ARGS(GLCustomXferFP, (*this));
462 }
463
464 bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const {
465     const GrCustomXferFP& s = other.cast<GrCustomXferFP>();
466     return fMode == s.fMode;
467 }
468
469 void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
470     inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
471 }
472
473 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP);
474 GrFragmentProcessor* GrCustomXferFP::TestCreate(SkRandom* rand,
475                                                 GrContext*,
476                                                 const GrDrawTargetCaps&,
477                                                 GrTexture* textures[]) {
478     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
479
480     return SkNEW_ARGS(GrCustomXferFP, (static_cast<SkXfermode::Mode>(mode), textures[0]));
481 }
482
483 ///////////////////////////////////////////////////////////////////////////////
484 // Xfer Processor
485 ///////////////////////////////////////////////////////////////////////////////
486
487 class CustomXP : public GrXferProcessor {
488 public:
489     static GrXferProcessor* Create(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy,
490                                    bool willReadDstColor) {
491         if (!GrCustomXfermode::IsSupportedMode(mode)) {
492             return NULL;
493         } else {
494             return SkNEW_ARGS(CustomXP, (mode, dstCopy, willReadDstColor));
495         }
496     }
497
498     ~CustomXP() SK_OVERRIDE {};
499
500     const char* name() const SK_OVERRIDE { return "Custom Xfermode"; }
501
502     GrGLXferProcessor* createGLInstance() const SK_OVERRIDE;
503
504     bool hasSecondaryOutput() const SK_OVERRIDE { return false; }
505
506     GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
507                                                const GrProcOptInfo& coveragePOI,
508                                                bool doesStencilWrite,
509                                                GrColor* overrideColor,
510                                                const GrDrawTargetCaps& caps) SK_OVERRIDE;
511
512     void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
513         blendInfo->fSrcBlend = kOne_GrBlendCoeff;
514         blendInfo->fDstBlend = kZero_GrBlendCoeff;
515         blendInfo->fBlendConstant = 0;
516     }
517
518     SkXfermode::Mode mode() const { return fMode; }
519
520 private:
521     CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
522
523     void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE;
524
525     bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE;
526
527     SkXfermode::Mode fMode;
528
529     typedef GrXferProcessor INHERITED;
530 };
531
532 ///////////////////////////////////////////////////////////////////////////////
533
534 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
535     if (!GrCustomXfermode::IsSupportedMode(mode)) {
536         return NULL;
537     } else {
538         return SkNEW_ARGS(GrCustomXPFactory, (mode));
539     }
540 }
541
542 ///////////////////////////////////////////////////////////////////////////////
543
544 class GLCustomXP : public GrGLXferProcessor {
545 public:
546     GLCustomXP(const GrXferProcessor&) {}
547     ~GLCustomXP() SK_OVERRIDE {}
548
549     static void GenKey(const GrXferProcessor& proc, const GrGLCaps&, GrProcessorKeyBuilder* b) {
550         uint32_t key = proc.numTextures();
551         SkASSERT(key <= 1);
552         key |= proc.cast<CustomXP>().mode() << 1;
553         b->add32(key);
554     }
555
556 private:
557     void onEmitCode(const EmitArgs& args) SK_OVERRIDE {
558         SkXfermode::Mode mode = args.fXP.cast<CustomXP>().mode();
559         GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
560         const char* dstColor = fsBuilder->dstColor();
561
562         emit_custom_xfermode_code(mode, fsBuilder, args.fOutputPrimary, args.fInputColor, dstColor);
563
564         fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
565                                args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage,
566                                args.fInputCoverage, dstColor);
567     }
568
569     void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {}
570
571     typedef GrGLFragmentProcessor INHERITED;
572 };
573
574 ///////////////////////////////////////////////////////////////////////////////
575
576 CustomXP::CustomXP(SkXfermode::Mode mode, const GrDeviceCoordTexture* dstCopy,
577                    bool willReadDstColor)
578     : INHERITED(dstCopy, willReadDstColor), fMode(mode) {
579     this->initClassID<CustomXP>();
580 }
581
582 void CustomXP::onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const {
583     GLCustomXP::GenKey(*this, caps, b);
584 }
585
586 GrGLXferProcessor* CustomXP::createGLInstance() const {
587     return SkNEW_ARGS(GLCustomXP, (*this));
588 }
589
590 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
591     const CustomXP& s = other.cast<CustomXP>();
592     return fMode == s.fMode;
593 }
594
595 GrXferProcessor::OptFlags CustomXP::getOptimizations(const GrProcOptInfo& colorPOI,
596                                                        const GrProcOptInfo& coveragePOI,
597                                                        bool doesStencilWrite,
598                                                        GrColor* overrideColor,
599                                                        const GrDrawTargetCaps& caps) {
600    return GrXferProcessor::kNone_Opt;
601 }
602
603 ///////////////////////////////////////////////////////////////////////////////
604
605 GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode)
606     : fMode(mode) {
607     this->initClassID<GrCustomXPFactory>();
608 }
609
610 GrXferProcessor*
611 GrCustomXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI,
612                                          const GrProcOptInfo& coveragePOI,
613                                          const GrDeviceCoordTexture* dstCopy) const {
614     return CustomXP::Create(fMode, dstCopy, this->willReadDstColor(colorPOI, coveragePOI));
615 }
616
617
618 void GrCustomXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
619                                                const GrProcOptInfo& coveragePOI,
620                                                GrXPFactory::InvariantOutput* output) const {
621     output->fWillBlendWithDst = true;
622     output->fBlendedColorFlags = 0;
623 }
624
625 GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory);
626 GrXPFactory* GrCustomXPFactory::TestCreate(SkRandom* rand,
627                                            GrContext*,
628                                            const GrDrawTargetCaps&,
629                                            GrTexture*[]) {
630     int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
631
632     return SkNEW_ARGS(GrCustomXPFactory, (static_cast<SkXfermode::Mode>(mode)));
633 }
634