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