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