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