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