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