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