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/GrCustomXfermode.h"
9
10 #include "src/gpu/GrCaps.h"
11 #include "src/gpu/GrFragmentProcessor.h"
12 #include "src/gpu/GrPipeline.h"
13 #include "src/gpu/GrProcessor.h"
14 #include "src/gpu/GrShaderCaps.h"
15 #include "src/gpu/GrXferProcessor.h"
16 #include "src/gpu/KeyBuilder.h"
17 #include "src/gpu/glsl/GrGLSLBlend.h"
18 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
19 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
20 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
21
IsSupportedMode(SkBlendMode mode)22 bool GrCustomXfermode::IsSupportedMode(SkBlendMode mode) {
23 return (int)mode > (int)SkBlendMode::kLastCoeffMode &&
24 (int)mode <= (int)SkBlendMode::kLastMode;
25 }
26
27 ///////////////////////////////////////////////////////////////////////////////
28 // Static helpers
29 ///////////////////////////////////////////////////////////////////////////////
30
hw_blend_equation(SkBlendMode mode)31 static constexpr GrBlendEquation hw_blend_equation(SkBlendMode mode) {
32 constexpr int kEqOffset = (kOverlay_GrBlendEquation - (int)SkBlendMode::kOverlay);
33 static_assert(kOverlay_GrBlendEquation == (int)SkBlendMode::kOverlay + kEqOffset);
34 static_assert(kDarken_GrBlendEquation == (int)SkBlendMode::kDarken + kEqOffset);
35 static_assert(kLighten_GrBlendEquation == (int)SkBlendMode::kLighten + kEqOffset);
36 static_assert(kColorDodge_GrBlendEquation == (int)SkBlendMode::kColorDodge + kEqOffset);
37 static_assert(kColorBurn_GrBlendEquation == (int)SkBlendMode::kColorBurn + kEqOffset);
38 static_assert(kHardLight_GrBlendEquation == (int)SkBlendMode::kHardLight + kEqOffset);
39 static_assert(kSoftLight_GrBlendEquation == (int)SkBlendMode::kSoftLight + kEqOffset);
40 static_assert(kDifference_GrBlendEquation == (int)SkBlendMode::kDifference + kEqOffset);
41 static_assert(kExclusion_GrBlendEquation == (int)SkBlendMode::kExclusion + kEqOffset);
42 static_assert(kMultiply_GrBlendEquation == (int)SkBlendMode::kMultiply + kEqOffset);
43 static_assert(kHSLHue_GrBlendEquation == (int)SkBlendMode::kHue + kEqOffset);
44 static_assert(kHSLSaturation_GrBlendEquation == (int)SkBlendMode::kSaturation + kEqOffset);
45 static_assert(kHSLColor_GrBlendEquation == (int)SkBlendMode::kColor + kEqOffset);
46 static_assert(kHSLLuminosity_GrBlendEquation == (int)SkBlendMode::kLuminosity + kEqOffset);
47
48 // There's an illegal GrBlendEquation that corresponds to no SkBlendMode, hence the extra +1.
49 static_assert(kGrBlendEquationCnt == (int)SkBlendMode::kLastMode + 1 + 1 + kEqOffset);
50
51 return static_cast<GrBlendEquation>((int)mode + kEqOffset);
52 #undef EQ_OFFSET
53 }
54
can_use_hw_blend_equation(GrBlendEquation equation,GrProcessorAnalysisCoverage coverage,const GrCaps & caps)55 static bool can_use_hw_blend_equation(GrBlendEquation equation,
56 GrProcessorAnalysisCoverage coverage, const GrCaps& caps) {
57 if (!caps.advancedBlendEquationSupport()) {
58 return false;
59 }
60 if (GrProcessorAnalysisCoverage::kLCD == coverage) {
61 return false; // LCD coverage must be applied after the blend equation.
62 }
63 if (caps.isAdvancedBlendEquationDisabled(equation)) {
64 return false;
65 }
66 return true;
67 }
68
69 ///////////////////////////////////////////////////////////////////////////////
70 // Xfer Processor
71 ///////////////////////////////////////////////////////////////////////////////
72
73 class CustomXP : public GrXferProcessor {
74 public:
CustomXP(SkBlendMode mode,GrBlendEquation hwBlendEquation)75 CustomXP(SkBlendMode mode, GrBlendEquation hwBlendEquation)
76 : INHERITED(kCustomXP_ClassID)
77 , fMode(mode)
78 , fHWBlendEquation(hwBlendEquation) {}
79
CustomXP(SkBlendMode mode,GrProcessorAnalysisCoverage coverage)80 CustomXP(SkBlendMode mode, GrProcessorAnalysisCoverage coverage)
81 : INHERITED(kCustomXP_ClassID, /*willReadDstColor=*/true, coverage)
82 , fMode(mode)
83 , fHWBlendEquation(kIllegal_GrBlendEquation) {
84 }
85
name() const86 const char* name() const override { return "Custom Xfermode"; }
87
88 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
89
90 GrXferBarrierType xferBarrierType(const GrCaps&) const override;
91
92 private:
hasHWBlendEquation() const93 bool hasHWBlendEquation() const { return kIllegal_GrBlendEquation != fHWBlendEquation; }
94
95 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
96
97 void onGetBlendInfo(BlendInfo*) const override;
98
99 bool onIsEqual(const GrXferProcessor& xpBase) const override;
100
101 const SkBlendMode fMode;
102 const GrBlendEquation fHWBlendEquation;
103
104 using INHERITED = GrXferProcessor;
105 };
106
onAddToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const107 void CustomXP::onAddToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
108 uint32_t key = 0;
109 if (this->hasHWBlendEquation()) {
110 SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation().
111 key |= caps.advBlendEqInteraction();
112 static_assert(GrShaderCaps::kLast_AdvBlendEqInteraction < 4);
113 } else {
114 key |= static_cast<int>(fMode) << 3;
115 }
116 b->add32(key);
117 }
118
makeProgramImpl() const119 std::unique_ptr<GrXferProcessor::ProgramImpl> CustomXP::makeProgramImpl() const {
120 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
121
122 class Impl : public ProgramImpl {
123 private:
124 void emitOutputsForBlendState(const EmitArgs& args) override {
125 const CustomXP& xp = args.fXP.cast<CustomXP>();
126 SkASSERT(xp.hasHWBlendEquation());
127
128 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
129 fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.fHWBlendEquation);
130
131 // Apply coverage by multiplying it into the src color before blending. This will "just
132 // work" automatically. (See analysisProperties())
133 fragBuilder->codeAppendf("%s = %s * %s;",
134 args.fOutputPrimary,
135 args.fInputCoverage,
136 args.fInputColor);
137 }
138
139 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
140 GrGLSLUniformHandler* uniformHandler,
141 const char* srcColor,
142 const char* srcCoverage,
143 const char* dstColor,
144 const char* outColor,
145 const char* outColorSecondary,
146 const GrXferProcessor& proc) override {
147 const CustomXP& xp = proc.cast<CustomXP>();
148 SkASSERT(!xp.hasHWBlendEquation());
149
150 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.fMode);
151
152 // Apply coverage.
153 DefaultCoverageModulation(fragBuilder,
154 srcCoverage,
155 dstColor,
156 outColor,
157 outColorSecondary,
158 xp);
159 }
160 };
161
162 return std::make_unique<Impl>();
163 }
164
onIsEqual(const GrXferProcessor & other) const165 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
166 const CustomXP& s = other.cast<CustomXP>();
167 return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
168 }
169
xferBarrierType(const GrCaps & caps) const170 GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const {
171 if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
172 return kBlend_GrXferBarrierType;
173 }
174 return kNone_GrXferBarrierType;
175 }
176
onGetBlendInfo(BlendInfo * blendInfo) const177 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
178 if (this->hasHWBlendEquation()) {
179 blendInfo->fEquation = fHWBlendEquation;
180 }
181 }
182
183 ///////////////////////////////////////////////////////////////////////////////
184
185 // See the comment above GrXPFactory's definition about this warning suppression.
186 #if defined(__GNUC__)
187 #pragma GCC diagnostic push
188 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
189 #endif
190 #if defined(__clang__)
191 #pragma clang diagnostic push
192 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
193 #endif
194 class CustomXPFactory : public GrXPFactory {
195 public:
CustomXPFactory(SkBlendMode mode)196 constexpr CustomXPFactory(SkBlendMode mode)
197 : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
198
199 private:
200 sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
201 GrProcessorAnalysisCoverage,
202 const GrCaps&,
203 GrClampType) const override;
204
205 AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
206 const GrProcessorAnalysisCoverage&,
207 const GrCaps&,
208 GrClampType) const override;
209
210 GR_DECLARE_XP_FACTORY_TEST
211
212 SkBlendMode fMode;
213 GrBlendEquation fHWBlendEquation;
214
215 using INHERITED = GrXPFactory;
216 };
217 #if defined(__GNUC__)
218 #pragma GCC diagnostic pop
219 #endif
220 #if defined(__clang__)
221 #pragma clang diagnostic pop
222 #endif
223
makeXferProcessor(const GrProcessorAnalysisColor &,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const224 sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor(
225 const GrProcessorAnalysisColor&,
226 GrProcessorAnalysisCoverage coverage,
227 const GrCaps& caps,
228 GrClampType clampType) const {
229 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
230 if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
231 return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));
232 }
233 return sk_sp<GrXferProcessor>(new CustomXP(fMode, coverage));
234 }
235
analysisProperties(const GrProcessorAnalysisColor &,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const236 GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
237 const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage,
238 const GrCaps& caps, GrClampType clampType) const {
239 /*
240 The general SVG blend equation is defined in the spec as follows:
241
242 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
243 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
244
245 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
246 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
247 RGB colors.)
248
249 For every blend mode supported by this class, i.e. the "advanced" blend
250 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
251
252 It can be shown that when X=Y=Z=1, these equations can modulate alpha for
253 coverage.
254
255
256 == Color ==
257
258 We substitute Y=Z=1 and define a blend() function that calculates Dca' in
259 terms of premultiplied alpha only:
260
261 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
262 Sca : if Da == 0,
263 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if
264 Sa,Da != 0}
265
266 And for coverage modulation, we use a post blend src-over model:
267
268 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
269
270 (Where f is the fractional coverage.)
271
272 Next we show that canTweakAlphaForCoverage() is true by proving the
273 following relationship:
274
275 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
276
277 General case (f,Sa,Da != 0):
278
279 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
280 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da !=
281 0, definition of blend()]
282 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
283 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
284 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
285 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
286 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
287 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0]
288 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()]
289
290 Corner cases (Sa=0, Da=0, and f=0):
291
292 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
293 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()]
294 = Dca
295 = blend(0, Dca, 0, Da) [definition of blend()]
296 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0]
297
298 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
299 = f * Sca + (1-f) * Dca [Da=0, definition of blend()]
300 = f * Sca [Da=0]
301 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()]
302 = blend(f*Sca, Dca, f*Sa, Da) [Da=0]
303
304 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
305 = Dca [f=0]
306 = blend(0, Dca, 0, Da) [definition of blend()]
307 = blend(f*Sca, Dca, f*Sa, Da) [f=0]
308
309 == Alpha ==
310
311 We substitute X=Y=Z=1 and define a blend() function that calculates Da':
312
313 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
314 = Sa * Da + Sa - Sa * Da + Da - Da * Sa
315 = Sa + Da - Sa * Da
316
317 We use the same model for coverage modulation as we did with color:
318
319 Da'' = f * blend(Sa, Da) + (1-f) * Da
320
321 And show that canTweakAlphaForCoverage() is true by proving the following
322 relationship:
323
324 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
325
326
327 f * blend(Sa, Da) + (1-f) * Da
328 = f * (Sa + Da - Sa * Da) + (1-f) * Da
329 = f*Sa + f*Da - f*Sa * Da + Da - f*Da
330 = f*Sa - f*Sa * Da + Da
331 = f*Sa + Da - f*Sa * Da
332 = blend(f*Sa, Da)
333 */
334 if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
335 if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) {
336 return AnalysisProperties::kCompatibleWithCoverageAsAlpha;
337 } else {
338 return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
339 AnalysisProperties::kRequiresNonOverlappingDraws |
340 AnalysisProperties::kUsesNonCoherentHWBlending;
341 }
342 }
343 return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
344 AnalysisProperties::kReadsDstInShader;
345 }
346
347 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
348 #if GR_TEST_UTILS
TestGet(GrProcessorTestData * d)349 const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) {
350 int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1,
351 (int)SkBlendMode::kLastSeparableMode);
352
353 return GrCustomXfermode::Get((SkBlendMode)mode);
354 }
355 #endif
356
357 ///////////////////////////////////////////////////////////////////////////////
358
Get(SkBlendMode mode)359 const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) {
360 static constexpr const CustomXPFactory gOverlay(SkBlendMode::kOverlay);
361 static constexpr const CustomXPFactory gDarken(SkBlendMode::kDarken);
362 static constexpr const CustomXPFactory gLighten(SkBlendMode::kLighten);
363 static constexpr const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge);
364 static constexpr const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn);
365 static constexpr const CustomXPFactory gHardLight(SkBlendMode::kHardLight);
366 static constexpr const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight);
367 static constexpr const CustomXPFactory gDifference(SkBlendMode::kDifference);
368 static constexpr const CustomXPFactory gExclusion(SkBlendMode::kExclusion);
369 static constexpr const CustomXPFactory gMultiply(SkBlendMode::kMultiply);
370 static constexpr const CustomXPFactory gHue(SkBlendMode::kHue);
371 static constexpr const CustomXPFactory gSaturation(SkBlendMode::kSaturation);
372 static constexpr const CustomXPFactory gColor(SkBlendMode::kColor);
373 static constexpr const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity);
374 switch (mode) {
375 case SkBlendMode::kOverlay:
376 return &gOverlay;
377 case SkBlendMode::kDarken:
378 return &gDarken;
379 case SkBlendMode::kLighten:
380 return &gLighten;
381 case SkBlendMode::kColorDodge:
382 return &gColorDodge;
383 case SkBlendMode::kColorBurn:
384 return &gColorBurn;
385 case SkBlendMode::kHardLight:
386 return &gHardLight;
387 case SkBlendMode::kSoftLight:
388 return &gSoftLight;
389 case SkBlendMode::kDifference:
390 return &gDifference;
391 case SkBlendMode::kExclusion:
392 return &gExclusion;
393 case SkBlendMode::kMultiply:
394 return &gMultiply;
395 case SkBlendMode::kHue:
396 return &gHue;
397 case SkBlendMode::kSaturation:
398 return &gSaturation;
399 case SkBlendMode::kColor:
400 return &gColor;
401 case SkBlendMode::kLuminosity:
402 return &gLuminosity;
403 default:
404 SkASSERT(!GrCustomXfermode::IsSupportedMode(mode));
405 return nullptr;
406 }
407 }
408