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