• 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/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     SkString getShaderDfxInfo() const override;
88 
89     std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
90 
91     GrXferBarrierType xferBarrierType(const GrCaps&) const override;
92 
93 private:
hasHWBlendEquation() const94     bool hasHWBlendEquation() const { return kIllegal_GrBlendEquation != fHWBlendEquation; }
95 
96     void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
97 
98     void onGetBlendInfo(BlendInfo*) const override;
99 
100     bool onIsEqual(const GrXferProcessor& xpBase) const override;
101 
102     const SkBlendMode      fMode;
103     const GrBlendEquation  fHWBlendEquation;
104 
105     using INHERITED = GrXferProcessor;
106 };
107 
getShaderDfxInfo() const108 SkString CustomXP::getShaderDfxInfo() const
109 {
110     SkString format;
111     format.printf("ShaderDfx_CustomXP_%d_%d", hasHWBlendEquation(), fMode);
112     return format;
113 }
114 
onAddToKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const115 void CustomXP::onAddToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const {
116     uint32_t key = 0;
117     if (this->hasHWBlendEquation()) {
118         SkASSERT(caps.advBlendEqInteraction() > 0);  // 0 will mean !xp.hasHWBlendEquation().
119         key |= caps.advBlendEqInteraction();
120         static_assert(GrShaderCaps::kLast_AdvBlendEqInteraction < 4);
121     } else {
122         key |= static_cast<int>(fMode) << 3;
123     }
124     b->add32(key);
125 }
126 
makeProgramImpl() const127 std::unique_ptr<GrXferProcessor::ProgramImpl> CustomXP::makeProgramImpl() const {
128     SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
129 
130     class Impl : public ProgramImpl {
131     private:
132         void emitOutputsForBlendState(const EmitArgs& args) override {
133             const CustomXP& xp = args.fXP.cast<CustomXP>();
134             SkASSERT(xp.hasHWBlendEquation());
135 
136             GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
137             fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.fHWBlendEquation);
138 
139             // Apply coverage by multiplying it into the src color before blending. This will "just
140             // work" automatically. (See analysisProperties())
141             fragBuilder->codeAppendf("%s = %s * %s;",
142                                      args.fOutputPrimary,
143                                      args.fInputCoverage,
144                                      args.fInputColor);
145         }
146 
147         void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
148                                      GrGLSLUniformHandler* uniformHandler,
149                                      const char* srcColor,
150                                      const char* srcCoverage,
151                                      const char* dstColor,
152                                      const char* outColor,
153                                      const char* outColorSecondary,
154                                      const GrXferProcessor& proc) override {
155             const CustomXP& xp = proc.cast<CustomXP>();
156             SkASSERT(!xp.hasHWBlendEquation());
157 
158             GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.fMode);
159 
160             // Apply coverage.
161             DefaultCoverageModulation(fragBuilder,
162                                       srcCoverage,
163                                       dstColor,
164                                       outColor,
165                                       outColorSecondary,
166                                       xp);
167         }
168     };
169 
170     return std::make_unique<Impl>();
171 }
172 
onIsEqual(const GrXferProcessor & other) const173 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
174     const CustomXP& s = other.cast<CustomXP>();
175     return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
176 }
177 
xferBarrierType(const GrCaps & caps) const178 GrXferBarrierType CustomXP::xferBarrierType(const GrCaps& caps) const {
179     if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
180         return kBlend_GrXferBarrierType;
181     }
182     return kNone_GrXferBarrierType;
183 }
184 
onGetBlendInfo(BlendInfo * blendInfo) const185 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
186     if (this->hasHWBlendEquation()) {
187         blendInfo->fEquation = fHWBlendEquation;
188     }
189 }
190 
191 ///////////////////////////////////////////////////////////////////////////////
192 
193 // See the comment above GrXPFactory's definition about this warning suppression.
194 #if defined(__GNUC__)
195 #pragma GCC diagnostic push
196 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
197 #endif
198 #if defined(__clang__)
199 #pragma clang diagnostic push
200 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
201 #endif
202 class CustomXPFactory : public GrXPFactory {
203 public:
CustomXPFactory(SkBlendMode mode)204     constexpr CustomXPFactory(SkBlendMode mode)
205             : fMode(mode), fHWBlendEquation(hw_blend_equation(mode)) {}
206 
207 private:
208     sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&,
209                                                    GrProcessorAnalysisCoverage,
210                                                    const GrCaps&,
211                                                    GrClampType) const override;
212 
213     AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&,
214                                           const GrProcessorAnalysisCoverage&,
215                                           const GrCaps&,
216                                           GrClampType) const override;
217 
218     GR_DECLARE_XP_FACTORY_TEST
219 
220     SkBlendMode fMode;
221     GrBlendEquation fHWBlendEquation;
222 
223     using INHERITED = GrXPFactory;
224 };
225 #if defined(__GNUC__)
226 #pragma GCC diagnostic pop
227 #endif
228 #if defined(__clang__)
229 #pragma clang diagnostic pop
230 #endif
231 
makeXferProcessor(const GrProcessorAnalysisColor &,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const232 sk_sp<const GrXferProcessor> CustomXPFactory::makeXferProcessor(
233         const GrProcessorAnalysisColor&,
234         GrProcessorAnalysisCoverage coverage,
235         const GrCaps& caps,
236         GrClampType clampType) const {
237     SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
238     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
239         return sk_sp<GrXferProcessor>(new CustomXP(fMode, fHWBlendEquation));
240     }
241     return sk_sp<GrXferProcessor>(new CustomXP(fMode, coverage));
242 }
243 
analysisProperties(const GrProcessorAnalysisColor &,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const244 GrXPFactory::AnalysisProperties CustomXPFactory::analysisProperties(
245         const GrProcessorAnalysisColor&, const GrProcessorAnalysisCoverage& coverage,
246         const GrCaps& caps, GrClampType clampType) const {
247     /*
248       The general SVG blend equation is defined in the spec as follows:
249 
250         Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
251         Da'  = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
252 
253       (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
254        and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
255        RGB colors.)
256 
257       For every blend mode supported by this class, i.e. the "advanced" blend
258       modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
259 
260       It can be shown that when X=Y=Z=1, these equations can modulate alpha for
261       coverage.
262 
263 
264       == Color ==
265 
266       We substitute Y=Z=1 and define a blend() function that calculates Dca' in
267       terms of premultiplied alpha only:
268 
269         blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
270                                    Sca : if Da == 0,
271                                    B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if
272       Sa,Da != 0}
273 
274       And for coverage modulation, we use a post blend src-over model:
275 
276         Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
277 
278       (Where f is the fractional coverage.)
279 
280       Next we show that canTweakAlphaForCoverage() is true by proving the
281       following relationship:
282 
283         blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
284 
285       General case (f,Sa,Da != 0):
286 
287         f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
288           = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca  [Sa,Da !=
289       0, definition of blend()]
290           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
291           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
292           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
293           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
294           = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
295           = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)  [f!=0]
296           = blend(f*Sca, Dca, f*Sa, Da)  [definition of blend()]
297 
298       Corner cases (Sa=0, Da=0, and f=0):
299 
300         Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
301                 = f * Dca + (1-f) * Dca  [Sa=0, definition of blend()]
302                 = Dca
303                 = blend(0, Dca, 0, Da)  [definition of blend()]
304                 = blend(f*Sca, Dca, f*Sa, Da)  [Sa=0]
305 
306         Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
307                 = f * Sca + (1-f) * Dca  [Da=0, definition of blend()]
308                 = f * Sca  [Da=0]
309                 = blend(f*Sca, 0, f*Sa, 0)  [definition of blend()]
310                 = blend(f*Sca, Dca, f*Sa, Da)  [Da=0]
311 
312         f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
313                = Dca  [f=0]
314                = blend(0, Dca, 0, Da)  [definition of blend()]
315                = blend(f*Sca, Dca, f*Sa, Da)  [f=0]
316 
317       == Alpha ==
318 
319       We substitute X=Y=Z=1 and define a blend() function that calculates Da':
320 
321         blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
322                       = Sa * Da + Sa - Sa * Da + Da - Da * Sa
323                       = Sa + Da - Sa * Da
324 
325       We use the same model for coverage modulation as we did with color:
326 
327         Da'' = f * blend(Sa, Da) + (1-f) * Da
328 
329       And show that canTweakAlphaForCoverage() is true by proving the following
330       relationship:
331 
332         blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
333 
334 
335         f * blend(Sa, Da) + (1-f) * Da
336           = f * (Sa + Da - Sa * Da) + (1-f) * Da
337           = f*Sa + f*Da - f*Sa * Da + Da - f*Da
338           = f*Sa - f*Sa * Da + Da
339           = f*Sa + Da - f*Sa * Da
340           = blend(f*Sa, Da)
341     */
342     if (can_use_hw_blend_equation(fHWBlendEquation, coverage, caps)) {
343         if (caps.blendEquationSupport() == GrCaps::kAdvancedCoherent_BlendEquationSupport) {
344             return AnalysisProperties::kCompatibleWithCoverageAsAlpha;
345         } else {
346             return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
347                    AnalysisProperties::kRequiresNonOverlappingDraws |
348                    AnalysisProperties::kUsesNonCoherentHWBlending;
349         }
350     }
351     return AnalysisProperties::kCompatibleWithCoverageAsAlpha |
352            AnalysisProperties::kReadsDstInShader;
353 }
354 
355 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
356 #if GR_TEST_UTILS
TestGet(GrProcessorTestData * d)357 const GrXPFactory* CustomXPFactory::TestGet(GrProcessorTestData* d) {
358     int mode = d->fRandom->nextRangeU((int)SkBlendMode::kLastCoeffMode + 1,
359                                       (int)SkBlendMode::kLastSeparableMode);
360 
361     return GrCustomXfermode::Get((SkBlendMode)mode);
362 }
363 #endif
364 
365 ///////////////////////////////////////////////////////////////////////////////
366 
Get(SkBlendMode mode)367 const GrXPFactory* GrCustomXfermode::Get(SkBlendMode mode) {
368     static constexpr const CustomXPFactory gOverlay(SkBlendMode::kOverlay);
369     static constexpr const CustomXPFactory gDarken(SkBlendMode::kDarken);
370     static constexpr const CustomXPFactory gLighten(SkBlendMode::kLighten);
371     static constexpr const CustomXPFactory gColorDodge(SkBlendMode::kColorDodge);
372     static constexpr const CustomXPFactory gColorBurn(SkBlendMode::kColorBurn);
373     static constexpr const CustomXPFactory gHardLight(SkBlendMode::kHardLight);
374     static constexpr const CustomXPFactory gSoftLight(SkBlendMode::kSoftLight);
375     static constexpr const CustomXPFactory gDifference(SkBlendMode::kDifference);
376     static constexpr const CustomXPFactory gExclusion(SkBlendMode::kExclusion);
377     static constexpr const CustomXPFactory gMultiply(SkBlendMode::kMultiply);
378     static constexpr const CustomXPFactory gHue(SkBlendMode::kHue);
379     static constexpr const CustomXPFactory gSaturation(SkBlendMode::kSaturation);
380     static constexpr const CustomXPFactory gColor(SkBlendMode::kColor);
381     static constexpr const CustomXPFactory gLuminosity(SkBlendMode::kLuminosity);
382     switch (mode) {
383         case SkBlendMode::kOverlay:
384             return &gOverlay;
385         case SkBlendMode::kDarken:
386             return &gDarken;
387         case SkBlendMode::kLighten:
388             return &gLighten;
389         case SkBlendMode::kColorDodge:
390             return &gColorDodge;
391         case SkBlendMode::kColorBurn:
392             return &gColorBurn;
393         case SkBlendMode::kHardLight:
394             return &gHardLight;
395         case SkBlendMode::kSoftLight:
396             return &gSoftLight;
397         case SkBlendMode::kDifference:
398             return &gDifference;
399         case SkBlendMode::kExclusion:
400             return &gExclusion;
401         case SkBlendMode::kMultiply:
402             return &gMultiply;
403         case SkBlendMode::kHue:
404             return &gHue;
405         case SkBlendMode::kSaturation:
406             return &gSaturation;
407         case SkBlendMode::kColor:
408             return &gColor;
409         case SkBlendMode::kLuminosity:
410             return &gLuminosity;
411         default:
412             SkASSERT(!GrCustomXfermode::IsSupportedMode(mode));
413             return nullptr;
414     }
415 }
416