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

Side by Side Diff: src/gpu/effects/GrAdvancedEquationXPFactory.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
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/GrAdvancedEquationXPFactory.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 bool GrAdvancedEquationXPFactory::IsSupported(const GrContext* context, SkXfermo de::Mode mode) {
17 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) {
18 return false;
19 }
20 if (mode > SkXfermode::kLastMode) {
21 return false;
22 }
23 return mode == SkXfermode::kScreen_Mode || mode > SkXfermode::kLastCoeffMode ;
24 }
25
26 template<GrBlendEquation Equation> GrXPFactory* GrAdvancedEquationXPFactory::Tak eFactoryRef() {
27 GR_STATIC_ASSERT(GrBlendEquationIsAdvanced(Equation));
28 static GrAdvancedEquationXPFactory* factory;
29 if (!factory) {
30 factory = SkNEW_ARGS(GrAdvancedEquationXPFactory, (Equation));
31 }
32 return SkRef(factory);
33 }
34
35 GrXPFactory* GrAdvancedEquationXPFactory::Create(const GrContext* context, SkXfe rmode::Mode mode) {
36 if (!context->getGpu()->caps()->advancedBlendEquationSupport()) {
37 return NULL;
38 }
39
40 switch (mode) {
41 default: break;
42 case SkXfermode::kScreen_Mode: return TakeFactoryRef<kScreen_GrBlendEqua tion>();
43 case SkXfermode::kOverlay_Mode: return TakeFactoryRef<kOverlay_GrBlendEq uation>();
44 case SkXfermode::kDarken_Mode: return TakeFactoryRef<kDarken_GrBlendEqua tion>();
45 case SkXfermode::kLighten_Mode: return TakeFactoryRef<kLighten_GrBlendEq uation>();
46 case SkXfermode::kColorDodge_Mode: return TakeFactoryRef<kColorDodge_GrB lendEquation>();
47 case SkXfermode::kColorBurn_Mode: return TakeFactoryRef<kColorBurn_GrBle ndEquation>();
48 case SkXfermode::kHardLight_Mode: return TakeFactoryRef<kHardLight_GrBle ndEquation>();
49 case SkXfermode::kSoftLight_Mode: return TakeFactoryRef<kSoftLight_GrBle ndEquation>();
50 case SkXfermode::kDifference_Mode: return TakeFactoryRef<kDifference_GrB lendEquation>();
51 case SkXfermode::kExclusion_Mode: return TakeFactoryRef<kExclusion_GrBle ndEquation>();
52 case SkXfermode::kMultiply_Mode: return TakeFactoryRef<kMultiply_GrBlend Equation>();
53 case SkXfermode::kHue_Mode: return TakeFactoryRef<kHSLHue_GrBlendEquatio n>();
54 case SkXfermode::kSaturation_Mode: return TakeFactoryRef<kHSLSaturation_ GrBlendEquation>();
55 case SkXfermode::kColor_Mode: return TakeFactoryRef<kHSLColor_GrBlendEqu ation>();
56 case SkXfermode::kLuminosity_Mode: return TakeFactoryRef<kHSLLuminosity_ GrBlendEquation>();
57 }
58
59 return NULL;
60 }
61
62 bool GrAdvancedEquationXPFactory::canTweakAlphaForCoverage() const {
63 /*
64 The general SVG blend equation is defined in the spec as follows:
65
66 Dca' = B(Sc, Dc) * Sa * Da + Y * Sca * (1-Da) + Z * Dca * (1-Sa)
67 Da' = X * Sa * Da + Y * Sa * (1-Da) + Z * Da * (1-Sa)
68
69 (Note that Sca, Dca indicate RGB vectors that are premultiplied by alpha,
70 and that B(Sc, Dc) is a mode-specific function that accepts non-multiplied
71 RGB colors.)
72
73 For every "advanced" blend mode, X=Y=Z=1 and this equation reduces to the
74 PDF blend equation.
75
76 It can be shown that when X=Y=Z=1, canTweakAlphaForCoverage() is true.
Mark Kilgard 2015/04/03 18:30:03 great to see this analysis
77
78
79 == Color ==
80
81 We substitute Y=Z=1 and define a blend() function that calculates Dca' in
82 terms of premultiplied alpha only:
83
84 blend(Sca, Dca, Sa, Da) = {Dca : if Sa == 0,
85 Sca : if Da == 0,
86 B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dc a * (1-Sa) : if Sa,Da != 0}
87
88 And for coverage modulation, Skia uses a post blend src-over model:
89
90 Dca'' = f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
91
92 (Where f is the fractional coverage.)
93
94 Next we show that canTweakAlphaForCoverage() is true by proving the
95 following relationship:
96
97 blend(f*Sca, Dca, f*Sa, Da) == f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
98
99 Corner cases (Sa=0, Da=0, and f=0):
100
101 Sa=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
102 = f * Dca + (1-f) * Dca [Sa=0, definition of blend()]
103 = Dca
104 = blend(0, Dca, 0, Da) [definition of blend()]
105 = blend(f*Sca, Dca, f*Sa, Da) [Sa=0]
106
107 Da=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
108 = f * Sca + (1-f) * Dca [Da=0, definition of blend()]
109 = f * Sca [Da=0]
110 = blend(f*Sca, 0, f*Sa, 0) [definition of blend()]
111 = blend(f*Sca, Dca, f*Sa, Da) [Da=0]
112
113 f=0: f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
114 = Dca [f=0]
115 = blend(0, Dca, 0, Da) [definition of blend()]
116 = blend(f*Sca, Dca, f*Sa, Da) [f=0]
117
118 General case (f,Sa,Da != 0):
119
120 f * blend(Sca, Dca, Sa, Da) + (1-f) * Dca
121 = f * (B(Sca/Sa, Dca/Da) * Sa * Da + Sca * (1-Da) + Dca * (1-Sa)) + (1-f ) * Dca [Sa,Da != 0, definition of blend()]
122 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + f*Dca * (1-Sa) + Dca - f*Dca
123 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da + f*Dca - f*Dca * S a + Dca - f*Dca
124 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca - f*Sca * Da - f*Dca * Sa + Dca
125 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) - f*Dca * Sa + Dca
126 = B(Sca/Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa)
127 = B(f*Sca/f*Sa, Dca/Da) * f*Sa * Da + f*Sca * (1-Da) + Dca * (1 - f*Sa) [f!=0]
128 = blend(f*Sca, Dca, f*Sa, Da) [definition of blend()]
Mark Kilgard 2015/04/03 18:30:04 great analysis I think you should motivate the "C
Chris Dalton 2015/04/17 08:37:18 Done.
129
130
131 == Alpha ==
132
133 We substitute X=Y=Z=1 and define a blend() function that calculates Da':
134
135 blend(Sa, Da) = Sa * Da + Sa * (1-Da) + Da * (1-Sa)
136 = Sa * Da + Sa - Sa * Da + Da - Da * Sa
137 = Sa + Da - Sa * Da
138
139 We use the same model for coverage modulation as we did with color:
140
141 Da'' = f * blend(Sa, Da) + (1-f) * Da
142
143 And show that canTweakAlphaForCoverage() is true by proving the following
144 relationship:
145
146 blend(f*Sa, Da) == f * blend(Sa, Da) + (1-f) * Da
147
148
149 f * blend(Sa, Da) + (1-f) * Da
150 = f * (Sa + Da - Sa * Da) + (1-f) * Da
151 = f*Sa + f*Da - f*Sa * Da + Da - f*Da
152 = f*Sa - f*Sa * Da + Da
153 = f*Sa + Da - f*Sa * Da
154 = blend(f*Sa, Da)
155 */
156
157 return true;
158 }
159
160 bool GrAdvancedEquationXPFactory::supportsRGBCoverage(GrColor knownColor,
161 uint32_t knownColorFlags) const {
162 /*
163 We do coverage modulation by multiplying it into the src color before
164 blending. The GPU runs the blend equation *after* the fragment shader, so
165 it is not within our control to apply coverage at that point. This model
166 is mathematically correct, but the proof lies in the following property:
167
168 f*Sca / f*Sa == Sc
169
170 (That is, the general case, f,Sa,Da != 0. See canTweakAlphaForCoverage().)
171
172 But when coverage is unique per channel, this property no longer holds:
Mark Kilgard 2015/04/03 18:30:03 "when coverage is unique per channel" ?? huh? Wh
Chris Dalton 2015/04/17 08:37:19 Yeah, "RGB coverage" in the context of GrXferProce
173
174 fc*Sca / fa*Sa == fc/fa * Sc != Sc [fc!=fa]
175
176 The only time it is still true is when Sc == 0.
Chris Dalton 2015/03/31 10:51:49 This is most likely wrong. I'll update the comment
177
178 (It would also work out if we could know the dst color was trans black.)
Mark Kilgard 2015/04/03 18:30:03 I'm assume by "trans black" you mean transparent b
179 */
180
181 return kRGB_GrColorComponentFlags == (knownColorFlags & kRGB_GrColorComponen tFlags) &&
182 0 == (knownColor & ~(0xffu << GrColor_SHIFT_A)); // RGB=0
Mark Kilgard 2015/04/03 18:30:03 Is there not some constant to use instead of 0xffu
Chris Dalton 2015/04/17 08:37:19 That code is completely gone now.
183 }
184
185 bool GrAdvancedEquationXPFactory::willBlendCoherently(const GrDrawTargetCaps& ca ps) const {
186 return GrDrawTargetCaps::kAdvancedCoherent_BlendEquationSupport == caps.blen dEquationSupport();
187 }
188
189 GrXferProcessor* GrAdvancedEquationXPFactory::onCreateXferProcessor(
190 const GrDrawTargetCaps& caps,
191 const GrProcOptInfo& col orPOI,
192 const GrProcOptInfo& cov eragePOI,
Mark Kilgard 2015/04/03 18:30:03 wish I knew what "XP" stands for can I assume POI
Chris Dalton 2015/04/17 08:37:19 XP = Xfer Processor = An object that controls the
193 const GrDeviceCoordTextu re* dstCopy) const {
194 SkASSERT(caps.advancedBlendEquationSupport());
195 SkASSERT(!dstCopy || !dstCopy->texture());
196
197 if (coveragePOI.isFourChannelOutput() && !this->supportsRGBCoverage(colorPOI .color(),
198 colorPOI .validFlags())) {
199 return NULL;
200 }
201 if (!coveragePOI.isSolidWhite()) {
202 return SkRef(&fXferProcessorWithCoverage);
203 }
204 return SkRef(&fXferProcessor);
205 }
206
207 void GrAdvancedEquationXPFactory::XferProcessorBase::onGetGLProcessorKey(const G rGLCaps&,
208 GrProcessor KeyBuilder*) const {
209 // Our XP's don't emit variable fragment code. (HasCoverage is accounted for by the class ID.)
210 return;
211 }
212
213 template</*HasCoverage = true*/>
214 GrGLXferProcessor* GrAdvancedEquationXPFactory::XferProcessor<true>::createGLIns tance() const {
215 class GLXferProcessorWithCoverage : public GrGLXferProcessor {
216 private:
217 void onEmitCode(const EmitArgs& args) override {
218 // We do coverage modulation by multiplying it into the src color be fore blending.
219 // (See canTweakAlphaForCoverage())
220 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r();
221 fsBuilder->codeAppendf("%s = %s * %s;",
222 args.fOutputPrimary, args.fInputColor, args.f InputCoverage);
223 }
224 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {}
225 };
226 return SkNEW(GLXferProcessorWithCoverage);
227 }
228
229 template</*HasCoverage = false*/>
230 GrGLXferProcessor* GrAdvancedEquationXPFactory::XferProcessor<false>::createGLIn stance() const {
231 class GLXferProcessor : public GrGLXferProcessor {
232 private:
233 void onEmitCode(const EmitArgs& args) override {
234 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde r();
235 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputC olor);
236 }
237 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) ov erride {}
238 };
239 return SkNEW(GLXferProcessor);
240 }
241
242 void GrAdvancedEquationXPFactory::XferProcessorBase::onGetBlendInfo(BlendInfo* b lendInfo) const {
243 SkASSERT(GrBlendEquationIsAdvanced(fEquation));
244 blendInfo->fEquation = fEquation;
245 }
246
247
248 GR_DEFINE_XP_FACTORY_TEST(GrAdvancedEquationXPFactory);
249
250 GrXPFactory* GrAdvancedEquationXPFactory::TestCreate(SkRandom* random,
251 GrContext* context,
252 const GrDrawTargetCaps& cap s,
253 GrTexture*[]) {
254 int mode = random->nextRangeU(SkXfermode::kLastCoeffMode, SkXfermode::kLastM ode);
255 if (mode == SkXfermode::kLastCoeffMode) {
256 mode = SkXfermode::kScreen_Mode;
257 }
258 return GrAdvancedEquationXPFactory::Create(context, static_cast<SkXfermode:: Mode>(mode));
259 }
OLDNEW
« no previous file with comments | « src/gpu/SkGr.cpp ('k') | src/gpu/gl/GrGLCaps.cpp » ('j') | src/gpu/gl/GrGLCaps.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698