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

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