blob: dde383ed45b2324f14ed391db6da42baf27a2bce [file] [log] [blame]
wangyix809e5af2015-09-09 12:58:32 -07001/*
Brian Salomona12c1532017-02-13 12:41:44 -05002 * 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 */
wangyix809e5af2015-09-09 12:58:32 -07007
Robert Phillips54cbcd72017-04-20 17:20:24 -04008#include "GrXfermodeFragmentProcessor.h"
wangyix809e5af2015-09-09 12:58:32 -07009
Robert Phillips54cbcd72017-04-20 17:20:24 -040010#include "GrConstColorProcessor.h"
wangyix809e5af2015-09-09 12:58:32 -070011#include "GrFragmentProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080012#include "glsl/GrGLSLFragmentProcessor.h"
13#include "glsl/GrGLSLBlend.h"
egdaniel2d721d32015-11-11 13:06:05 -080014#include "glsl/GrGLSLFragmentShaderBuilder.h"
Brian Osman3b655982017-03-07 16:58:08 -050015#include "SkGr.h"
Mike Reed6b3542a2017-06-06 10:41:18 -040016#include "SkXfermodePriv.h"
wangyix809e5af2015-09-09 12:58:32 -070017
Brian Salomon246a3c22017-02-10 16:16:21 -050018// Some of the cpu implementations of blend modes differ too much from the GPU enough that
19// we can't use the cpu implementation to implement constantOutputForConstantInput.
20static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) {
21 // The non-seperable modes differ too much. So does SoftLight. ColorBurn differs too much on our
22 // test iOS device (but we just disable it across the aboard since it may happen on untested
23 // GPUs).
24 return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
25 mode != SkBlendMode::kColorBurn;
26}
27
28//////////////////////////////////////////////////////////////////////////////
29
bsalomonae4738f2015-09-15 15:33:27 -070030class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
wangyix809e5af2015-09-09 12:58:32 -070031public:
Robert Phillips1c9686b2017-06-30 08:40:28 -040032 static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> src,
33 sk_sp<GrFragmentProcessor> dst,
34 SkBlendMode mode) {
35 return sk_sp<GrFragmentProcessor>(new ComposeTwoFragmentProcessor(std::move(src),
36 std::move(dst), mode));
wangyix809e5af2015-09-09 12:58:32 -070037 }
38
bsalomonae4738f2015-09-15 15:33:27 -070039 const char* name() const override { return "ComposeTwo"; }
wangyix809e5af2015-09-09 12:58:32 -070040
Brian Osmanbd1f76f2017-03-15 11:33:12 -040041 SkString dumpInfo() const override {
42 SkString str;
43
44 str.appendf("Mode: %s", SkBlendMode_Name(fMode));
45
46 for (int i = 0; i < this->numChildProcessors(); ++i) {
47 str.appendf(" [%s %s]",
48 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
49 }
50 return str;
51 }
52
Brian Salomon94efbf52016-11-29 13:43:05 -050053 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
Mike Reed7d954ad2016-10-28 15:42:34 -040054 b->add32((int)fMode);
wangyix809e5af2015-09-09 12:58:32 -070055 }
56
Mike Reed7d954ad2016-10-28 15:42:34 -040057 SkBlendMode getMode() const { return fMode; }
wangyix809e5af2015-09-09 12:58:32 -070058
Brian Salomon587e08f2017-01-27 10:59:27 -050059private:
Robert Phillips1c9686b2017-06-30 08:40:28 -040060 ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src,
61 sk_sp<GrFragmentProcessor> dst,
62 SkBlendMode mode)
63 : INHERITED(OptFlags(src.get(), dst.get(), mode))
64 , fMode(mode) {
65 this->initClassID<ComposeTwoFragmentProcessor>();
66 SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
67 SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
68 SkASSERT(0 == shaderAChildIndex);
69 SkASSERT(1 == shaderBChildIndex);
70 }
71
Brian Salomon587e08f2017-01-27 10:59:27 -050072 static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
73 const GrFragmentProcessor* dst, SkBlendMode mode) {
Brian Salomona12c1532017-02-13 12:41:44 -050074 OptimizationFlags flags;
75 switch (mode) {
76 case SkBlendMode::kClear:
77 case SkBlendMode::kSrc:
78 case SkBlendMode::kDst:
79 SkFAIL("Should never create clear, src, or dst compose two FP.");
80 flags = kNone_OptimizationFlags;
81 break;
82
83 // Produces opaque if both src and dst are opaque.
84 case SkBlendMode::kSrcIn:
85 case SkBlendMode::kDstIn:
86 case SkBlendMode::kModulate:
87 flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput()
88 ? kPreservesOpaqueInput_OptimizationFlag
89 : kNone_OptimizationFlags;
90 break;
91
92 // Produces zero when both are opaque, indeterminate if one is opaque.
93 case SkBlendMode::kSrcOut:
94 case SkBlendMode::kDstOut:
95 case SkBlendMode::kXor:
96 flags = kNone_OptimizationFlags;
97 break;
98
99 // Is opaque if the dst is opaque.
100 case SkBlendMode::kSrcATop:
101 flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
102 : kNone_OptimizationFlags;
103 break;
104
105 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
106 case SkBlendMode::kDstATop:
107 case SkBlendMode::kScreen:
108 flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
109 : kNone_OptimizationFlags;
110 break;
111
112 // These modes are all opaque if either src or dst is opaque. All the advanced modes
113 // compute alpha as src-over.
114 case SkBlendMode::kSrcOver:
115 case SkBlendMode::kDstOver:
116 case SkBlendMode::kPlus:
117 case SkBlendMode::kOverlay:
118 case SkBlendMode::kDarken:
119 case SkBlendMode::kLighten:
120 case SkBlendMode::kColorDodge:
121 case SkBlendMode::kColorBurn:
122 case SkBlendMode::kHardLight:
123 case SkBlendMode::kSoftLight:
124 case SkBlendMode::kDifference:
125 case SkBlendMode::kExclusion:
126 case SkBlendMode::kMultiply:
127 case SkBlendMode::kHue:
128 case SkBlendMode::kSaturation:
129 case SkBlendMode::kColor:
130 case SkBlendMode::kLuminosity:
131 flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput()
132 ? kPreservesOpaqueInput_OptimizationFlag
133 : kNone_OptimizationFlags;
134 break;
135 }
Brian Salomon246a3c22017-02-10 16:16:21 -0500136 if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() &&
137 dst->hasConstantOutputForConstantInput()) {
Brian Salomona12c1532017-02-13 12:41:44 -0500138 flags |= kConstantOutputForConstantInput_OptimizationFlag;
Brian Salomon587e08f2017-01-27 10:59:27 -0500139 }
Brian Salomona12c1532017-02-13 12:41:44 -0500140 return flags;
Brian Salomon587e08f2017-01-27 10:59:27 -0500141 }
142
wangyix809e5af2015-09-09 12:58:32 -0700143 bool onIsEqual(const GrFragmentProcessor& other) const override {
bsalomonae4738f2015-09-15 15:33:27 -0700144 const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
wangyix809e5af2015-09-09 12:58:32 -0700145 return fMode == cs.fMode;
146 }
147
Brian Salomon587e08f2017-01-27 10:59:27 -0500148 GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
149 float alpha = input.fRGBA[3];
150 input = input.opaque();
151 GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
152 GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
153 SkPM4f src = GrColor4fToSkPM4f(srcColor);
154 SkPM4f dst = GrColor4fToSkPM4f(dstColor);
Mike Reedf066ac92017-06-09 14:36:59 -0400155 SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
156 return SkPM4fToGrColor4f(res).mulByScalar(alpha);
Brian Salomon587e08f2017-01-27 10:59:27 -0500157 }
158
egdaniel57d3b032015-11-13 11:57:27 -0800159 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyix809e5af2015-09-09 12:58:32 -0700160
Mike Reed7d954ad2016-10-28 15:42:34 -0400161 SkBlendMode fMode;
wangyix809e5af2015-09-09 12:58:32 -0700162
163 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
164
165 typedef GrFragmentProcessor INHERITED;
166};
167
168/////////////////////////////////////////////////////////////////////
169
egdaniel64c47282015-11-13 06:54:19 -0800170class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
wangyix809e5af2015-09-09 12:58:32 -0700171public:
wangyix809e5af2015-09-09 12:58:32 -0700172 void emitCode(EmitArgs&) override;
173
174private:
egdaniel64c47282015-11-13 06:54:19 -0800175 typedef GrGLSLFragmentProcessor INHERITED;
wangyix809e5af2015-09-09 12:58:32 -0700176};
177
178/////////////////////////////////////////////////////////////////////
179
bsalomonae4738f2015-09-15 15:33:27 -0700180GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
wangyix809e5af2015-09-09 12:58:32 -0700181
Hal Canary6f6961e2017-01-31 13:50:44 -0500182#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700183sk_sp<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
wangyix809e5af2015-09-09 12:58:32 -0700184 // Create two random frag procs.
bungeman06ca8ec2016-06-09 08:01:03 -0700185 sk_sp<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d));
186 sk_sp<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d));
wangyix809e5af2015-09-09 12:58:32 -0700187
Brian Salomona12c1532017-02-13 12:41:44 -0500188 SkBlendMode mode;
189 do {
190 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
191 } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
bungeman06ca8ec2016-06-09 08:01:03 -0700192 return sk_sp<GrFragmentProcessor>(
193 new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode));
wangyix809e5af2015-09-09 12:58:32 -0700194}
Hal Canary6f6961e2017-01-31 13:50:44 -0500195#endif
wangyix809e5af2015-09-09 12:58:32 -0700196
egdaniel57d3b032015-11-13 11:57:27 -0800197GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
robertphillips9cdb9922016-02-03 12:25:40 -0800198 return new GLComposeTwoFragmentProcessor;
wangyix809e5af2015-09-09 12:58:32 -0700199}
200
201/////////////////////////////////////////////////////////////////////
202
bsalomonae4738f2015-09-15 15:33:27 -0700203void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
wangyix809e5af2015-09-09 12:58:32 -0700204
cdalton85285412016-02-18 12:37:07 -0800205 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
bsalomonae4738f2015-09-15 15:33:27 -0700206 const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
wangyix809e5af2015-09-09 12:58:32 -0700207
bsalomonf1b7a1d2015-09-28 06:26:28 -0700208 const char* inputColor = nullptr;
bsalomonb5b60322015-09-14 12:26:33 -0700209 if (args.fInputColor) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700210 inputColor = "inputColor";
egdaniel4ca2e602015-11-18 08:01:26 -0800211 fragBuilder->codeAppendf("vec4 inputColor = vec4(%s.rgb, 1.0);", args.fInputColor);
bsalomonb5b60322015-09-14 12:26:33 -0700212 }
wangyix809e5af2015-09-09 12:58:32 -0700213
214 // declare outputColor and emit the code for each of the two children
ethannicholas22f939e2016-10-13 13:25:34 -0700215 SkString srcColor("xfer_src");
bsalomonf1b7a1d2015-09-28 06:26:28 -0700216 this->emitChild(0, inputColor, &srcColor, args);
wangyix809e5af2015-09-09 12:58:32 -0700217
ethannicholas22f939e2016-10-13 13:25:34 -0700218 SkString dstColor("xfer_dst");
bsalomonf1b7a1d2015-09-28 06:26:28 -0700219 this->emitChild(1, inputColor, &dstColor, args);
wangyix809e5af2015-09-09 12:58:32 -0700220
221 // emit blend code
Mike Reed7d954ad2016-10-28 15:42:34 -0400222 SkBlendMode mode = cs.getMode();
Mike Reedcde90312017-06-07 23:05:45 -0400223 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
egdaniel4ca2e602015-11-18 08:01:26 -0800224 GrGLSLBlend::AppendMode(fragBuilder,
225 srcColor.c_str(),
226 dstColor.c_str(),
227 args.fOutputColor,
228 mode);
wangyix809e5af2015-09-09 12:58:32 -0700229
230 // re-multiply the output color by the input color's alpha
bsalomonf1b7a1d2015-09-28 06:26:28 -0700231 if (args.fInputColor) {
egdaniel4ca2e602015-11-18 08:01:26 -0800232 fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
bsalomonb5b60322015-09-14 12:26:33 -0700233 }
wangyix809e5af2015-09-09 12:58:32 -0700234}
235
bungeman06ca8ec2016-06-09 08:01:03 -0700236sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors(
Mike Reed7d954ad2016-10-28 15:42:34 -0400237 sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
wangyix809e5af2015-09-09 12:58:32 -0700238 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400239 case SkBlendMode::kClear:
Brian Osman618d3042016-10-25 10:51:28 -0400240 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
bungeman06ca8ec2016-06-09 08:01:03 -0700241 GrConstColorProcessor::kIgnore_InputMode);
Mike Reed7d954ad2016-10-28 15:42:34 -0400242 case SkBlendMode::kSrc:
bungeman06ca8ec2016-06-09 08:01:03 -0700243 return src;
Mike Reed7d954ad2016-10-28 15:42:34 -0400244 case SkBlendMode::kDst:
bungeman06ca8ec2016-06-09 08:01:03 -0700245 return dst;
wangyix809e5af2015-09-09 12:58:32 -0700246 default:
Robert Phillips1c9686b2017-06-30 08:40:28 -0400247 return ComposeTwoFragmentProcessor::Make(std::move(src), std::move(dst), mode);
bsalomonae4738f2015-09-15 15:33:27 -0700248 }
249}
250
251//////////////////////////////////////////////////////////////////////////////
252
253class ComposeOneFragmentProcessor : public GrFragmentProcessor {
254public:
255 enum Child {
256 kDst_Child,
257 kSrc_Child,
258 };
259
Robert Phillips1c9686b2017-06-30 08:40:28 -0400260 static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor> fp, SkBlendMode mode,
261 Child child) {
262 if (!fp) {
263 return nullptr;
264 }
265 return sk_sp<GrFragmentProcessor>(new ComposeOneFragmentProcessor(std::move(fp),
266 mode, child));
bsalomonae4738f2015-09-15 15:33:27 -0700267 }
268
269 const char* name() const override { return "ComposeOne"; }
270
robertphillips783a4da2015-11-19 14:00:02 -0800271 SkString dumpInfo() const override {
272 SkString str;
273
Brian Osmanbd1f76f2017-03-15 11:33:12 -0400274 str.appendf("Mode: %s, Child: %s",
275 SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src");
276
robertphillips783a4da2015-11-19 14:00:02 -0800277 for (int i = 0; i < this->numChildProcessors(); ++i) {
Brian Osmanbd1f76f2017-03-15 11:33:12 -0400278 str.appendf(" [%s %s]",
279 this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
robertphillips783a4da2015-11-19 14:00:02 -0800280 }
281 return str;
282 }
283
Brian Salomon94efbf52016-11-29 13:43:05 -0500284 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
Mike Reed7d954ad2016-10-28 15:42:34 -0400285 GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode);
286 b->add32((int)fMode | (fChild << 16));
bsalomonae4738f2015-09-15 15:33:27 -0700287 }
288
Mike Reed7d954ad2016-10-28 15:42:34 -0400289 SkBlendMode mode() const { return fMode; }
bsalomonae4738f2015-09-15 15:33:27 -0700290
291 Child child() const { return fChild; }
292
Brian Salomon587e08f2017-01-27 10:59:27 -0500293private:
Brian Salomona12c1532017-02-13 12:41:44 -0500294 OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) {
295 OptimizationFlags flags;
296 switch (mode) {
297 case SkBlendMode::kClear:
298 SkFAIL("Should never create clear compose one FP.");
299 flags = kNone_OptimizationFlags;
300 break;
301
302 case SkBlendMode::kSrc:
303 SkASSERT(child == kSrc_Child);
304 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
305 : kNone_OptimizationFlags;
306 break;
307
308 case SkBlendMode::kDst:
309 SkASSERT(child == kDst_Child);
310 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
311 : kNone_OptimizationFlags;
312 break;
313
314 // Produces opaque if both src and dst are opaque. These also will modulate the child's
Brian Salomone0265112017-02-21 14:19:07 -0500315 // output by either the input color or alpha. However, if the child is not compatible
316 // with the coverage as alpha then it may produce a color that is not valid premul.
Brian Salomona12c1532017-02-13 12:41:44 -0500317 case SkBlendMode::kSrcIn:
318 case SkBlendMode::kDstIn:
319 case SkBlendMode::kModulate:
Brian Salomone0265112017-02-21 14:19:07 -0500320 if (fp->compatibleWithCoverageAsAlpha()) {
321 if (fp->preservesOpaqueInput()) {
322 flags = kPreservesOpaqueInput_OptimizationFlag |
323 kCompatibleWithCoverageAsAlpha_OptimizationFlag;
324 } else {
325 flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
326 }
Brian Salomonf3b995b2017-02-15 10:22:23 -0500327 } else {
Brian Salomone0265112017-02-21 14:19:07 -0500328 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
329 : kNone_OptimizationFlags;
Brian Salomonf3b995b2017-02-15 10:22:23 -0500330 }
Brian Salomona12c1532017-02-13 12:41:44 -0500331 break;
332
333 // Produces zero when both are opaque, indeterminate if one is opaque.
334 case SkBlendMode::kSrcOut:
335 case SkBlendMode::kDstOut:
336 case SkBlendMode::kXor:
337 flags = kNone_OptimizationFlags;
338 break;
339
340 // Is opaque if the dst is opaque.
341 case SkBlendMode::kSrcATop:
342 if (child == kDst_Child) {
343 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
344 : kNone_OptimizationFlags;
345 } else {
346 flags = kPreservesOpaqueInput_OptimizationFlag;
347 }
348 break;
349
350 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
351 case SkBlendMode::kDstATop:
352 case SkBlendMode::kScreen:
353 if (child == kSrc_Child) {
354 flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
355 : kNone_OptimizationFlags;
356 } else {
357 flags = kPreservesOpaqueInput_OptimizationFlag;
358 }
359 break;
360
361 // These modes are all opaque if either src or dst is opaque. All the advanced modes
362 // compute alpha as src-over.
363 case SkBlendMode::kSrcOver:
364 case SkBlendMode::kDstOver:
365 case SkBlendMode::kPlus:
366 case SkBlendMode::kOverlay:
367 case SkBlendMode::kDarken:
368 case SkBlendMode::kLighten:
369 case SkBlendMode::kColorDodge:
370 case SkBlendMode::kColorBurn:
371 case SkBlendMode::kHardLight:
372 case SkBlendMode::kSoftLight:
373 case SkBlendMode::kDifference:
374 case SkBlendMode::kExclusion:
375 case SkBlendMode::kMultiply:
376 case SkBlendMode::kHue:
377 case SkBlendMode::kSaturation:
378 case SkBlendMode::kColor:
379 case SkBlendMode::kLuminosity:
380 flags = kPreservesOpaqueInput_OptimizationFlag;
381 break;
Brian Salomon587e08f2017-01-27 10:59:27 -0500382 }
Brian Salomona12c1532017-02-13 12:41:44 -0500383 if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) {
384 flags |= kConstantOutputForConstantInput_OptimizationFlag;
385 }
386 return flags;
Brian Salomon587e08f2017-01-27 10:59:27 -0500387 }
388
bsalomonae4738f2015-09-15 15:33:27 -0700389 bool onIsEqual(const GrFragmentProcessor& that) const override {
390 return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
391 }
392
Brian Salomon587e08f2017-01-27 10:59:27 -0500393 GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
394 GrColor4f childColor =
395 ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
396 SkPM4f src, dst;
397 if (kSrc_Child == fChild) {
398 src = GrColor4fToSkPM4f(childColor);
399 dst = GrColor4fToSkPM4f(inputColor);
400 } else {
401 src = GrColor4fToSkPM4f(inputColor);
402 dst = GrColor4fToSkPM4f(childColor);
403 }
Mike Reedf066ac92017-06-09 14:36:59 -0400404 SkPM4f res = SkBlendMode_Apply(fMode, src, dst);
405 return SkPM4fToGrColor4f(res);
Brian Salomon587e08f2017-01-27 10:59:27 -0500406 }
407
bsalomonae4738f2015-09-15 15:33:27 -0700408private:
Robert Phillips1c9686b2017-06-30 08:40:28 -0400409 ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> fp, SkBlendMode mode, Child child)
410 : INHERITED(OptFlags(fp.get(), mode, child))
411 , fMode(mode)
412 , fChild(child) {
413 this->initClassID<ComposeOneFragmentProcessor>();
414 SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp));
415 SkASSERT(0 == dstIndex);
416 }
417
egdaniel57d3b032015-11-13 11:57:27 -0800418 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
bsalomonae4738f2015-09-15 15:33:27 -0700419
Mike Reed7d954ad2016-10-28 15:42:34 -0400420 SkBlendMode fMode;
421 Child fChild;
bsalomonae4738f2015-09-15 15:33:27 -0700422
423 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
424
425 typedef GrFragmentProcessor INHERITED;
426};
427
428//////////////////////////////////////////////////////////////////////////////
429
egdaniel64c47282015-11-13 06:54:19 -0800430class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
bsalomonae4738f2015-09-15 15:33:27 -0700431public:
bsalomonae4738f2015-09-15 15:33:27 -0700432 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800433 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
Mike Reed7d954ad2016-10-28 15:42:34 -0400434 SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
bsalomonae4738f2015-09-15 15:33:27 -0700435 ComposeOneFragmentProcessor::Child child =
436 args.fFp.cast<ComposeOneFragmentProcessor>().child();
bsalomon38ddbad2015-09-24 06:00:00 -0700437 SkString childColor("child");
Ethan Nicholas2983f402017-05-08 09:36:08 -0400438 this->emitChild(0, &childColor, args);
bsalomonae4738f2015-09-15 15:33:27 -0700439
440 const char* inputColor = args.fInputColor;
441 // We don't try to optimize for this case at all
442 if (!inputColor) {
egdaniel4ca2e602015-11-18 08:01:26 -0800443 fragBuilder->codeAppendf("const vec4 ones = vec4(1);");
bsalomonae4738f2015-09-15 15:33:27 -0700444 inputColor = "ones";
445 }
446
447 // emit blend code
Mike Reedcde90312017-06-07 23:05:45 -0400448 fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkBlendMode_Name(mode));
bsalomon38ddbad2015-09-24 06:00:00 -0700449 const char* childStr = childColor.c_str();
bsalomonae4738f2015-09-15 15:33:27 -0700450 if (ComposeOneFragmentProcessor::kDst_Child == child) {
egdaniel4ca2e602015-11-18 08:01:26 -0800451 GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode);
bsalomonae4738f2015-09-15 15:33:27 -0700452 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800453 GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode);
bsalomonae4738f2015-09-15 15:33:27 -0700454 }
bsalomonae4738f2015-09-15 15:33:27 -0700455 }
456
457private:
egdaniel64c47282015-11-13 06:54:19 -0800458 typedef GrGLSLFragmentProcessor INHERITED;
bsalomonae4738f2015-09-15 15:33:27 -0700459};
460
461/////////////////////////////////////////////////////////////////////
462
463GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
464
Hal Canary6f6961e2017-01-31 13:50:44 -0500465#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -0700466sk_sp<GrFragmentProcessor> ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
bsalomonae4738f2015-09-15 15:33:27 -0700467 // Create one random frag procs.
468 // For now, we'll prevent either children from being a shader with children to prevent the
469 // possibility of an arbitrarily large tree of procs.
bungeman06ca8ec2016-06-09 08:01:03 -0700470 sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
Brian Salomona12c1532017-02-13 12:41:44 -0500471 SkBlendMode mode;
472 ComposeOneFragmentProcessor::Child child;
473 do {
474 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
475 child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child;
476 } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) ||
477 (SkBlendMode::kSrc == mode && child == kDst_Child));
bungeman06ca8ec2016-06-09 08:01:03 -0700478 return sk_sp<GrFragmentProcessor>(new ComposeOneFragmentProcessor(std::move(dst), mode, child));
bsalomonae4738f2015-09-15 15:33:27 -0700479}
Hal Canary6f6961e2017-01-31 13:50:44 -0500480#endif
bsalomonae4738f2015-09-15 15:33:27 -0700481
egdaniel57d3b032015-11-13 11:57:27 -0800482GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
robertphillips9cdb9922016-02-03 12:25:40 -0800483 return new GLComposeOneFragmentProcessor;
bsalomonae4738f2015-09-15 15:33:27 -0700484}
485
486//////////////////////////////////////////////////////////////////////////////
487
Brian Salomona12c1532017-02-13 12:41:44 -0500488// It may seems as though when the input FP is the dst and the mode is kDst (or same for src/kSrc)
489// that these factories could simply return the input FP. However, that doesn't have quite
490// the same effect as the returned compose FP will replace the FP's input with solid white and
491// ignore the original input. This could be implemented as:
492// RunInSeries(ConstColor(GrColor_WHITE, kIgnoreInput), inputFP).
493
bungeman06ca8ec2016-06-09 08:01:03 -0700494sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor(
Mike Reed7d954ad2016-10-28 15:42:34 -0400495 sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700496 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400497 case SkBlendMode::kClear:
Brian Osman618d3042016-10-25 10:51:28 -0400498 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Brian Salomona12c1532017-02-13 12:41:44 -0500499 GrConstColorProcessor::kIgnore_InputMode);
Mike Reed7d954ad2016-10-28 15:42:34 -0400500 case SkBlendMode::kSrc:
bsalomonae4738f2015-09-15 15:33:27 -0700501 return nullptr;
502 default:
Robert Phillips1c9686b2017-06-30 08:40:28 -0400503 return ComposeOneFragmentProcessor::Make(std::move(dst), mode,
504 ComposeOneFragmentProcessor::kDst_Child);
bsalomonae4738f2015-09-15 15:33:27 -0700505 }
506}
507
bungeman06ca8ec2016-06-09 08:01:03 -0700508sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor(
Mike Reed7d954ad2016-10-28 15:42:34 -0400509 sk_sp<GrFragmentProcessor> src, SkBlendMode mode) {
bsalomonae4738f2015-09-15 15:33:27 -0700510 switch (mode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400511 case SkBlendMode::kClear:
Brian Osman618d3042016-10-25 10:51:28 -0400512 return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
Brian Salomona12c1532017-02-13 12:41:44 -0500513 GrConstColorProcessor::kIgnore_InputMode);
Mike Reed7d954ad2016-10-28 15:42:34 -0400514 case SkBlendMode::kDst:
bsalomonae4738f2015-09-15 15:33:27 -0700515 return nullptr;
516 default:
Robert Phillips1c9686b2017-06-30 08:40:28 -0400517 return ComposeOneFragmentProcessor::Make(std::move(src), mode,
518 ComposeOneFragmentProcessor::kSrc_Child);
wangyix809e5af2015-09-09 12:58:32 -0700519 }
520}