/src/skia/src/gpu/effects/GrBlendFragmentProcessor.cpp
Line | Count | Source (jump to first uncovered line) |
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. |
17 | 73.4k | 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 | 73.4k | return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight && |
22 | 73.1k | mode != SkBlendMode::kColorBurn; |
23 | 73.4k | } |
24 | | |
25 | | ////////////////////////////////////////////////////////////////////////////// |
26 | | |
27 | | class BlendFragmentProcessor : public GrFragmentProcessor { |
28 | | public: |
29 | | static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src, |
30 | | std::unique_ptr<GrFragmentProcessor> dst, |
31 | 73.4k | SkBlendMode mode) { |
32 | 73.4k | return std::unique_ptr<GrFragmentProcessor>( |
33 | 73.4k | new BlendFragmentProcessor(std::move(src), std::move(dst), mode)); |
34 | 73.4k | } |
35 | | |
36 | 0 | const char* name() const override { return "Blend"; } |
37 | | |
38 | | std::unique_ptr<GrFragmentProcessor> clone() const override; |
39 | | |
40 | | private: |
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 | 73.4k | , fMode(mode) { |
46 | 73.4k | this->setIsBlendFunction(); |
47 | 73.4k | this->registerChild(std::move(src)); |
48 | 73.4k | this->registerChild(std::move(dst)); |
49 | 73.4k | } |
50 | | |
51 | | BlendFragmentProcessor(const BlendFragmentProcessor& that) |
52 | | : INHERITED(that) |
53 | 4 | , fMode(that.fMode) {} |
54 | | |
55 | | #if GR_TEST_UTILS |
56 | 0 | SkString onDumpInfo() const override { |
57 | 0 | return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode)); |
58 | 0 | } |
59 | | #endif |
60 | | |
61 | | static OptimizationFlags OptFlags(const GrFragmentProcessor* src, |
62 | 73.4k | const GrFragmentProcessor* dst, SkBlendMode mode) { |
63 | 73.4k | OptimizationFlags flags; |
64 | 73.4k | switch (mode) { |
65 | 0 | case SkBlendMode::kClear: |
66 | 0 | case SkBlendMode::kSrc: |
67 | 0 | case SkBlendMode::kDst: |
68 | 0 | SkDEBUGFAIL("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'."); |
69 | 0 | flags = kNone_OptimizationFlags; |
70 | 0 | 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 | 2.70k | case SkBlendMode::kSrcIn: |
76 | 40.9k | case SkBlendMode::kDstIn: |
77 | 73.1k | case SkBlendMode::kModulate: |
78 | 73.1k | if (src && dst) { |
79 | 1.01k | flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) & |
80 | 1.01k | kPreservesOpaqueInput_OptimizationFlag; |
81 | 72.1k | } else if (src) { |
82 | 41.4k | flags = ProcessorOptimizationFlags(src) & |
83 | 41.4k | ~kConstantOutputForConstantInput_OptimizationFlag; |
84 | 30.7k | } else if (dst) { |
85 | 30.7k | flags = ProcessorOptimizationFlags(dst) & |
86 | 30.7k | ~kConstantOutputForConstantInput_OptimizationFlag; |
87 | 0 | } else { |
88 | 0 | flags = kNone_OptimizationFlags; |
89 | 0 | } |
90 | 73.1k | break; |
91 | | |
92 | | // Produces zero when both are opaque, indeterminate if one is opaque. |
93 | 1 | case SkBlendMode::kSrcOut: |
94 | 4 | case SkBlendMode::kDstOut: |
95 | 4 | case SkBlendMode::kXor: |
96 | 4 | flags = kNone_OptimizationFlags; |
97 | 4 | break; |
98 | | |
99 | | // Is opaque if the dst is opaque. |
100 | 0 | case SkBlendMode::kSrcATop: |
101 | 0 | flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag; |
102 | 0 | break; |
103 | | |
104 | | // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. |
105 | 2 | case SkBlendMode::kDstATop: |
106 | 2 | case SkBlendMode::kScreen: |
107 | 2 | flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag; |
108 | 2 | 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 | 0 | case SkBlendMode::kSrcOver: |
113 | 0 | case SkBlendMode::kDstOver: |
114 | 1 | case SkBlendMode::kPlus: |
115 | 1 | case SkBlendMode::kOverlay: |
116 | 1 | case SkBlendMode::kDarken: |
117 | 1 | case SkBlendMode::kLighten: |
118 | 1 | case SkBlendMode::kColorDodge: |
119 | 2 | case SkBlendMode::kColorBurn: |
120 | 5 | case SkBlendMode::kHardLight: |
121 | 5 | case SkBlendMode::kSoftLight: |
122 | 5 | case SkBlendMode::kDifference: |
123 | 5 | case SkBlendMode::kExclusion: |
124 | 5 | case SkBlendMode::kMultiply: |
125 | 5 | case SkBlendMode::kHue: |
126 | 5 | case SkBlendMode::kSaturation: |
127 | 5 | case SkBlendMode::kColor: |
128 | 223 | case SkBlendMode::kLuminosity: |
129 | 223 | flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) & |
130 | 223 | kPreservesOpaqueInput_OptimizationFlag; |
131 | 223 | break; |
132 | 73.4k | } |
133 | 73.4k | if (does_cpu_blend_impl_match_gpu(mode) && |
134 | 73.1k | (!src || src->hasConstantOutputForConstantInput()) && |
135 | 33.0k | (!dst || dst->hasConstantOutputForConstantInput())) { |
136 | 1.63k | flags |= kConstantOutputForConstantInput_OptimizationFlag; |
137 | 1.63k | } |
138 | 73.4k | return flags; |
139 | 73.4k | } |
140 | | |
141 | 0 | void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { |
142 | 0 | b->add32((int)fMode); |
143 | 0 | } |
144 | | |
145 | 56.4k | bool onIsEqual(const GrFragmentProcessor& other) const override { |
146 | 56.4k | const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>(); |
147 | 56.4k | return fMode == cs.fMode; |
148 | 56.4k | } |
149 | | |
150 | 28 | SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { |
151 | 28 | const auto* src = this->childProcessor(0); |
152 | 28 | const auto* dst = this->childProcessor(1); |
153 | | |
154 | 28 | SkPMColor4f srcColor = ConstantOutputForConstantInput(src, input); |
155 | 28 | SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, input); |
156 | | |
157 | 28 | return SkBlendMode_Apply(fMode, srcColor, dstColor); |
158 | 28 | } |
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 |
175 | 0 | std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) { |
176 | | // Create one or two random fragment processors. |
177 | 0 | std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d)); |
178 | 0 | std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d)); |
179 | 0 | if (d->fRandom->nextBool()) { |
180 | 0 | std::swap(src, dst); |
181 | 0 | } |
182 | |
|
183 | 0 | SkBlendMode mode; |
184 | 0 | do { |
185 | 0 | mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); |
186 | 0 | } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode); |
187 | 0 | return std::unique_ptr<GrFragmentProcessor>( |
188 | 0 | new BlendFragmentProcessor(std::move(src), std::move(dst), mode)); |
189 | 0 | } |
190 | | #endif |
191 | | |
192 | 4 | std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const { |
193 | 4 | return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this)); |
194 | 4 | } |
195 | | |
196 | 0 | std::unique_ptr<GrFragmentProcessor::ProgramImpl> BlendFragmentProcessor::onMakeProgramImpl() const { |
197 | 0 | class Impl : public ProgramImpl { |
198 | 0 | public: |
199 | 0 | void emitCode(EmitArgs& args) override { |
200 | 0 | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
201 | 0 | const BlendFragmentProcessor& bfp = args.fFp.cast<BlendFragmentProcessor>(); |
202 | 0 | SkBlendMode mode = bfp.fMode; |
203 | |
|
204 | 0 | 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 | 0 | SkString srcColor = this->invokeChild(0, args); |
208 | 0 | SkString dstColor = this->invokeChild(1, args); |
209 | | |
210 | | // Blend src and dst colors together. |
211 | 0 | fragBuilder->codeAppendf("return %s(%s, %s);", |
212 | 0 | GrGLSLBlend::BlendFuncName(mode), |
213 | 0 | srcColor.c_str(), |
214 | 0 | dstColor.c_str()); |
215 | 0 | } |
216 | 0 | }; |
217 | |
|
218 | 0 | return std::make_unique<Impl>(); |
219 | 0 | } |
220 | | |
221 | | ////////////////////////////////////////////////////////////////////////////// |
222 | | |
223 | | std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make( |
224 | | std::unique_ptr<GrFragmentProcessor> src, |
225 | | std::unique_ptr<GrFragmentProcessor> dst, |
226 | 75.8k | SkBlendMode mode) { |
227 | 75.8k | switch (mode) { |
228 | 833 | case SkBlendMode::kClear: |
229 | 833 | return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT); |
230 | 313 | case SkBlendMode::kSrc: |
231 | 313 | return src; |
232 | 1.31k | case SkBlendMode::kDst: |
233 | 1.31k | return dst; |
234 | 73.4k | default: |
235 | 73.4k | return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode); |
236 | 75.8k | } |
237 | 75.8k | } |