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/GrGLSLFragmentShaderBuilder.h"
14
15 // Some of the CPU implementations of blend modes differ from the GPU enough that
16 // we can't use the CPU implementation to implement constantOutputForConstantInput.
does_cpu_blend_impl_match_gpu(SkBlendMode mode)17 static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) {
18 // The non-separable modes differ too much. So does SoftLight. ColorBurn differs too much on our
19 // test iOS device, but we just disable it across the board since it might differ on untested
20 // GPUs.
21 return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight &&
22 mode != SkBlendMode::kColorBurn;
23 }
24
25 //////////////////////////////////////////////////////////////////////////////
26
27 class BlendFragmentProcessor : public GrFragmentProcessor {
28 public:
Make(std::unique_ptr<GrFragmentProcessor> src, std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode)29 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src,
30 std::unique_ptr<GrFragmentProcessor> dst,
31 SkBlendMode mode) {
32 return std::unique_ptr<GrFragmentProcessor>(
33 new BlendFragmentProcessor(std::move(src), std::move(dst), mode));
34 }
35
36 const char* name() const override { return "Blend"; }
37
38 SkString getShaderDfxInfo() const override {
39 SkString format;
40 format.printf("ShaderDfx_Blend_%d", fMode);
41 return format;
42 }
43
44 std::unique_ptr<GrFragmentProcessor> clone() const override;
45
46 private:
BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src, std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode)47 BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src,
48 std::unique_ptr<GrFragmentProcessor> dst,
49 SkBlendMode mode)
50 : INHERITED(kBlendFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode))
51 , fMode(mode) {
52 this->setIsBlendFunction();
53 this->registerChild(std::move(src));
54 this->registerChild(std::move(dst));
55 }
56
BlendFragmentProcessor(const BlendFragmentProcessor& that)57 BlendFragmentProcessor(const BlendFragmentProcessor& that)
58 : INHERITED(that)
59 , fMode(that.fMode) {}
60
61 #if GR_TEST_UTILS
62 SkString onDumpInfo() const override {
63 return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode));
64 }
65 #endif
66
OptFlags(const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkBlendMode mode)67 static OptimizationFlags OptFlags(const GrFragmentProcessor* src,
68 const GrFragmentProcessor* dst, SkBlendMode mode) {
69 OptimizationFlags flags;
70 switch (mode) {
71 case SkBlendMode::kClear:
72 case SkBlendMode::kSrc:
73 case SkBlendMode::kDst:
74 SkDEBUGFAIL("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'.");
75 flags = kNone_OptimizationFlags;
76 break;
77
78 // Produces opaque if both src and dst are opaque. These also will modulate the child's
79 // output by either the input color or alpha. However, if the child is not compatible
80 // with the coverage as alpha then it may produce a color that is not valid premul.
81 case SkBlendMode::kSrcIn:
82 case SkBlendMode::kDstIn:
83 case SkBlendMode::kModulate:
84 if (src && dst) {
85 flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) &
86 kPreservesOpaqueInput_OptimizationFlag;
87 } else if (src) {
88 flags = ProcessorOptimizationFlags(src) &
89 ~kConstantOutputForConstantInput_OptimizationFlag;
90 } else if (dst) {
91 flags = ProcessorOptimizationFlags(dst) &
92 ~kConstantOutputForConstantInput_OptimizationFlag;
93 } else {
94 flags = kNone_OptimizationFlags;
95 }
96 break;
97
98 // Produces zero when both are opaque, indeterminate if one is opaque.
99 case SkBlendMode::kSrcOut:
100 case SkBlendMode::kDstOut:
101 case SkBlendMode::kXor:
102 flags = kNone_OptimizationFlags;
103 break;
104
105 // Is opaque if the dst is opaque.
106 case SkBlendMode::kSrcATop:
107 flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag;
108 break;
109
110 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque.
111 case SkBlendMode::kDstATop:
112 case SkBlendMode::kScreen:
113 flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag;
114 break;
115
116 // These modes are all opaque if either src or dst is opaque. All the advanced modes
117 // compute alpha as src-over.
118 case SkBlendMode::kSrcOver:
119 case SkBlendMode::kDstOver:
120 case SkBlendMode::kPlus:
121 case SkBlendMode::kOverlay:
122 case SkBlendMode::kDarken:
123 case SkBlendMode::kLighten:
124 case SkBlendMode::kColorDodge:
125 case SkBlendMode::kColorBurn:
126 case SkBlendMode::kHardLight:
127 case SkBlendMode::kSoftLight:
128 case SkBlendMode::kDifference:
129 case SkBlendMode::kExclusion:
130 case SkBlendMode::kMultiply:
131 case SkBlendMode::kHue:
132 case SkBlendMode::kSaturation:
133 case SkBlendMode::kColor:
134 case SkBlendMode::kLuminosity:
135 flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) &
136 kPreservesOpaqueInput_OptimizationFlag;
137 break;
138 }
139 if (does_cpu_blend_impl_match_gpu(mode) &&
140 (!src || src->hasConstantOutputForConstantInput()) &&
141 (!dst || dst->hasConstantOutputForConstantInput())) {
142 flags |= kConstantOutputForConstantInput_OptimizationFlag;
143 }
144 return flags;
145 }
146
147 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
148 b->add32((int)fMode);
149 }
150
151 bool onIsEqual(const GrFragmentProcessor& other) const override {
152 const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>();
153 return fMode == cs.fMode;
154 }
155
156 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
157 const auto* src = this->childProcessor(0);
158 const auto* dst = this->childProcessor(1);
159
160 SkPMColor4f srcColor = ConstantOutputForConstantInput(src, input);
161 SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, input);
162
163 return SkBlendMode_Apply(fMode, srcColor, dstColor);
164 }
165
166 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
167
168 SkBlendMode fMode;
169
170 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
171
172 using INHERITED = GrFragmentProcessor;
173 };
174
175 /////////////////////////////////////////////////////////////////////
176
177
178 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BlendFragmentProcessor);
179
180 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData* d)181 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) {
182 // Create one or two random fragment processors.
183 std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d));
184 std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
185 if (d->fRandom->nextBool()) {
186 std::swap(src, dst);
187 }
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 BlendFragmentProcessor(std::move(src), std::move(dst), mode));
195 }
196 #endif
197
clone() const198 std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const {
199 return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this));
200 }
201
onMakeProgramImpl() const202 std::unique_ptr<GrFragmentProcessor::ProgramImpl> BlendFragmentProcessor::onMakeProgramImpl() const {
203 class Impl : public ProgramImpl {
204 public:
205 void emitCode(EmitArgs& args) override {
206 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
207 const BlendFragmentProcessor& bfp = args.fFp.cast<BlendFragmentProcessor>();
208 SkBlendMode mode = bfp.fMode;
209
210 fragBuilder->codeAppendf("// Blend mode: %s\n", SkBlendMode_Name(mode));
211
212 // Invoke src/dst with our input color (or substitute input color if no child FP)
213 SkString srcColor = this->invokeChild(0, args);
214 SkString dstColor = this->invokeChild(1, args);
215
216 // Blend src and dst colors together.
217 fragBuilder->codeAppendf("return %s(%s, %s);",
218 GrGLSLBlend::BlendFuncName(mode),
219 srcColor.c_str(),
220 dstColor.c_str());
221 }
222 };
223
224 return std::make_unique<Impl>();
225 }
226
227 //////////////////////////////////////////////////////////////////////////////
228
Make( std::unique_ptr<GrFragmentProcessor> src, std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode)229 std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make(
230 std::unique_ptr<GrFragmentProcessor> src,
231 std::unique_ptr<GrFragmentProcessor> dst,
232 SkBlendMode mode) {
233 switch (mode) {
234 case SkBlendMode::kClear:
235 return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT);
236 case SkBlendMode::kSrc:
237 return src;
238 case SkBlendMode::kDst:
239 return dst;
240 default:
241 return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode);
242 }
243 }
244