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/GrXfermodeFragmentProcessor.h"
9 
10 #include "GrFragmentProcessor.h"
11 #include "effects/GrConstColorProcessor.h"
12 #include "glsl/GrGLSLFragmentProcessor.h"
13 #include "glsl/GrGLSLBlend.h"
14 #include "glsl/GrGLSLFragmentShaderBuilder.h"
15 #include "SkGr.h"
16 
17 // Some of the cpu implementations of blend modes differ too much from the GPU enough that
18 // we can't use the cpu implementation to implement constantOutputForConstantInput.
does_cpu_blend_impl_match_gpu(SkBlendMode mode)19 static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) {
20     // The non-seperable modes differ too much. So does SoftLight. ColorBurn differs too much on our
21     // test iOS device (but we just disable it across the aboard since it may happen on untested
22     // GPUs).
23     return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
24            mode != SkBlendMode::kColorBurn;
25 }
26 
27 //////////////////////////////////////////////////////////////////////////////
28 
29 class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
30 public:
ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src,sk_sp<GrFragmentProcessor> dst,SkBlendMode mode)31     ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst,
32                                 SkBlendMode mode)
33             : INHERITED(OptFlags(src.get(), dst.get(), mode)), fMode(mode) {
34         this->initClassID<ComposeTwoFragmentProcessor>();
35         SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
36         SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
37         SkASSERT(0 == shaderAChildIndex);
38         SkASSERT(1 == shaderBChildIndex);
39     }
40 
name() const41     const char* name() const override { return "ComposeTwo"; }
42 
dumpInfo() const43     SkString dumpInfo() const override {
44         SkString str;
45 
46         str.appendf("Mode: %s", SkBlendMode_Name(fMode));
47 
48         for (int i = 0; i < this->numChildProcessors(); ++i) {
49             str.appendf(" [%s %s]",
50                         this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
51         }
52         return str;
53     }
54 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const55     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
56         b->add32((int)fMode);
57     }
58 
getMode() const59     SkBlendMode getMode() const { return fMode; }
60 
61 private:
OptFlags(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkBlendMode mode)62     static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
63                                       const GrFragmentProcessor* dst, SkBlendMode mode) {
64         OptimizationFlags flags;
65         switch (mode) {
66             case SkBlendMode::kClear:
67             case SkBlendMode::kSrc:
68             case SkBlendMode::kDst:
69                 SkFAIL("Should never create clear, src, or dst compose two FP.");
70                 flags = kNone_OptimizationFlags;
71                 break;
72 
73             // Produces opaque if both src and dst are opaque.
74             case SkBlendMode::kSrcIn:
75             case SkBlendMode::kDstIn:
76             case SkBlendMode::kModulate:
77                 flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput()
78                                 ? kPreservesOpaqueInput_OptimizationFlag
79                                 : kNone_OptimizationFlags;
80                 break;
81 
82             // Produces zero when both are opaque, indeterminate if one is opaque.
83             case SkBlendMode::kSrcOut:
84             case SkBlendMode::kDstOut:
85             case SkBlendMode::kXor:
86                 flags = kNone_OptimizationFlags;
87                 break;
88 
89             // Is opaque if the dst is opaque.
90             case SkBlendMode::kSrcATop:
91                 flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
92                                                     : kNone_OptimizationFlags;
93                 break;
94 
95             // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
96             case SkBlendMode::kDstATop:
97             case SkBlendMode::kScreen:
98                 flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
99                                                     : kNone_OptimizationFlags;
100                 break;
101 
102             // These modes are all opaque if either src or dst is opaque. All the advanced modes
103             // compute alpha as src-over.
104             case SkBlendMode::kSrcOver:
105             case SkBlendMode::kDstOver:
106             case SkBlendMode::kPlus:
107             case SkBlendMode::kOverlay:
108             case SkBlendMode::kDarken:
109             case SkBlendMode::kLighten:
110             case SkBlendMode::kColorDodge:
111             case SkBlendMode::kColorBurn:
112             case SkBlendMode::kHardLight:
113             case SkBlendMode::kSoftLight:
114             case SkBlendMode::kDifference:
115             case SkBlendMode::kExclusion:
116             case SkBlendMode::kMultiply:
117             case SkBlendMode::kHue:
118             case SkBlendMode::kSaturation:
119             case SkBlendMode::kColor:
120             case SkBlendMode::kLuminosity:
121                 flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput()
122                                 ? kPreservesOpaqueInput_OptimizationFlag
123                                 : kNone_OptimizationFlags;
124                 break;
125         }
126         if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() &&
127             dst->hasConstantOutputForConstantInput()) {
128             flags |= kConstantOutputForConstantInput_OptimizationFlag;
129         }
130         return flags;
131     }
132 
onIsEqual(const GrFragmentProcessor & other) const133     bool onIsEqual(const GrFragmentProcessor& other) const override {
134         const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
135         return fMode == cs.fMode;
136     }
137 
constantOutputForConstantInput(GrColor4f input) const138     GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
139         float alpha = input.fRGBA[3];
140         input = input.opaque();
141         GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
142         GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
143         SkPM4f src = GrColor4fToSkPM4f(srcColor);
144         SkPM4f dst = GrColor4fToSkPM4f(dstColor);
145         auto proc = SkXfermode::GetProc4f(fMode);
146         return SkPM4fToGrColor4f(proc(src, dst)).mulByScalar(alpha);
147     }
148 
149     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
150 
151     SkBlendMode fMode;
152 
153     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
154 
155     typedef GrFragmentProcessor INHERITED;
156 };
157 
158 /////////////////////////////////////////////////////////////////////
159 
160 class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
161 public:
162     void emitCode(EmitArgs&) override;
163 
164 private:
165     typedef GrGLSLFragmentProcessor INHERITED;
166 };
167 
168 /////////////////////////////////////////////////////////////////////
169 
170 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
171 
172 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)173 sk_sp<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
174     // Create two random frag procs.
175     sk_sp<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d));
176     sk_sp<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d));
177 
178     SkBlendMode mode;
179     do {
180         mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
181     } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
182     return sk_sp<GrFragmentProcessor>(
183         new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode));
184 }
185 #endif
186 
onCreateGLSLInstance() const187 GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
188     return new GLComposeTwoFragmentProcessor;
189 }
190 
191 /////////////////////////////////////////////////////////////////////
192 
emitCode(EmitArgs & args)193 void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
194 
195     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
196     const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
197 
198     const char* inputColor = nullptr;
199     if (args.fInputColor) {
200         inputColor = "inputColor";
201         fragBuilder->codeAppendf("vec4 inputColor = vec4(%s.rgb, 1.0);", args.fInputColor);
202     }
203 
204     // declare outputColor and emit the code for each of the two children
205     SkString srcColor("xfer_src");
206     this->emitChild(0, inputColor, &srcColor, args);
207 
208     SkString dstColor("xfer_dst");
209     this->emitChild(1, inputColor, &dstColor, args);
210 
211     // emit blend code
212     SkBlendMode mode = cs.getMode();
213     fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
214     GrGLSLBlend::AppendMode(fragBuilder,
215                             srcColor.c_str(),
216                             dstColor.c_str(),
217                             args.fOutputColor,
218                             mode);
219 
220     // re-multiply the output color by the input color's alpha
221     if (args.fInputColor) {
222         fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
223     }
224 }
225 
MakeFromTwoProcessors(sk_sp<GrFragmentProcessor> src,sk_sp<GrFragmentProcessor> dst,SkBlendMode mode)226 sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors(
227          sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
228     switch (mode) {
229         case SkBlendMode::kClear:
230             return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
231                                                GrConstColorProcessor::kIgnore_InputMode);
232         case SkBlendMode::kSrc:
233             return src;
234         case SkBlendMode::kDst:
235             return dst;
236         default:
237             return sk_sp<GrFragmentProcessor>(
238                 new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), mode));
239     }
240 }
241 
242 //////////////////////////////////////////////////////////////////////////////
243 
244 class ComposeOneFragmentProcessor : public GrFragmentProcessor {
245 public:
246     enum Child {
247         kDst_Child,
248         kSrc_Child,
249     };
250 
ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> fp,SkBlendMode mode,Child child)251     ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> fp, SkBlendMode mode, Child child)
252             : INHERITED(OptFlags(fp.get(), mode, child)), fMode(mode), fChild(child) {
253         this->initClassID<ComposeOneFragmentProcessor>();
254         SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp));
255         SkASSERT(0 == dstIndex);
256     }
257 
name() const258     const char* name() const override { return "ComposeOne"; }
259 
dumpInfo() const260     SkString dumpInfo() const override {
261         SkString str;
262 
263         str.appendf("Mode: %s, Child: %s",
264                     SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src");
265 
266         for (int i = 0; i < this->numChildProcessors(); ++i) {
267             str.appendf(" [%s %s]",
268                         this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
269         }
270         return str;
271     }
272 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const273     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
274         GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode);
275         b->add32((int)fMode | (fChild << 16));
276     }
277 
mode() const278     SkBlendMode mode() const { return fMode; }
279 
child() const280     Child child() const { return fChild; }
281 
282 private:
OptFlags(const GrFragmentProcessor * fp,SkBlendMode mode,Child child)283     OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) {
284         OptimizationFlags flags;
285         switch (mode) {
286             case SkBlendMode::kClear:
287                 SkFAIL("Should never create clear compose one FP.");
288                 flags = kNone_OptimizationFlags;
289                 break;
290 
291             case SkBlendMode::kSrc:
292                 SkASSERT(child == kSrc_Child);
293                 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
294                                                    : kNone_OptimizationFlags;
295                 break;
296 
297             case SkBlendMode::kDst:
298                 SkASSERT(child == kDst_Child);
299                 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
300                                                    : kNone_OptimizationFlags;
301                 break;
302 
303             // Produces opaque if both src and dst are opaque. These also will modulate the child's
304             // output by either the input color or alpha. However, if the child is not compatible
305             // with the coverage as alpha then it may produce a color that is not valid premul.
306             case SkBlendMode::kSrcIn:
307             case SkBlendMode::kDstIn:
308             case SkBlendMode::kModulate:
309                 if (fp->compatibleWithCoverageAsAlpha()) {
310                     if (fp->preservesOpaqueInput()) {
311                         flags = kPreservesOpaqueInput_OptimizationFlag |
312                                 kCompatibleWithCoverageAsAlpha_OptimizationFlag;
313                     } else {
314                         flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
315                     }
316                 } else {
317                     flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
318                                                        : kNone_OptimizationFlags;
319                 }
320                 break;
321 
322             // Produces zero when both are opaque, indeterminate if one is opaque.
323             case SkBlendMode::kSrcOut:
324             case SkBlendMode::kDstOut:
325             case SkBlendMode::kXor:
326                 flags = kNone_OptimizationFlags;
327                 break;
328 
329             // Is opaque if the dst is opaque.
330             case SkBlendMode::kSrcATop:
331                 if (child == kDst_Child) {
332                     flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
333                                                        : kNone_OptimizationFlags;
334                 } else {
335                     flags = kPreservesOpaqueInput_OptimizationFlag;
336                 }
337                 break;
338 
339             // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
340             case SkBlendMode::kDstATop:
341             case SkBlendMode::kScreen:
342                 if (child == kSrc_Child) {
343                     flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
344                                                        : kNone_OptimizationFlags;
345                 } else {
346                     flags = kPreservesOpaqueInput_OptimizationFlag;
347                 }
348                 break;
349 
350             // These modes are all opaque if either src or dst is opaque. All the advanced modes
351             // compute alpha as src-over.
352             case SkBlendMode::kSrcOver:
353             case SkBlendMode::kDstOver:
354             case SkBlendMode::kPlus:
355             case SkBlendMode::kOverlay:
356             case SkBlendMode::kDarken:
357             case SkBlendMode::kLighten:
358             case SkBlendMode::kColorDodge:
359             case SkBlendMode::kColorBurn:
360             case SkBlendMode::kHardLight:
361             case SkBlendMode::kSoftLight:
362             case SkBlendMode::kDifference:
363             case SkBlendMode::kExclusion:
364             case SkBlendMode::kMultiply:
365             case SkBlendMode::kHue:
366             case SkBlendMode::kSaturation:
367             case SkBlendMode::kColor:
368             case SkBlendMode::kLuminosity:
369                 flags = kPreservesOpaqueInput_OptimizationFlag;
370                 break;
371         }
372         if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) {
373             flags |= kConstantOutputForConstantInput_OptimizationFlag;
374         }
375         return flags;
376     }
377 
onIsEqual(const GrFragmentProcessor & that) const378     bool onIsEqual(const GrFragmentProcessor& that) const override {
379         return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
380     }
381 
constantOutputForConstantInput(GrColor4f inputColor) const382     GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
383         GrColor4f childColor =
384                 ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
385         SkPM4f src, dst;
386         if (kSrc_Child == fChild) {
387             src = GrColor4fToSkPM4f(childColor);
388             dst = GrColor4fToSkPM4f(inputColor);
389         } else {
390             src = GrColor4fToSkPM4f(inputColor);
391             dst = GrColor4fToSkPM4f(childColor);
392         }
393         auto proc = SkXfermode::GetProc4f(fMode);
394         return SkPM4fToGrColor4f(proc(src, dst));
395     }
396 
397 private:
398     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
399 
400     SkBlendMode fMode;
401     Child       fChild;
402 
403     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
404 
405     typedef GrFragmentProcessor INHERITED;
406 };
407 
408 //////////////////////////////////////////////////////////////////////////////
409 
410 class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
411 public:
emitCode(EmitArgs & args)412     void emitCode(EmitArgs& args) override {
413         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
414         SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
415         ComposeOneFragmentProcessor::Child child =
416             args.fFp.cast<ComposeOneFragmentProcessor>().child();
417         SkString childColor("child");
418         this->emitChild(0, nullptr, &childColor, args);
419 
420         const char* inputColor = args.fInputColor;
421         // We don't try to optimize for this case at all
422         if (!inputColor) {
423             fragBuilder->codeAppendf("const vec4 ones = vec4(1);");
424             inputColor = "ones";
425         }
426 
427         // emit blend code
428         fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
429         const char* childStr = childColor.c_str();
430         if (ComposeOneFragmentProcessor::kDst_Child == child) {
431             GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode);
432         } else {
433             GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode);
434         }
435     }
436 
437 private:
438     typedef GrGLSLFragmentProcessor INHERITED;
439 };
440 
441 /////////////////////////////////////////////////////////////////////
442 
443 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
444 
445 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)446 sk_sp<GrFragmentProcessor> ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
447     // Create one random frag procs.
448     // For now, we'll prevent either children from being a shader with children to prevent the
449     // possibility of an arbitrarily large tree of procs.
450     sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
451     SkBlendMode mode;
452     ComposeOneFragmentProcessor::Child child;
453     do {
454         mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
455         child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child;
456     } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) ||
457              (SkBlendMode::kSrc == mode && child == kDst_Child));
458     return sk_sp<GrFragmentProcessor>(new ComposeOneFragmentProcessor(std::move(dst), mode, child));
459 }
460 #endif
461 
onCreateGLSLInstance() const462 GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
463     return new GLComposeOneFragmentProcessor;
464 }
465 
466 //////////////////////////////////////////////////////////////////////////////
467 
468 // It may seems as though when the input FP is the dst and the mode is kDst (or same for src/kSrc)
469 // that these factories could simply return the input FP. However, that doesn't have quite
470 // the same effect as the returned compose FP will replace the FP's input with solid white and
471 // ignore the original input. This could be implemented as:
472 // RunInSeries(ConstColor(GrColor_WHITE, kIgnoreInput), inputFP).
473 
MakeFromDstProcessor(sk_sp<GrFragmentProcessor> dst,SkBlendMode mode)474 sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor(
475     sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
476     switch (mode) {
477         case SkBlendMode::kClear:
478             return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
479                                                GrConstColorProcessor::kIgnore_InputMode);
480         case SkBlendMode::kSrc:
481             return nullptr;
482         default:
483             return sk_sp<GrFragmentProcessor>(
484                 new ComposeOneFragmentProcessor(std::move(dst), mode,
485                                                 ComposeOneFragmentProcessor::kDst_Child));
486     }
487 }
488 
MakeFromSrcProcessor(sk_sp<GrFragmentProcessor> src,SkBlendMode mode)489 sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor(
490     sk_sp<GrFragmentProcessor> src, SkBlendMode mode) {
491     switch (mode) {
492         case SkBlendMode::kClear:
493             return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
494                                                GrConstColorProcessor::kIgnore_InputMode);
495         case SkBlendMode::kDst:
496             return nullptr;
497         default:
498             return sk_sp<GrFragmentProcessor>(
499                 new ComposeOneFragmentProcessor(std::move(src), mode,
500                                                 ComposeOneFragmentProcessor::kSrc_Child));
501     }
502 }
503