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