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 "GrCoordTransform.h"
11 #include "GrContext.h"
12 #include "GrFragmentProcessor.h"
13 #include "GrInvariantOutput.h"
14 #include "GrPipeline.h"
15 #include "GrProcessor.h"
16 #include "GrTexture.h"
17 #include "GrTextureAccess.h"
18 #include "SkXfermode.h"
19 #include "glsl/GrGLSLBlend.h"
20 #include "glsl/GrGLSLCaps.h"
21 #include "glsl/GrGLSLFragmentProcessor.h"
22 #include "glsl/GrGLSLFragmentShaderBuilder.h"
23 #include "glsl/GrGLSLProgramDataManager.h"
24 #include "glsl/GrGLSLUniformHandler.h"
25 #include "glsl/GrGLSLXferProcessor.h"
26
IsSupportedMode(SkXfermode::Mode mode)27 bool GrCustomXfermode::IsSupportedMode(SkXfermode::Mode mode) {
28 return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
29 }
30
31 ///////////////////////////////////////////////////////////////////////////////
32 // Static helpers
33 ///////////////////////////////////////////////////////////////////////////////
34
hw_blend_equation(SkXfermode::Mode mode)35 static GrBlendEquation hw_blend_equation(SkXfermode::Mode mode) {
36 enum { kOffset = kOverlay_GrBlendEquation - SkXfermode::kOverlay_Mode };
37 return static_cast<GrBlendEquation>(mode + kOffset);
38
39 GR_STATIC_ASSERT(kOverlay_GrBlendEquation == SkXfermode::kOverlay_Mode + kOffset);
40 GR_STATIC_ASSERT(kDarken_GrBlendEquation == SkXfermode::kDarken_Mode + kOffset);
41 GR_STATIC_ASSERT(kLighten_GrBlendEquation == SkXfermode::kLighten_Mode + kOffset);
42 GR_STATIC_ASSERT(kColorDodge_GrBlendEquation == SkXfermode::kColorDodge_Mode + kOffset);
43 GR_STATIC_ASSERT(kColorBurn_GrBlendEquation == SkXfermode::kColorBurn_Mode + kOffset);
44 GR_STATIC_ASSERT(kHardLight_GrBlendEquation == SkXfermode::kHardLight_Mode + kOffset);
45 GR_STATIC_ASSERT(kSoftLight_GrBlendEquation == SkXfermode::kSoftLight_Mode + kOffset);
46 GR_STATIC_ASSERT(kDifference_GrBlendEquation == SkXfermode::kDifference_Mode + kOffset);
47 GR_STATIC_ASSERT(kExclusion_GrBlendEquation == SkXfermode::kExclusion_Mode + kOffset);
48 GR_STATIC_ASSERT(kMultiply_GrBlendEquation == SkXfermode::kMultiply_Mode + kOffset);
49 GR_STATIC_ASSERT(kHSLHue_GrBlendEquation == SkXfermode::kHue_Mode + kOffset);
50 GR_STATIC_ASSERT(kHSLSaturation_GrBlendEquation == SkXfermode::kSaturation_Mode + kOffset);
51 GR_STATIC_ASSERT(kHSLColor_GrBlendEquation == SkXfermode::kColor_Mode + kOffset);
52 GR_STATIC_ASSERT(kHSLLuminosity_GrBlendEquation == SkXfermode::kLuminosity_Mode + kOffset);
53 GR_STATIC_ASSERT(kGrBlendEquationCnt == SkXfermode::kLastMode + 1 + kOffset);
54 }
55
can_use_hw_blend_equation(GrBlendEquation equation,const GrPipelineOptimizations & opt,const GrCaps & caps)56 static bool can_use_hw_blend_equation(GrBlendEquation equation,
57 const GrPipelineOptimizations& opt,
58 const GrCaps& caps) {
59 if (!caps.advancedBlendEquationSupport()) {
60 return false;
61 }
62 if (opt.fOverrides.fUsePLSDstRead) {
63 return false;
64 }
65 if (opt.fCoveragePOI.isFourChannelOutput()) {
66 return false; // LCD coverage must be applied after the blend equation.
67 }
68 if (caps.canUseAdvancedBlendEquation(equation)) {
69 return false;
70 }
71 return true;
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////
75 // Xfer Processor
76 ///////////////////////////////////////////////////////////////////////////////
77
78 class CustomXP : public GrXferProcessor {
79 public:
CustomXP(SkXfermode::Mode mode,GrBlendEquation hwBlendEquation)80 CustomXP(SkXfermode::Mode mode, GrBlendEquation hwBlendEquation)
81 : fMode(mode),
82 fHWBlendEquation(hwBlendEquation) {
83 this->initClassID<CustomXP>();
84 }
85
CustomXP(const DstTexture * dstTexture,bool hasMixedSamples,SkXfermode::Mode mode)86 CustomXP(const DstTexture* dstTexture, bool hasMixedSamples, SkXfermode::Mode mode)
87 : INHERITED(dstTexture, true, hasMixedSamples),
88 fMode(mode),
89 fHWBlendEquation(static_cast<GrBlendEquation>(-1)) {
90 this->initClassID<CustomXP>();
91 }
92
name() const93 const char* name() const override { return "Custom Xfermode"; }
94
95 GrGLSLXferProcessor* createGLSLInstance() const override;
96
mode() const97 SkXfermode::Mode mode() const { return fMode; }
hasHWBlendEquation() const98 bool hasHWBlendEquation() const { return -1 != static_cast<int>(fHWBlendEquation); }
99
hwBlendEquation() const100 GrBlendEquation hwBlendEquation() const {
101 SkASSERT(this->hasHWBlendEquation());
102 return fHWBlendEquation;
103 }
104
105 private:
106 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
107 bool doesStencilWrite,
108 GrColor* overrideColor,
109 const GrCaps& caps) const override;
110
111 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
112
113 GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const override;
114
115 void onGetBlendInfo(BlendInfo*) const override;
116
117 bool onIsEqual(const GrXferProcessor& xpBase) const override;
118
119 const SkXfermode::Mode fMode;
120 const GrBlendEquation fHWBlendEquation;
121
122 typedef GrXferProcessor INHERITED;
123 };
124
125 ///////////////////////////////////////////////////////////////////////////////
126
127 class GLCustomXP : public GrGLSLXferProcessor {
128 public:
GLCustomXP(const GrXferProcessor &)129 GLCustomXP(const GrXferProcessor&) {}
~GLCustomXP()130 ~GLCustomXP() override {}
131
GenKey(const GrXferProcessor & p,const GrGLSLCaps & caps,GrProcessorKeyBuilder * b)132 static void GenKey(const GrXferProcessor& p, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) {
133 const CustomXP& xp = p.cast<CustomXP>();
134 uint32_t key = 0;
135 if (xp.hasHWBlendEquation()) {
136 SkASSERT(caps.advBlendEqInteraction() > 0); // 0 will mean !xp.hasHWBlendEquation().
137 key |= caps.advBlendEqInteraction();
138 GR_STATIC_ASSERT(GrGLSLCaps::kLast_AdvBlendEqInteraction < 4);
139 }
140 if (!xp.hasHWBlendEquation() || caps.mustEnableSpecificAdvBlendEqs()) {
141 key |= xp.mode() << 3;
142 }
143 b->add32(key);
144 }
145
146 private:
emitOutputsForBlendState(const EmitArgs & args)147 void emitOutputsForBlendState(const EmitArgs& args) override {
148 const CustomXP& xp = args.fXP.cast<CustomXP>();
149 SkASSERT(xp.hasHWBlendEquation());
150
151 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
152 fragBuilder->enableAdvancedBlendEquationIfNeeded(xp.hwBlendEquation());
153
154 // Apply coverage by multiplying it into the src color before blending. Mixed samples will
155 // "just work" automatically. (See onGetOptimizations())
156 if (args.fInputCoverage) {
157 fragBuilder->codeAppendf("%s = %s * %s;",
158 args.fOutputPrimary, args.fInputCoverage, args.fInputColor);
159 } else {
160 fragBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
161 }
162 }
163
emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const char * srcColor,const char * srcCoverage,const char * dstColor,const char * outColor,const char * outColorSecondary,const GrXferProcessor & proc)164 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
165 GrGLSLUniformHandler* uniformHandler,
166 const char* srcColor,
167 const char* srcCoverage,
168 const char* dstColor,
169 const char* outColor,
170 const char* outColorSecondary,
171 const GrXferProcessor& proc) override {
172 const CustomXP& xp = proc.cast<CustomXP>();
173 SkASSERT(!xp.hasHWBlendEquation());
174
175 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.mode());
176
177 // Apply coverage.
178 INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
179 outColorSecondary, xp);
180 }
181
onSetData(const GrGLSLProgramDataManager &,const GrXferProcessor &)182 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
183
184 typedef GrGLSLXferProcessor INHERITED;
185 };
186
187 ///////////////////////////////////////////////////////////////////////////////
188
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const189 void CustomXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
190 GLCustomXP::GenKey(*this, caps, b);
191 }
192
createGLSLInstance() const193 GrGLSLXferProcessor* CustomXP::createGLSLInstance() const {
194 SkASSERT(this->willReadDstColor() != this->hasHWBlendEquation());
195 return new GLCustomXP(*this);
196 }
197
onIsEqual(const GrXferProcessor & other) const198 bool CustomXP::onIsEqual(const GrXferProcessor& other) const {
199 const CustomXP& s = other.cast<CustomXP>();
200 return fMode == s.fMode && fHWBlendEquation == s.fHWBlendEquation;
201 }
202
onGetOptimizations(const GrPipelineOptimizations & optimizations,bool doesStencilWrite,GrColor * overrideColor,const GrCaps & caps) const203 GrXferProcessor::OptFlags CustomXP::onGetOptimizations(const GrPipelineOptimizations& optimizations,
204 bool doesStencilWrite,
205 GrColor* overrideColor,
206 const GrCaps& caps) const {
207 /*
208 Most the optimizations we do here are based on tweaking alpha for coverage.
209
210 The general SVG blend equation is defined in the spec as follows:
211
212 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
213 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
214
215 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
216 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
217 RGB colors.)
218
219 For every blend mode supported by this class, i.e. the "advanced" blend
220 modes, X=Y=Z=1 and this equation reduces to the PDF blend equation.
221
222 It can be shown that when X=Y=Z=1, these equations can modulate alpha for
223 coverage.
224
225
226 == Color ==
227
228 We substitute Y=Z=1 and define a blend() function that calculates Dca' in
229 terms of premultiplied alpha only:
230
231 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
232 Sca : if Da == 0,
233 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa) : if Sa,Da != 0}
234
235 And for coverage modulation, we use a post blend src-over model:
236
237 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
238
239 (Where f is the fractional coverage.)
240
241 Next we show that canTweakAlphaForCoverage() is true by proving the
242 following relationship:
243
244 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
245
246 General case (f,Sa,Da != 0):
247
248 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
249 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f) * Dca [Sa,Da != 0, definition of blend()]
250 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
251 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * Sa + Dca - f*Dca
252 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
253 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
254 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
255 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0]
256 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()]
257
258 Corner cases (Sa=0, Da=0, and f=0):
259
260 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
261 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()]
262 = Dca
263 = blend(0, Dca, 0, Da) [definition of blend()]
264 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0]
265
266 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
267 = f * Sca + (1-f) * Dca [Da=0, definition of blend()]
268 = f * Sca [Da=0]
269 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()]
270 = blend(f*Sca, Dca, f*Sa, Da) [Da=0]
271
272 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
273 = Dca [f=0]
274 = blend(0, Dca, 0, Da) [definition of blend()]
275 = blend(f*Sca, Dca, f*Sa, Da) [f=0]
276
277 == Alpha ==
278
279 We substitute X=Y=Z=1 and define a blend() function that calculates Da':
280
281 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
282 = Sa * Da + Sa - Sa * Da + Da - Da * Sa
283 = Sa + Da - Sa * Da
284
285 We use the same model for coverage modulation as we did with color:
286
287 Da'' = f * blend(Sa, Da) + (1-f) * Da
288
289 And show that canTweakAlphaForCoverage() is true by proving the following
290 relationship:
291
292 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
293
294
295 f * blend(Sa, Da) + (1-f) * Da
296 = f * (Sa + Da - Sa * Da) + (1-f) * Da
297 = f*Sa + f*Da - f*Sa * Da + Da - f*Da
298 = f*Sa - f*Sa * Da + Da
299 = f*Sa + Da - f*Sa * Da
300 = blend(f*Sa, Da)
301 */
302
303 OptFlags flags = kNone_OptFlags;
304 if (optimizations.fColorPOI.allStagesMultiplyInput()) {
305 flags |= kCanTweakAlphaForCoverage_OptFlag;
306 }
307 if (this->hasHWBlendEquation() && optimizations.fCoveragePOI.isSolidWhite()) {
308 flags |= kIgnoreCoverage_OptFlag;
309 }
310 return flags;
311 }
312
onXferBarrier(const GrRenderTarget * rt,const GrCaps & caps) const313 GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const {
314 if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) {
315 return kBlend_GrXferBarrierType;
316 }
317 return kNone_GrXferBarrierType;
318 }
319
onGetBlendInfo(BlendInfo * blendInfo) const320 void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
321 if (this->hasHWBlendEquation()) {
322 blendInfo->fEquation = this->hwBlendEquation();
323 }
324 }
325
326 ///////////////////////////////////////////////////////////////////////////////
327 class CustomXPFactory : public GrXPFactory {
328 public:
329 CustomXPFactory(SkXfermode::Mode mode);
330
331 void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
332 GrXPFactory::InvariantBlendedColor*) const override;
333
334 private:
335 GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
336 const GrPipelineOptimizations& optimizations,
337 bool hasMixedSamples,
338 const DstTexture*) const override;
339
340 bool onWillReadDstColor(const GrCaps& caps,
341 const GrPipelineOptimizations& optimizations,
342 bool hasMixedSamples) const override;
343
onIsEqual(const GrXPFactory & xpfBase) const344 bool onIsEqual(const GrXPFactory& xpfBase) const override {
345 const CustomXPFactory& xpf = xpfBase.cast<CustomXPFactory>();
346 return fMode == xpf.fMode;
347 }
348
349 GR_DECLARE_XP_FACTORY_TEST;
350
351 SkXfermode::Mode fMode;
352 GrBlendEquation fHWBlendEquation;
353
354 typedef GrXPFactory INHERITED;
355 };
356
CustomXPFactory(SkXfermode::Mode mode)357 CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode)
358 : fMode(mode),
359 fHWBlendEquation(hw_blend_equation(mode)) {
360 SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
361 this->initClassID<CustomXPFactory>();
362 }
363
onCreateXferProcessor(const GrCaps & caps,const GrPipelineOptimizations & opt,bool hasMixedSamples,const DstTexture * dstTexture) const364 GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
365 const GrPipelineOptimizations& opt,
366 bool hasMixedSamples,
367 const DstTexture* dstTexture) const {
368 if (can_use_hw_blend_equation(fHWBlendEquation, opt, caps)) {
369 SkASSERT(!dstTexture || !dstTexture->texture());
370 return new CustomXP(fMode, fHWBlendEquation);
371 }
372 return new CustomXP(dstTexture, hasMixedSamples, fMode);
373 }
374
onWillReadDstColor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples) const375 bool CustomXPFactory::onWillReadDstColor(const GrCaps& caps,
376 const GrPipelineOptimizations& optimizations,
377 bool hasMixedSamples) const {
378 return !can_use_hw_blend_equation(fHWBlendEquation, optimizations, caps);
379 }
380
getInvariantBlendedColor(const GrProcOptInfo & colorPOI,InvariantBlendedColor * blendedColor) const381 void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
382 InvariantBlendedColor* blendedColor) const {
383 blendedColor->fWillBlendWithDst = true;
384 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
385 }
386
387 GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
TestCreate(GrProcessorTestData * d)388 const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) {
389 int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1,
390 SkXfermode::kLastSeparableMode);
391
392 return new CustomXPFactory(static_cast<SkXfermode::Mode>(mode));
393 }
394
395 ///////////////////////////////////////////////////////////////////////////////
396
CreateXPFactory(SkXfermode::Mode mode)397 GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
398 if (!GrCustomXfermode::IsSupportedMode(mode)) {
399 return nullptr;
400 } else {
401 return new CustomXPFactory(mode);
402 }
403 }
404