Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(272)

Side by Side Diff: src/gpu/effects/GrAdvancedEquationXferProcessor.cpp

Issue 1037123003: Implement support for KHR_blend_equation_advanced (Closed) Base URL: https://skia.googlesource.com/skia.git@upload_zzz2_barriers
Patch Set: Addressed comments Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/GrAdvancedEquationXferProcessor.h"
9
10 #include "GrDrawTargetCaps.h"
11 #include "GrGpu.h"
12 #include "gl/GrGLXferProcessor.h"
13 #include "gl/builders/GrGLFragmentShaderBuilder.h"
14 #include "gl/builders/GrGLProgramBuilder.h"
15
16 class AdvancedEquationXPBase : public GrXferProcessor {
17 public:
18 static AdvancedEquationXPBase* Create(bool hasCoverage, GrBlendEquation equa tion);
19 AdvancedEquationXPBase(GrBlendEquation equation) : fEquation(equation) {}
20
21 const char* name() const override { return "Blend Equation Advanced"; }
22 bool hasSecondaryOutput() const override { return false; }
23
24 bool willNeedXferBarrier(const GrRenderTarget* rt, const GrDrawTargetCaps&,
25 GrXferBarrierType* outBarrierType) const override;
26
27 protected:
28 void onGetGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const over ride;
29
30 void onGetBlendInfo(BlendInfo*) const override;
31
32 bool onIsEqual(const GrXferProcessor& xpBase) const override {
33 const AdvancedEquationXPBase& xp = xpBase.cast<AdvancedEquationXPBase>() ;
34 return fEquation == xp.fEquation;
35 }
36
37 const GrBlendEquation fEquation;
38
39 typedef GrXferProcessor INHERITED;
40 };
41
42 template<bool HasCoverage> class AdvancedEquationXP: public AdvancedEquationXPBa se {
43 public:
44 AdvancedEquationXP(GrBlendEquation equation) : INHERITED(equation) {
45 this->initClassID<AdvancedEquationXP>();
46 }
47
48 OptFlags getOptimizations(const GrProcOptInfo&, const GrProcOptInfo&, bool, GrColor*,
49 const GrDrawTargetCaps&) override;
50
51 GrGLXferProcessor* createGLInstance() const override;
52
53 private:
54 typedef AdvancedEquationXPBase INHERITED;
55 };
56
57
58 bool GrAdvancedEquationXPFactory::IsSupported(const GrContext* context, SkXfermo de::Mode mode) {
59 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) {
60 return false;
61 }
62 if (mode > SkXfermode::kLastMode) {
63 return false;
64 }
65 return mode == SkXfermode::kScreen_Mode || mode > SkXfermode::kLastCoeffMode ;
66 }
67
68 GrXPFactory* GrAdvancedEquationXPFactory::Create(SkXfermode::Mode mode) {
69 switch (mode) {
70 default: break;
71 case SkXfermode::kScreen_Mode: return RefFactory<kScreen_GrBlendEquation >();
72 case SkXfermode::kOverlay_Mode: return RefFactory<kOverlay_GrBlendEquati on>();
73 case SkXfermode::kDarken_Mode: return RefFactory<kDarken_GrBlendEquation >();
74 case SkXfermode::kLighten_Mode: return RefFactory<kLighten_GrBlendEquati on>();
75 case SkXfermode::kColorDodge_Mode: return RefFactory<kColorDodge_GrBlend Equation>();
76 case SkXfermode::kColorBurn_Mode: return RefFactory<kColorBurn_GrBlendEq uation>();
77 case SkXfermode::kHardLight_Mode: return RefFactory<kHardLight_GrBlendEq uation>();
78 case SkXfermode::kSoftLight_Mode: return RefFactory<kSoftLight_GrBlendEq uation>();
79 case SkXfermode::kDifference_Mode: return RefFactory<kDifference_GrBlend Equation>();
80 case SkXfermode::kExclusion_Mode: return RefFactory<kExclusion_GrBlendEq uation>();
81 case SkXfermode::kMultiply_Mode: return RefFactory<kMultiply_GrBlendEqua tion>();
82 case SkXfermode::kHue_Mode: return RefFactory<kHSLHue_GrBlendEquation>() ;
83 case SkXfermode::kSaturation_Mode: return RefFactory<kHSLSaturation_GrBl endEquation>();
84 case SkXfermode::kColor_Mode: return RefFactory<kHSLColor_GrBlendEquatio n>();
85 case SkXfermode::kLuminosity_Mode: return RefFactory<kHSLLuminosity_GrBl endEquation>();
86 }
87
88 return NULL;
89 }
90
91 template<GrBlendEquation Equation> GrXPFactory* GrAdvancedEquationXPFactory::Ref Factory() {
92 GR_STATIC_ASSERT(GrBlendEquationIsAdvanced(Equation));
93 static GrAdvancedEquationXPFactory* factory;
94 if (!factory) {
95 factory = SkNEW_ARGS(GrAdvancedEquationXPFactory, (Equation));
96 }
97 return SkRef(factory);
98 }
99
100 bool GrAdvancedEquationXPFactory::canTweakAlphaForCoverage() const {
101 /*
102 The general SVG blend equation is defined in the spec as follows:
103
104 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
105 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
106
107 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
108 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
109 RGB colors.)
110
111 For every "advanced" blend mode, X=Y=Z=1 and this equation reduces to the
112 PDF blend equation.
113
114 It can be shown that when X=Y=Z=1, canTweakAlphaForCoverage() is true.
115
116
117 == Color ==
118
119 We substitute Y=Z=1 and define a blend() function that calculates Dca' in
120 terms of premultiplied alpha only:
121
122 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
123 Sca : if Da == 0,
124 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dc a * (1-Sa) : if Sa,Da != 0}
125
126 And for coverage modulation, we use a post blend src-over model:
127
128 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
129
130 (Where f is the fractional coverage.)
131
132 Next we show that canTweakAlphaForCoverage() is true by proving the
133 following relationship:
134
135 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
136
137 General case (f,Sa,Da != 0):
138
139 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
140 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f ) * Dca [Sa,Da != 0, definition of blend()]
141 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
142 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * S a + Dca - f*Dca
143 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
144 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
145 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
146 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0]
147 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()]
148
149 Corner cases (Sa=0, Da=0, and f=0):
150
151 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
152 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()]
153 = Dca
154 = blend(0, Dca, 0, Da) [definition of blend()]
155 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0]
156
157 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
158 = f * Sca + (1-f) * Dca [Da=0, definition of blend()]
159 = f * Sca [Da=0]
160 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()]
161 = blend(f*Sca, Dca, f*Sa, Da) [Da=0]
162
163 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
164 = Dca [f=0]
165 = blend(0, Dca, 0, Da) [definition of blend()]
166 = blend(f*Sca, Dca, f*Sa, Da) [f=0]
167
168 == Alpha ==
169
170 We substitute X=Y=Z=1 and define a blend() function that calculates Da':
171
172 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
173 = Sa * Da + Sa - Sa * Da + Da - Da * Sa
174 = Sa + Da - Sa * Da
175
176 We use the same model for coverage modulation as we did with color:
177
178 Da'' = f * blend(Sa, Da) + (1-f) * Da
179
180 And show that canTweakAlphaForCoverage() is true by proving the following
181 relationship:
182
183 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
184
185
186 f * blend(Sa, Da) + (1-f) * Da
187 = f * (Sa + Da - Sa * Da) + (1-f) * Da
188 = f*Sa + f*Da - f*Sa * Da + Da - f*Da
189 = f*Sa - f*Sa * Da + Da
190 = f*Sa + Da - f*Sa * Da
191 = blend(f*Sa, Da)
192 */
193
194 return true;
195 }
196
197 bool GrAdvancedEquationXPFactory::supportsRGBCoverage(GrColor, uint32_t) const {
198 /*
199 We do coverage modulation by multiplying it into the src color before
200 blending. The GPU runs the blend equation *after* the fragment shader, so
201 it is not within our control to apply coverage at that point. This model
202 is mathematically correct, but it only works with scalar coverage. It's easy
203 to see why it won't work when coverage is unique per component:
204
205 blend(fc*Sca, Dca, fa*Sa, Da)
206 = B((fc*Sca)/(fa*Sa), Dca/Da) * ...
207 != B(Sc, Dc) * ...
208
209 The arguments for B() no longer reduce to (Sc, Dc). And when Sc == 0, the
210 arguments for B() work, but the equation still doesn't:
211
212 fc * blend(0, Dca, Sa, Da) + (1-fc) * Dca
213 = ...
214 = B(0, Dca/Da) * fc*Sa * Da + fc*0 * (1-Da) + Dca * (1 - fc*Sa)
215 = blend(fc*0, Dca, fc*Sa, Da)
216 != blend(fc*0, Dca, fa*Sa, Da)
217
218 (Note that this could work if we knew the dst was transparent black.)
219 */
220
221 return false;
Chris Dalton 2015/04/22 19:17:01 One thing I haven't done yet is a fallback for RGB
bsalomon 2015/04/24 16:22:22 Unfortunately, we don't know until later whether t
Chris Dalton 2015/04/24 18:45:01 Ok, then that isn't going to work :). So consider
222 }
223
224 GrXferProcessor* GrAdvancedEquationXPFactory::onCreateXferProcessor(
225 const GrDrawTargetCaps& caps,
226 const GrProcOptInfo& col orPOI,
227 const GrProcOptInfo& cov eragePOI,
228 const GrDeviceCoordTextu re* dstCopy) const {
229 SkASSERT(!dstCopy || !dstCopy->texture());
230
231 if (!caps.advancedBlendEquationSupport()) {
232 return NULL;
233 }
234 if (coveragePOI.isFourChannelOutput()) {
235 // RGB coverage is not supported. (See supportsRGBCoverage())
236 return NULL;
237 }
238 return AdvancedEquationXPBase::Create(!coveragePOI.isSolidWhite(), fEquation );
239 }
240
241 AdvancedEquationXPBase* AdvancedEquationXPBase::Create(bool hasCoverage, GrBlend Equation equation) {
242 if (hasCoverage) {
243 return SkNEW_ARGS(AdvancedEquationXP<true>, (equation));
244 } else {
245 return SkNEW_ARGS(AdvancedEquationXP<false>, (equation));
246 }
247 }
248
249 bool AdvancedEquationXPBase::willNeedXferBarrier(const GrRenderTarget*,
250 const GrDrawTargetCaps& caps,
251 GrXferBarrierType* outBarrierTy pe) const {
252 if (GrDrawTargetCaps::kAdvancedCoherent_BlendEquationSupport != caps.blendEq uationSupport()) {
253 *outBarrierType = kBlend_GrXferBarrierType;
254 return true;
255 }
256 return false;
257 }
258
259 void AdvancedEquationXPBase::onGetGLProcessorKey(const GrGLCaps&, GrProcessorKey Builder*) const {
260 // Our XP's don't emit variable fragment code. (HasCoverage is accounted for by the class ID.)
261 return;
262 }
263
264 template</*HasCoverage = false*/>
265 GrXferProcessor::OptFlags AdvancedEquationXP<false>::getOptimizations(const GrPr ocOptInfo&,
266 const GrPr ocOptInfo&,
267 bool, GrCo lor*,
268 const GrDr awTargetCaps&) {
269 return kIgnoreCoverage_OptFlag;
270 }
271
272 template</*HasCoverage = false*/>
273 GrGLXferProcessor* AdvancedEquationXP<false>::createGLInstance() const {
274 class GLAdvancedEquationXP : public GrGLXferProcessor {
275 private:
276 void onEmitCode(const EmitArgs& args) override {
277 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r();
278 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputC olor);
279 }
280 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {}
281 };
282 return SkNEW(GLAdvancedEquationXP);
283 }
284
285 template</*HasCoverage = true*/>
286 GrXferProcessor::OptFlags AdvancedEquationXP<true>::getOptimizations(const GrPro cOptInfo&,
287 const GrPro cOptInfo&,
288 bool, GrCol or*,
289 const GrDra wTargetCaps&) {
290 return kNone_Opt;
291 }
292
293 template</*HasCoverage = true*/>
294 GrGLXferProcessor* AdvancedEquationXP<true>::createGLInstance() const {
295 class GLAdvancedEquationXPWithCoverage : public GrGLXferProcessor {
296 private:
297 void onEmitCode(const EmitArgs& args) override {
298 // We do coverage modulation by multiplying it into the src color be fore blending.
299 // (See canTweakAlphaForCoverage())
300 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r();
301 fsBuilder->codeAppendf("%s = %s * %s;",
302 args.fOutputPrimary, args.fInputColor, args.f InputCoverage);
303 }
304 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {}
305 };
306 return SkNEW(GLAdvancedEquationXPWithCoverage);
307 }
308
309 void AdvancedEquationXPBase::onGetBlendInfo(BlendInfo* blendInfo) const {
310 SkASSERT(GrBlendEquationIsAdvanced(fEquation));
311 blendInfo->fEquation = fEquation;
312 }
313
314
315 GR_DEFINE_XP_FACTORY_TEST(GrAdvancedEquationXPFactory);
316
317 GrXPFactory* GrAdvancedEquationXPFactory::TestCreate(SkRandom* random,
318 GrContext* context,
319 const GrDrawTargetCaps& cap s,
320 GrTexture*[]) {
321 int mode = random->nextRangeU(SkXfermode::kLastCoeffMode, SkXfermode::kLastM ode);
322 if (SkXfermode::kLastCoeffMode == mode) {
323 mode = SkXfermode::kScreen_Mode;
324 }
325 return GrAdvancedEquationXPFactory::Create(static_cast<SkXfermode::Mode>(mod e));
326 }
OLDNEW
« include/gpu/GrXferProcessor.h ('K') | « src/gpu/SkGr.cpp ('k') | src/gpu/gl/GrGLCaps.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698