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