Line data Source code
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.
19 0 : 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 0 : return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
24 0 : mode != SkBlendMode::kColorBurn;
25 : }
26 :
27 : //////////////////////////////////////////////////////////////////////////////
28 :
29 0 : class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
30 : public:
31 0 : ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst,
32 : SkBlendMode mode)
33 0 : : INHERITED(OptFlags(src.get(), dst.get(), mode)), fMode(mode) {
34 0 : this->initClassID<ComposeTwoFragmentProcessor>();
35 0 : SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
36 0 : SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
37 0 : SkASSERT(0 == shaderAChildIndex);
38 0 : SkASSERT(1 == shaderBChildIndex);
39 0 : }
40 :
41 0 : const char* name() const override { return "ComposeTwo"; }
42 :
43 0 : SkString dumpInfo() const override {
44 0 : SkString str;
45 :
46 0 : str.appendf("Mode: %s", SkBlendMode_Name(fMode));
47 :
48 0 : for (int i = 0; i < this->numChildProcessors(); ++i) {
49 0 : str.appendf(" [%s %s]",
50 0 : this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
51 : }
52 0 : return str;
53 : }
54 :
55 0 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
56 0 : b->add32((int)fMode);
57 0 : }
58 :
59 0 : SkBlendMode getMode() const { return fMode; }
60 :
61 : private:
62 0 : static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
63 : const GrFragmentProcessor* dst, SkBlendMode mode) {
64 : OptimizationFlags flags;
65 0 : switch (mode) {
66 : case SkBlendMode::kClear:
67 : case SkBlendMode::kSrc:
68 : case SkBlendMode::kDst:
69 0 : SkFAIL("Should never create clear, src, or dst compose two FP.");
70 0 : flags = kNone_OptimizationFlags;
71 0 : 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 0 : flags = src->preservesOpaqueInput() && dst->preservesOpaqueInput()
78 0 : ? kPreservesOpaqueInput_OptimizationFlag
79 : : kNone_OptimizationFlags;
80 0 : 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 0 : flags = kNone_OptimizationFlags;
87 0 : break;
88 :
89 : // Is opaque if the dst is opaque.
90 : case SkBlendMode::kSrcATop:
91 0 : flags = dst->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
92 : : kNone_OptimizationFlags;
93 0 : 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 0 : flags = src->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
99 : : kNone_OptimizationFlags;
100 0 : 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 0 : flags = src->preservesOpaqueInput() || dst->preservesOpaqueInput()
122 0 : ? kPreservesOpaqueInput_OptimizationFlag
123 : : kNone_OptimizationFlags;
124 0 : break;
125 : }
126 0 : if (does_cpu_blend_impl_match_gpu(mode) && src->hasConstantOutputForConstantInput() &&
127 0 : dst->hasConstantOutputForConstantInput()) {
128 0 : flags |= kConstantOutputForConstantInput_OptimizationFlag;
129 : }
130 0 : return flags;
131 : }
132 :
133 0 : bool onIsEqual(const GrFragmentProcessor& other) const override {
134 0 : const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
135 0 : return fMode == cs.fMode;
136 : }
137 :
138 0 : GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
139 0 : float alpha = input.fRGBA[3];
140 0 : input = input.opaque();
141 0 : GrColor4f srcColor = ConstantOutputForConstantInput(this->childProcessor(0), input);
142 0 : GrColor4f dstColor = ConstantOutputForConstantInput(this->childProcessor(1), input);
143 0 : SkPM4f src = GrColor4fToSkPM4f(srcColor);
144 0 : SkPM4f dst = GrColor4fToSkPM4f(dstColor);
145 0 : auto proc = SkXfermode::GetProc4f(fMode);
146 0 : 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 0 : 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
173 0 : sk_sp<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
174 : // Create two random frag procs.
175 0 : sk_sp<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d));
176 0 : sk_sp<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d));
177 :
178 : SkBlendMode mode;
179 0 : do {
180 0 : mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
181 0 : } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
182 : return sk_sp<GrFragmentProcessor>(
183 0 : new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode));
184 : }
185 : #endif
186 :
187 0 : GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
188 0 : return new GLComposeTwoFragmentProcessor;
189 : }
190 :
191 : /////////////////////////////////////////////////////////////////////
192 :
193 0 : void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
194 :
195 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
196 0 : const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
197 :
198 0 : const char* inputColor = nullptr;
199 0 : if (args.fInputColor) {
200 0 : inputColor = "inputColor";
201 0 : 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 0 : SkString srcColor("xfer_src");
206 0 : this->emitChild(0, inputColor, &srcColor, args);
207 :
208 0 : SkString dstColor("xfer_dst");
209 0 : this->emitChild(1, inputColor, &dstColor, args);
210 :
211 : // emit blend code
212 0 : SkBlendMode mode = cs.getMode();
213 0 : fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
214 0 : GrGLSLBlend::AppendMode(fragBuilder,
215 : srcColor.c_str(),
216 : dstColor.c_str(),
217 : args.fOutputColor,
218 0 : mode);
219 :
220 : // re-multiply the output color by the input color's alpha
221 0 : if (args.fInputColor) {
222 0 : fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
223 : }
224 0 : }
225 :
226 0 : sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors(
227 : sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
228 0 : switch (mode) {
229 : case SkBlendMode::kClear:
230 : return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
231 0 : GrConstColorProcessor::kIgnore_InputMode);
232 : case SkBlendMode::kSrc:
233 0 : return src;
234 : case SkBlendMode::kDst:
235 0 : return dst;
236 : default:
237 : return sk_sp<GrFragmentProcessor>(
238 0 : new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), mode));
239 : }
240 : }
241 :
242 : //////////////////////////////////////////////////////////////////////////////
243 :
244 0 : class ComposeOneFragmentProcessor : public GrFragmentProcessor {
245 : public:
246 : enum Child {
247 : kDst_Child,
248 : kSrc_Child,
249 : };
250 :
251 0 : ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> fp, SkBlendMode mode, Child child)
252 0 : : INHERITED(OptFlags(fp.get(), mode, child)), fMode(mode), fChild(child) {
253 0 : this->initClassID<ComposeOneFragmentProcessor>();
254 0 : SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp));
255 0 : SkASSERT(0 == dstIndex);
256 0 : }
257 :
258 0 : const char* name() const override { return "ComposeOne"; }
259 :
260 0 : SkString dumpInfo() const override {
261 0 : SkString str;
262 :
263 0 : str.appendf("Mode: %s, Child: %s",
264 0 : SkBlendMode_Name(fMode), kDst_Child == fChild ? "Dst" : "Src");
265 :
266 0 : for (int i = 0; i < this->numChildProcessors(); ++i) {
267 0 : str.appendf(" [%s %s]",
268 0 : this->childProcessor(i).name(), this->childProcessor(i).dumpInfo().c_str());
269 : }
270 0 : return str;
271 : }
272 :
273 0 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
274 : GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode);
275 0 : b->add32((int)fMode | (fChild << 16));
276 0 : }
277 :
278 0 : SkBlendMode mode() const { return fMode; }
279 :
280 0 : Child child() const { return fChild; }
281 :
282 : private:
283 0 : OptimizationFlags OptFlags(const GrFragmentProcessor* fp, SkBlendMode mode, Child child) {
284 : OptimizationFlags flags;
285 0 : switch (mode) {
286 : case SkBlendMode::kClear:
287 0 : SkFAIL("Should never create clear compose one FP.");
288 0 : flags = kNone_OptimizationFlags;
289 0 : break;
290 :
291 : case SkBlendMode::kSrc:
292 0 : SkASSERT(child == kSrc_Child);
293 0 : flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
294 : : kNone_OptimizationFlags;
295 0 : break;
296 :
297 : case SkBlendMode::kDst:
298 0 : SkASSERT(child == kDst_Child);
299 0 : flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
300 : : kNone_OptimizationFlags;
301 0 : 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 0 : if (fp->compatibleWithCoverageAsAlpha()) {
310 0 : if (fp->preservesOpaqueInput()) {
311 0 : flags = kPreservesOpaqueInput_OptimizationFlag |
312 : kCompatibleWithCoverageAsAlpha_OptimizationFlag;
313 : } else {
314 0 : flags = kCompatibleWithCoverageAsAlpha_OptimizationFlag;
315 : }
316 : } else {
317 0 : flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
318 : : kNone_OptimizationFlags;
319 : }
320 0 : 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 0 : flags = kNone_OptimizationFlags;
327 0 : break;
328 :
329 : // Is opaque if the dst is opaque.
330 : case SkBlendMode::kSrcATop:
331 0 : if (child == kDst_Child) {
332 0 : flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
333 : : kNone_OptimizationFlags;
334 : } else {
335 0 : flags = kPreservesOpaqueInput_OptimizationFlag;
336 : }
337 0 : 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 0 : if (child == kSrc_Child) {
343 0 : flags = fp->preservesOpaqueInput() ? kPreservesOpaqueInput_OptimizationFlag
344 : : kNone_OptimizationFlags;
345 : } else {
346 0 : flags = kPreservesOpaqueInput_OptimizationFlag;
347 : }
348 0 : 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 0 : flags = kPreservesOpaqueInput_OptimizationFlag;
370 0 : break;
371 : }
372 0 : if (does_cpu_blend_impl_match_gpu(mode) && fp->hasConstantOutputForConstantInput()) {
373 0 : flags |= kConstantOutputForConstantInput_OptimizationFlag;
374 : }
375 0 : return flags;
376 : }
377 :
378 0 : bool onIsEqual(const GrFragmentProcessor& that) const override {
379 0 : return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
380 : }
381 :
382 0 : GrColor4f constantOutputForConstantInput(GrColor4f inputColor) const override {
383 : GrColor4f childColor =
384 0 : ConstantOutputForConstantInput(this->childProcessor(0), GrColor4f::OpaqueWhite());
385 : SkPM4f src, dst;
386 0 : if (kSrc_Child == fChild) {
387 0 : src = GrColor4fToSkPM4f(childColor);
388 0 : dst = GrColor4fToSkPM4f(inputColor);
389 : } else {
390 0 : src = GrColor4fToSkPM4f(inputColor);
391 0 : dst = GrColor4fToSkPM4f(childColor);
392 : }
393 0 : auto proc = SkXfermode::GetProc4f(fMode);
394 0 : 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 0 : class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
411 : public:
412 0 : void emitCode(EmitArgs& args) override {
413 0 : GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
414 0 : SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
415 : ComposeOneFragmentProcessor::Child child =
416 0 : args.fFp.cast<ComposeOneFragmentProcessor>().child();
417 0 : SkString childColor("child");
418 0 : this->emitChild(0, nullptr, &childColor, args);
419 :
420 0 : const char* inputColor = args.fInputColor;
421 : // We don't try to optimize for this case at all
422 0 : if (!inputColor) {
423 0 : fragBuilder->codeAppendf("const vec4 ones = vec4(1);");
424 0 : inputColor = "ones";
425 : }
426 :
427 : // emit blend code
428 0 : fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
429 0 : const char* childStr = childColor.c_str();
430 0 : if (ComposeOneFragmentProcessor::kDst_Child == child) {
431 0 : GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode);
432 : } else {
433 0 : GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode);
434 : }
435 0 : }
436 :
437 : private:
438 : typedef GrGLSLFragmentProcessor INHERITED;
439 : };
440 :
441 : /////////////////////////////////////////////////////////////////////
442 :
443 : GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
444 :
445 : #if GR_TEST_UTILS
446 0 : 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 0 : sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
451 : SkBlendMode mode;
452 : ComposeOneFragmentProcessor::Child child;
453 0 : do {
454 0 : mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
455 0 : child = d->fRandom->nextBool() ? kDst_Child : kSrc_Child;
456 0 : } while (SkBlendMode::kClear == mode || (SkBlendMode::kDst == mode && child == kSrc_Child) ||
457 0 : (SkBlendMode::kSrc == mode && child == kDst_Child));
458 0 : return sk_sp<GrFragmentProcessor>(new ComposeOneFragmentProcessor(std::move(dst), mode, child));
459 : }
460 : #endif
461 :
462 0 : GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
463 0 : 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 :
474 0 : sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor(
475 : sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
476 0 : switch (mode) {
477 : case SkBlendMode::kClear:
478 : return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
479 0 : GrConstColorProcessor::kIgnore_InputMode);
480 : case SkBlendMode::kSrc:
481 0 : return nullptr;
482 : default:
483 : return sk_sp<GrFragmentProcessor>(
484 0 : new ComposeOneFragmentProcessor(std::move(dst), mode,
485 0 : ComposeOneFragmentProcessor::kDst_Child));
486 : }
487 : }
488 :
489 0 : sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor(
490 : sk_sp<GrFragmentProcessor> src, SkBlendMode mode) {
491 0 : switch (mode) {
492 : case SkBlendMode::kClear:
493 : return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
494 0 : GrConstColorProcessor::kIgnore_InputMode);
495 : case SkBlendMode::kDst:
496 0 : return nullptr;
497 : default:
498 : return sk_sp<GrFragmentProcessor>(
499 0 : new ComposeOneFragmentProcessor(std::move(src), mode,
500 0 : ComposeOneFragmentProcessor::kSrc_Child));
501 : }
502 : }
|