• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/GrBlendFragmentProcessor.h"
9 
10 #include "src/gpu/GrFragmentProcessor.h"
11 #include "src/gpu/SkGr.h"
12 #include "src/gpu/glsl/GrGLSLBlend.h"
13 #include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
14 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
15 
16 using GrBlendFragmentProcessor::BlendBehavior;
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.
does_cpu_blend_impl_match_gpu(SkBlendMode mode)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 
BlendBehavior_Name(BlendBehavior behavior)28 static const char* BlendBehavior_Name(BlendBehavior behavior) {
29     SkASSERT(unsigned(behavior) <= unsigned(BlendBehavior::kLastBlendBehavior));
30     static constexpr const char* gStrings[] = {
31         "Default",
32         "Compose-One",
33         "Compose-Two",
34         "SkMode",
35     };
36     static_assert(SK_ARRAY_COUNT(gStrings) == size_t(BlendBehavior::kLastBlendBehavior) + 1);
37     return gStrings[int(behavior)];
38 }
39 
40 //////////////////////////////////////////////////////////////////////////////
41 
42 class BlendFragmentProcessor : public GrFragmentProcessor {
43 public:
Make(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode,BlendBehavior behavior)44     static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src,
45                                                      std::unique_ptr<GrFragmentProcessor> dst,
46                                                      SkBlendMode mode, BlendBehavior behavior) {
47         return std::unique_ptr<GrFragmentProcessor>(
48                 new BlendFragmentProcessor(std::move(src), std::move(dst), mode, behavior));
49     }
50 
name() const51     const char* name() const override { return "Blend"; }
52 
53     std::unique_ptr<GrFragmentProcessor> clone() const override;
54 
getMode() const55     SkBlendMode getMode() const { return fMode; }
blendBehavior() const56     BlendBehavior blendBehavior() const { return fBlendBehavior; }
57 
58 private:
BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode,BlendBehavior behavior)59     BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,
60                              std::unique_ptr<GrFragmentProcessor> dst,
61                              SkBlendMode mode, BlendBehavior behavior)
62             : INHERITED(kBlendFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode))
63             , fMode(mode)
64             , fBlendBehavior(behavior) {
65         if (fBlendBehavior == BlendBehavior::kDefault) {
66             fBlendBehavior = (src && dst) ? BlendBehavior::kComposeTwoBehavior
67                                           : BlendBehavior::kComposeOneBehavior;
68         }
69         this->registerChild(std::move(src));
70         this->registerChild(std::move(dst));
71     }
72 
BlendFragmentProcessor(const BlendFragmentProcessor & that)73     BlendFragmentProcessor(const BlendFragmentProcessor& that)
74             : INHERITED(kBlendFragmentProcessor_ClassID, ProcessorOptimizationFlags(&that))
75             , fMode(that.fMode)
76             , fBlendBehavior(that.fBlendBehavior) {
77         this->cloneAndRegisterAllChildProcessors(that);
78     }
79 
80 #if GR_TEST_UTILS
onDumpInfo() const81     SkString onDumpInfo() const override {
82         return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode));
83     }
84 #endif
85 
OptFlags(const GrFragmentProcessor * src,const GrFragmentProcessor * dst,SkBlendMode mode)86     static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
87                                       const GrFragmentProcessor* dst, SkBlendMode mode) {
88         OptimizationFlags flags;
89         switch (mode) {
90             case SkBlendMode::kClear:
91             case SkBlendMode::kSrc:
92             case SkBlendMode::kDst:
93                 SK_ABORT("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'.");
94                 flags = kNone_OptimizationFlags;
95                 break;
96 
97             // Produces opaque if both src and dst are opaque. These also will modulate the child's
98             // output by either the input color or alpha. However, if the child is not compatible
99             // with the coverage as alpha then it may produce a color that is not valid premul.
100             case SkBlendMode::kSrcIn:
101             case SkBlendMode::kDstIn:
102             case SkBlendMode::kModulate:
103                 if (src && dst) {
104                     flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) &
105                             kPreservesOpaqueInput_OptimizationFlag;
106                 } else if (src) {
107                     flags = ProcessorOptimizationFlags(src) &
108                             ~kConstantOutputForConstantInput_OptimizationFlag;
109                 } else if (dst) {
110                     flags = ProcessorOptimizationFlags(dst) &
111                             ~kConstantOutputForConstantInput_OptimizationFlag;
112                 } else {
113                     flags = kNone_OptimizationFlags;
114                 }
115                 break;
116 
117             // Produces zero when both are opaque, indeterminate if one is opaque.
118             case SkBlendMode::kSrcOut:
119             case SkBlendMode::kDstOut:
120             case SkBlendMode::kXor:
121                 flags = kNone_OptimizationFlags;
122                 break;
123 
124             // Is opaque if the dst is opaque.
125             case SkBlendMode::kSrcATop:
126                 flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag;
127                 break;
128 
129             // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
130             case SkBlendMode::kDstATop:
131             case SkBlendMode::kScreen:
132                 flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag;
133                 break;
134 
135             // These modes are all opaque if either src or dst is opaque. All the advanced modes
136             // compute alpha as src-over.
137             case SkBlendMode::kSrcOver:
138             case SkBlendMode::kDstOver:
139             case SkBlendMode::kPlus:
140             case SkBlendMode::kOverlay:
141             case SkBlendMode::kDarken:
142             case SkBlendMode::kLighten:
143             case SkBlendMode::kColorDodge:
144             case SkBlendMode::kColorBurn:
145             case SkBlendMode::kHardLight:
146             case SkBlendMode::kSoftLight:
147             case SkBlendMode::kDifference:
148             case SkBlendMode::kExclusion:
149             case SkBlendMode::kMultiply:
150             case SkBlendMode::kHue:
151             case SkBlendMode::kSaturation:
152             case SkBlendMode::kColor:
153             case SkBlendMode::kLuminosity:
154                 flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) &
155                         kPreservesOpaqueInput_OptimizationFlag;
156                 break;
157         }
158         if (does_cpu_blend_impl_match_gpu(mode) &&
159             (src ? src->hasConstantOutputForConstantInput() : true) &&
160             (dst ? dst->hasConstantOutputForConstantInput() : true)) {
161             flags |= kConstantOutputForConstantInput_OptimizationFlag;
162         }
163         return flags;
164     }
165 
onGetGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const166     void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
167         b->add32((int)fMode);
168     }
169 
onIsEqual(const GrFragmentProcessor & other) const170     bool onIsEqual(const GrFragmentProcessor& other) const override {
171         const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>();
172         return fMode == cs.fMode;
173     }
174 
constantOutputForConstantInput(const SkPMColor4f & input) const175     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
176         const auto* src = this->childProcessor(0);
177         const auto* dst = this->childProcessor(1);
178 
179         switch (fBlendBehavior) {
180             case BlendBehavior::kComposeOneBehavior: {
181                 SkPMColor4f srcColor = src ? ConstantOutputForConstantInput(src, SK_PMColor4fWHITE)
182                                            : input;
183                 SkPMColor4f dstColor = dst ? ConstantOutputForConstantInput(dst, SK_PMColor4fWHITE)
184                                            : input;
185                 return SkBlendMode_Apply(fMode, srcColor, dstColor);
186             }
187 
188             case BlendBehavior::kComposeTwoBehavior: {
189                 SkPMColor4f opaqueInput = { input.fR, input.fG, input.fB, 1 };
190                 SkPMColor4f srcColor = ConstantOutputForConstantInput(src, opaqueInput);
191                 SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, opaqueInput);
192                 SkPMColor4f result = SkBlendMode_Apply(fMode, srcColor, dstColor);
193                 return result * input.fA;
194             }
195 
196             case BlendBehavior::kSkModeBehavior: {
197                 SkPMColor4f srcColor = src ? ConstantOutputForConstantInput(src, SK_PMColor4fWHITE)
198                                            : input;
199                 SkPMColor4f dstColor = dst ? ConstantOutputForConstantInput(dst, input)
200                                            : input;
201                 return SkBlendMode_Apply(fMode, srcColor, dstColor);
202             }
203 
204             default:
205                 SK_ABORT("unrecognized blend behavior");
206                 return input;
207         }
208     }
209 
210     std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
211 
212     SkBlendMode fMode;
213     BlendBehavior fBlendBehavior;
214 
215     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
216 
217     using INHERITED = GrFragmentProcessor;
218 };
219 
220 /////////////////////////////////////////////////////////////////////
221 
222 class GLBlendFragmentProcessor : public GrGLSLFragmentProcessor {
223 public:
224     void emitCode(EmitArgs&) override;
225 
226 private:
227     using INHERITED = GrGLSLFragmentProcessor;
228 };
229 
230 /////////////////////////////////////////////////////////////////////
231 
232 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BlendFragmentProcessor);
233 
234 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)235 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) {
236     // Create one or two random fragment processors.
237     std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d));
238     std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
239     if (d->fRandom->nextBool()) {
240         std::swap(src, dst);
241     }
242 
243     SkBlendMode mode;
244     BlendBehavior behavior;
245     do {
246         mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
247         behavior = static_cast<BlendBehavior>(
248                 d->fRandom->nextRangeU(0, (int)BlendBehavior::kLastBlendBehavior));
249     } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode);
250     return std::unique_ptr<GrFragmentProcessor>(
251             new BlendFragmentProcessor(std::move(src), std::move(dst), mode, behavior));
252 }
253 #endif
254 
clone() const255 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const {
256     return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this));
257 }
258 
onMakeProgramImpl() const259 std::unique_ptr<GrGLSLFragmentProcessor> BlendFragmentProcessor::onMakeProgramImpl() const {
260     return std::make_unique<GLBlendFragmentProcessor>();
261 }
262 
263 /////////////////////////////////////////////////////////////////////
264 
emitCode(EmitArgs & args)265 void GLBlendFragmentProcessor::emitCode(EmitArgs& args) {
266     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
267     const BlendFragmentProcessor& cs = args.fFp.cast<BlendFragmentProcessor>();
268     SkBlendMode mode = cs.getMode();
269     BlendBehavior behavior = cs.blendBehavior();
270 
271     // Load the input color and make an opaque copy if needed.
272     fragBuilder->codeAppendf("// Blend mode: %s (%s behavior)\n",
273                              SkBlendMode_Name(mode), BlendBehavior_Name(behavior));
274 
275     SkString srcColor, dstColor;
276     switch (behavior) {
277         case BlendBehavior::kComposeOneBehavior:
278             // Compose-one operations historically leave the alpha on the input color.
279             srcColor = cs.childProcessor(0) ? this->invokeChild(0, "half4(1)", args)
280                                             : SkString(args.fInputColor);
281             dstColor = cs.childProcessor(1) ? this->invokeChild(1, "half4(1)", args)
282                                             : SkString(args.fInputColor);
283             break;
284 
285         case BlendBehavior::kComposeTwoBehavior:
286             // Compose-two operations historically have forced the input color to opaque.
287             // We're going to re-apply the input color's alpha below, so feed the *unpremul* RGB
288             // to the children, to avoid double-applying alpha.
289             fragBuilder->codeAppendf("half4 inputOpaque = unpremul(%s).rgb1;\n", args.fInputColor);
290             srcColor = this->invokeChild(0, "inputOpaque", args);
291             dstColor = this->invokeChild(1, "inputOpaque", args);
292             break;
293 
294         case BlendBehavior::kSkModeBehavior:
295             // SkModeColorFilter operations act like ComposeOne, but pass the input color to dst.
296             srcColor = cs.childProcessor(0) ? this->invokeChild(0, "half4(1)", args)
297                                             : SkString(args.fInputColor);
298             dstColor = cs.childProcessor(1) ? this->invokeChild(1, args.fInputColor, args)
299                                             : SkString(args.fInputColor);
300             break;
301 
302         default:
303             SK_ABORT("unrecognized blend behavior");
304             break;
305     }
306 
307     // Blend src and dst colors together.
308     fragBuilder->codeAppendf("return %s(%s, %s)", GrGLSLBlend::BlendFuncName(mode),
309                              srcColor.c_str(), dstColor.c_str());
310 
311     // Reapply alpha from input color if we are doing a compose-two.
312     if (behavior == BlendBehavior::kComposeTwoBehavior) {
313         fragBuilder->codeAppendf(" * %s.a", args.fInputColor);
314     }
315 
316     fragBuilder->codeAppendf(";\n");
317 }
318 
319 //////////////////////////////////////////////////////////////////////////////
320 
Make(std::unique_ptr<GrFragmentProcessor> src,std::unique_ptr<GrFragmentProcessor> dst,SkBlendMode mode,BlendBehavior behavior)321 std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make(
322         std::unique_ptr<GrFragmentProcessor> src,
323         std::unique_ptr<GrFragmentProcessor> dst,
324         SkBlendMode mode, BlendBehavior behavior) {
325     switch (mode) {
326         case SkBlendMode::kClear:
327             return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
328         case SkBlendMode::kSrc:
329             return GrFragmentProcessor::OverrideInput(std::move(src), SK_PMColor4fWHITE,
330                                                       /*useUniform=*/false);
331         case SkBlendMode::kDst:
332             return GrFragmentProcessor::OverrideInput(std::move(dst), SK_PMColor4fWHITE,
333                                                       /*useUniform=*/false);
334         default:
335             return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode, behavior);
336     }
337 }
338