OLD | NEW |
---|---|
(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 } | |
OLD | NEW |