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

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

Issue 1124373002: Implement Porter Duff XP with a blend table (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add coverage at runtime Created 5 years, 7 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
1 /* 1 /*
2 * Copyright 2014 Google Inc. 2 * Copyright 2014 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "effects/GrPorterDuffXferProcessor.h" 8 #include "effects/GrPorterDuffXferProcessor.h"
9 9
10 #include "GrBlend.h" 10 #include "GrBlend.h"
11 #include "GrDrawTargetCaps.h" 11 #include "GrDrawTargetCaps.h"
12 #include "GrProcessor.h" 12 #include "GrProcessor.h"
13 #include "GrProcOptInfo.h" 13 #include "GrProcOptInfo.h"
14 #include "GrTypes.h" 14 #include "GrTypes.h"
15 #include "GrXferProcessor.h" 15 #include "GrXferProcessor.h"
16 #include "gl/GrGLXferProcessor.h" 16 #include "gl/GrGLXferProcessor.h"
17 #include "gl/builders/GrGLFragmentShaderBuilder.h" 17 #include "gl/builders/GrGLFragmentShaderBuilder.h"
18 #include "gl/builders/GrGLProgramBuilder.h" 18 #include "gl/builders/GrGLProgramBuilder.h"
19 19
20 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) { 20 /**
21 /* 21 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
22 The fractional coverage is f. 22 */
23 The src and dst coeffs are Cs and Cd. 23 struct BlendFormula {
24 The dst and src colors are S and D. 24 public:
25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the sou rce color's alpha 25 /**
26 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second 26 * Values the shader can write to primary and secondary outputs. These must all be modulated by
27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various poss ibilities for Cd we 27 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. 28 */
29 */ 29 enum OutputType {
30 return kOne_GrBlendCoeff == dstCoeff || 30 kNone_OutputType, //<! 0
31 kISA_GrBlendCoeff == dstCoeff || 31 kCoverage_OutputType, //<! inputCoverage
32 kISC_GrBlendCoeff == dstCoeff; 32 kModulate_OutputType, //<! inputColor * inputCoverage
33 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
34 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
35
36 kLast_OutputType = kISCModulate_OutputType
37 };
38
39 enum CoverageStrategy {
egdaniel 2015/05/21 18:36:45 comments on what these strategies mean?
Chris Dalton 2015/05/21 23:14:49 Done. (Code removed)
40 kModulate_CoverageStrategy,
41 kSrcCoeffZero_CoverageStrategy,
42 kDstCoeffZero_CoverageStrategy,
43 kGeneral_CoverageStrategy,
44
45 kLast_CoverageStrategy = kGeneral_CoverageStrategy
46 };
47
48 enum Properties {
49 kModifiesDst_Property = 1,
50 kUsesDstColor_Property = 1 << 1,
51 kUsesInputColor_Property = 1 << 2,
52 kCanTweakAlphaForCoverage_Property = 1 << 3,
53
54 kLast_Property = kCanTweakAlphaForCoverage_Property
55 };
56
57 /**
58 * Returns an optimized blend formula for the input color and coverage.
59 */
60 static BlendFormula Get(SkXfermode::Mode xfermode,
61 const GrProcOptInfo& colorPOI,
62 const GrProcOptInfo& coveragePOI);
63
64 BlendFormula& operator =(const BlendFormula& other) {
65 fData = other.fData;
66 return *this;
67 }
68
69 bool operator ==(const BlendFormula& other) const {
70 return fData == other.fData;
71 }
72
73 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutpu tType; }
74 bool modifiesDst() const { return fProps & kModifiesDst_Property; }
75 bool usesDstColor() const { return fProps & kUsesDstColor_Property; }
76 bool usesInputColor() const { return fProps & kUsesInputColor_Property; }
77 bool canTweakAlphaForCoverage() const { return fProps & kCanTweakAlphaForCov erage_Property; }
78
79 /**
80 * Rewrite the blend formula to account for coverage.
81 */
82 void addCoverage(const GrProcOptInfo& colorPOI);
83
84 /**
85 * Deduce the coverage strategy for a basic, compile-time constant Porter Du ff formula.
86 */
87 template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
88 struct get_coverage_strategy : SkTIntegralConstant<CoverageStrategy,
89
90 (GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(kAdd_GrBlendEquation, SrcCoeff, D stCoeff) ?
91 kModulate_CoverageStrategy :
92
93 (kZero_GrBlendCoeff == SrcCoeff ?
94 kSrcCoeffZero_CoverageStrategy :
95
96 (kZero_GrBlendCoeff == DstCoeff ?
97 kDstCoeffZero_CoverageStrategy :
98
99 kGeneral_CoverageStrategy)))> {
100 };
101
102 /**
103 * Deduce the properties of a basic, compile-time constant Porter Duff formu la.
104 */
105 template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
106 struct get_properties : SkTIntegralConstant<Properties, static_cast<Properti es>(
107
108 (GR_BLEND_MODIFIES_DST(kAdd_GrBlendEquation, SrcCoeff, DstCoeff) ?
109 kModifiesDst_Property : 0) |
110
111 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
112 kUsesDstColor_Property : 0) |
113
114 (GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff) ?
115 kUsesInputColor_Property : 0) |
116
117 (GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(kAdd_GrBlendEquation, SrcCoeff, D stCoeff) ?
118 kCanTweakAlphaForCoverage_Property : 0))> {
119 };
120
121 union {
122 struct {
123 OutputType fPrimaryOutputType : 3;
124 OutputType fSecondaryOutputType : 3;
125 GrBlendEquation fBlendEquation : 5;
126 GrBlendCoeff fSrcCoeff : 5;
127 GrBlendCoeff fDstCoeff : 5;
128 CoverageStrategy fCoverageStrategy : 2;
129 Properties fProps : 9; // Should bring the l ength to 32.
130
131 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
132 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
133 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
134 GR_STATIC_ASSERT(kLast_CoverageStrategy < (1 << 2));
135 GR_STATIC_ASSERT(kLast_Property < (1 << 9));
136 };
137 uint32_t fData;
138 };
139 };
140
141 GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
142
143 GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
144
145 /**
146 * Init a compile-time constant BlendFormula and automatically deduce fCoverageS trategy and fProps.
147 *
148 */
149 #define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
150 {GR_BLEND_COEFFS_USE_SRC_COLOR(SRC_COEFF, DST_COEFF) ? \
151 BlendFormula::kModulate_OutputType : \
152 BlendFormula::kNone_OutputType, \
153 BlendFormula::kNone_OutputType, \
154 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF, \
155 BlendFormula::get_coverage_strategy<SRC_COEFF, DST_COEFF>::value, \
156 BlendFormula::get_properties<SRC_COEFF, DST_COEFF>::value}
157
158 #define DST_CLEAR_FORMULA COEFF_FORMULA(kZero_GrBlendCoeff, kZero_GrBlendCoeff)
egdaniel 2015/05/21 18:36:45 I don't really care one way or the other, but do y
Chris Dalton 2015/05/21 23:14:49 Done. (They have a purpose again now that we've go
159
160 #define NO_DST_WRITE_FORMULA COEFF_FORMULA(kZero_GrBlendCoeff, kOne_GrBlendCoeff )
161
162 /**
163 * This table outlines the blend formulas we use with each xfermode, both with a nd without an opaque
164 * input color. Optimization properties are deduced at compile time so we can ma ke runtime decisions
165 * quickly. RGB coverage is not supported.
166 */
167 static const BlendFormula gBlendTable[2][SkXfermode::kLastCoeffMode + 1] = {
168
169 /*>> Input color unknown <<*/ {
170
171 /* clear */ DST_CLEAR_FORMULA,
172 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
173 /* dst */ NO_DST_WRITE_FORMULA,
174 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
175 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
176 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
177 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
178 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
179 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
180 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
181 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
182 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
183 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
184 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
185 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
186
187 }, /*>> Input color opaque <<*/ {
188
189 /* clear */ DST_CLEAR_FORMULA,
190 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
191 /* dst */ NO_DST_WRITE_FORMULA,
192 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
193 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
194 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
195 /* dst-in */ NO_DST_WRITE_FORMULA,
196 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
197 /* dst-out */ DST_CLEAR_FORMULA,
198 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
199 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
200 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
201 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
202 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
203 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
204 }};
205
206 /**
207 * Finds the shader output for "(1 - dstCoeff) * inputCoverage".
208 */
209 static BlendFormula::OutputType inverse_dst_coeff_modulate(GrBlendCoeff dstCoeff ) {
210 static BlendFormula::OutputType gOneMinusDstCoeffModulate[] = {
211 BlendFormula::kCoverage_OutputType, //<! kZero_GrBlendCoeff
212 BlendFormula::kNone_OutputType, //<! kOne_GrBlendCoeff
213 BlendFormula::kISCModulate_OutputType, //<! kSC_GrBlendCoeff
214 static_cast<BlendFormula::OutputType>(-1),
215 static_cast<BlendFormula::OutputType>(-1),
216 static_cast<BlendFormula::OutputType>(-1),
217 BlendFormula::kISAModulate_OutputType //<! kSA_GrBlendCoeff
218 };
219
220 SkASSERT(dstCoeff >= 0 && dstCoeff < SK_ARRAY_COUNT(gOneMinusDstCoeffModulat e));
221 SkASSERT(-1 != gOneMinusDstCoeffModulate[dstCoeff]);
222 return gOneMinusDstCoeffModulate[dstCoeff];
223
224 GR_STATIC_ASSERT(0 == kZero_GrBlendCoeff);
225 GR_STATIC_ASSERT(1 == kOne_GrBlendCoeff);
226 GR_STATIC_ASSERT(2 == kSC_GrBlendCoeff);
227 GR_STATIC_ASSERT(6 == kSA_GrBlendCoeff);
33 } 228 }
34 229
230 void BlendFormula::addCoverage(const GrProcOptInfo& colorPOI) {
231 SkASSERT(kModulate_CoverageStrategy == fCoverageStrategy || !this->canTweakA lphaForCoverage());
232 SkASSERT(kModulate_OutputType == fPrimaryOutputType || kNone_OutputType == f PrimaryOutputType);
233 SkASSERT(kNone_OutputType == fSecondaryOutputType);
234 SkASSERT(kAdd_GrBlendEquation == fBlendEquation);
235
236 switch (fCoverageStrategy) {
237 /**
238 * We will get the right answer just by modulating the output color with coverage.
239 */
240 case kModulate_CoverageStrategy:
241 SkASSERT(this->canTweakAlphaForCoverage());
242 return;
243
244 /**
245 * When the src coeff is Zero, the equation with f=coverage becomes:
246 *
247 * D' = f * D * dstCoeff + (1-f) * D
248 *
249 * This can be rewritten as:
250 *
251 * D' = D - D * [f * (1 - dstCoeff)]
252 *
253 * To implement this formula, we output [f * (1 - dstCoeff)] for the pri mary color and use a
254 * reverse subtract HW blend equation with coeffs of (DC, One).
255 */
256 case kSrcCoeffZero_CoverageStrategy:
257 SkASSERT(kZero_GrBlendCoeff == fSrcCoeff);
258 fPrimaryOutputType = inverse_dst_coeff_modulate(fDstCoeff);
259 fBlendEquation = kReverseSubtract_GrBlendEquation;
260 fSrcCoeff = kDC_GrBlendCoeff;
261 fDstCoeff = kOne_GrBlendCoeff;
262 break;
263
264 /**
265 * When the dst coeff is Zero, the equation with f=coverage becomes:
266 *
267 * D' = f * S * srcCoeff + (1-f) * D
268 *
269 * To implement this formula, we output [f] for the secondary color and r eplace the HW dst
270 * coeff with IS2A (or ISA in the case of opaque color).
271 */
272 case kDstCoeffZero_CoverageStrategy:
273 SkASSERT(kZero_GrBlendCoeff != fSrcCoeff && kZero_GrBlendCoeff == fD stCoeff);
274 if (colorPOI.isOpaque()) {
275 fDstCoeff = kISA_GrBlendCoeff;
276 fProps = fProps | kCanTweakAlphaForCoverage_Property;
277 } else {
278 fSecondaryOutputType = kCoverage_OutputType;
279 fDstCoeff = kIS2A_GrBlendCoeff;
280 }
281 break;
282
283 /**
284 * The general equation with f=coverage is:
285 *
286 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
287 *
288 * This can be rewritten as:
289 *
290 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
291 *
292 * To implement this formula, we output [f * (1 - dstCoeff)] for the sec ondary color and
293 * replace the HW dst coeff with IS2C.
294 */
295 case kGeneral_CoverageStrategy:
296 SkASSERT(kZero_GrBlendCoeff != fSrcCoeff && kZero_GrBlendCoeff != fD stCoeff);
297 fSecondaryOutputType = inverse_dst_coeff_modulate(fDstCoeff);
298 fDstCoeff = kIS2C_GrBlendCoeff;
299 break;
300 };
301
302 fProps = fProps | (kModifiesDst_Property | kUsesDstColor_Property);
303 }
304
305 BlendFormula BlendFormula::Get(SkXfermode::Mode xfermode,
306 const GrProcOptInfo& colorPOI,
307 const GrProcOptInfo& coveragePOI) {
308 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
309 SkASSERT(!coveragePOI.isFourChannelOutput());
310
311 BlendFormula blendFormula = gBlendTable[colorPOI.isOpaque()][xfermode];
312 if (!coveragePOI.isSolidWhite()) {
313 blendFormula.addCoverage(colorPOI);
314 }
315 return blendFormula;
316 }
317
318 ///////////////////////////////////////////////////////////////////////////////
319
35 class PorterDuffXferProcessor : public GrXferProcessor { 320 class PorterDuffXferProcessor : public GrXferProcessor {
36 public: 321 public:
37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 322 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrDeviceCoor dTexture* dstCopy,
38 GrColor constant, const GrDeviceCoordTexture* dstCopy,
39 bool willReadDstColor) { 323 bool willReadDstColor) {
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant , dstCopy, 324 return SkNEW_ARGS(PorterDuffXferProcessor, (xfermode, dstCopy, willReadD stColor));
41 willReadDstColor));
42 } 325 }
43 326
44 ~PorterDuffXferProcessor() override; 327 ~PorterDuffXferProcessor() override;
45 328
46 const char* name() const override { return "Porter Duff"; } 329 const char* name() const override { return "Porter Duff"; }
47 330
48 GrGLXferProcessor* createGLInstance() const override; 331 GrGLXferProcessor* createGLInstance() const override;
49 332
50 bool hasSecondaryOutput() const override; 333 bool hasSecondaryOutput() const override {
334 return fBlendFormula.hasSecondaryOutput();
335 }
51 336
52 /////////////////////////////////////////////////////////////////////////// 337 SkXfermode::Mode getXfermode() const { return fXfermode; }
53 /// @name Stage Output Types 338 BlendFormula getBlendFormula() const { return fBlendFormula; }
54 ////
55
56 enum PrimaryOutputType {
57 kNone_PrimaryOutputType,
58 kColor_PrimaryOutputType,
59 kCoverage_PrimaryOutputType,
60 // Modulate color and coverage, write result as the color output.
61 kModulate_PrimaryOutputType,
62 // Custom Porter-Duff output, used for when we explictly are reading the dst and blending
63 // in the shader. Secondary Output must be none if you use this. The cus tom blend uses the
64 // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D
65 kCustom_PrimaryOutputType
66 };
67
68 enum SecondaryOutputType {
69 // There is no secondary output
70 kNone_SecondaryOutputType,
71 // Writes coverage as the secondary output. Only set if dual source blen ding is supported
72 // and primary output is kModulate.
73 kCoverage_SecondaryOutputType,
74 // Writes coverage * (1 - colorA) as the secondary output. Only set if d ual source blending
75 // is supported and primary output is kModulate.
76 kCoverageISA_SecondaryOutputType,
77 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set i f dual source
78 // blending is supported and primary output is kModulate.
79 kCoverageISC_SecondaryOutputType,
80
81 kSecondaryOutputTypeCnt,
82 };
83
84 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
85 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputTyp e; }
86
87 GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
88 GrBlendCoeff getDstBlend() const { return fDstBlend; }
89 339
90 private: 340 private:
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColo r constant, 341 PorterDuffXferProcessor(SkXfermode::Mode, const GrDeviceCoordTexture* dstCop y,
92 const GrDeviceCoordTexture* dstCopy, bool willReadDs tColor); 342 bool willReadDstColor);
93 343
94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 344 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
95 const GrProcOptInfo& coveragePO I, 345 const GrProcOptInfo& coveragePO I,
96 bool doesStencilWrite, 346 bool doesStencilWrite,
97 GrColor* overrideColor, 347 GrColor* overrideColor,
98 const GrCaps& caps) override; 348 const GrCaps& caps) override;
99 349
100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override; 350 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override;
101 351
102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 352 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
103 if (!this->willReadDstColor()) { 353 if (!this->willReadDstColor()) {
104 blendInfo->fSrcBlend = fSrcBlend; 354 blendInfo->fEquation = fBlendFormula.fBlendEquation;
105 blendInfo->fDstBlend = fDstBlend; 355 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
106 } else { 356 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff; 357 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
108 blendInfo->fDstBlend = kZero_GrBlendCoeff;
109 } 358 }
110 blendInfo->fBlendConstant = fBlendConstant;
111 } 359 }
112 360
113 bool onIsEqual(const GrXferProcessor& xpBase) const override { 361 bool onIsEqual(const GrXferProcessor& xpBase) const override {
114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> (); 362 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> ();
115 if (fSrcBlend != xp.fSrcBlend || 363 return fXfermode == xp.fXfermode &&
116 fDstBlend != xp.fDstBlend || 364 fBlendFormula == xp.fBlendFormula;
117 fBlendConstant != xp.fBlendConstant ||
118 fPrimaryOutputType != xp.fPrimaryOutputType ||
119 fSecondaryOutputType != xp.fSecondaryOutputType) {
120 return false;
121 }
122 return true;
123 } 365 }
124 366
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colo rPOI, 367 SkXfermode::Mode fXfermode;
126 const GrProcOptInfo& cove ragePOI, 368 BlendFormula fBlendFormula;
127 bool doesStencilWrite);
128
129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrCaps& caps ,
130 bool hasSolidCoverage);
131
132 GrBlendCoeff fSrcBlend;
133 GrBlendCoeff fDstBlend;
134 GrColor fBlendConstant;
135 PrimaryOutputType fPrimaryOutputType;
136 SecondaryOutputType fSecondaryOutputType;
137 369
138 typedef GrXferProcessor INHERITED; 370 typedef GrXferProcessor INHERITED;
139 }; 371 };
140 372
141 /////////////////////////////////////////////////////////////////////////////// 373 ///////////////////////////////////////////////////////////////////////////////
142 374
143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff , 375 void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilde r* fsBuilder,
376 BlendFormula::OutputType outputType, const char* output ,
377 const char* inColor, const char* inCoverage) {
378 switch (outputType) {
379 case BlendFormula::kNone_OutputType:
380 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
381 break;
382 case BlendFormula::kCoverage_OutputType:
383 fsBuilder->codeAppendf("%s = %s;",
384 output, xp.readsCoverage() ? inCoverage : "ve c4(1.0)");
385 break;
386 case BlendFormula::kModulate_OutputType:
387 if (xp.readsCoverage()) {
388 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover age);
389 } else {
390 fsBuilder->codeAppendf("%s = %s;", output, inColor);
391 }
392 break;
393 case BlendFormula::kISAModulate_OutputType:
394 if (xp.readsCoverage()) {
395 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColo r, inCoverage);
396 } else {
397 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor );
398 }
399 break;
400 case BlendFormula::kISCModulate_OutputType:
401 if (xp.readsCoverage()) {
402 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, in Color, inCoverage);
403 } else {
404 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
405 }
406 break;
407 default:
408 SkFAIL("Unsupported output type.");
409 break;
410 }
411 }
412
413 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
144 const char* colorName, const char* srcColorName, 414 const char* colorName, const char* srcColorName,
145 const char* dstColorName, bool hasPrevious) { 415 const char* dstColorName, bool hasPrevious) {
146 if (kZero_GrBlendCoeff == coeff) { 416 if (SkXfermode::kZero_Coeff == coeff) {
147 return hasPrevious; 417 return hasPrevious;
148 } else { 418 } else {
149 if (hasPrevious) { 419 if (hasPrevious) {
150 fsBuilder->codeAppend(" + "); 420 fsBuilder->codeAppend(" + ");
151 } 421 }
152 fsBuilder->codeAppendf("%s", colorName); 422 fsBuilder->codeAppendf("%s", colorName);
153 switch (coeff) { 423 switch (coeff) {
154 case kOne_GrBlendCoeff: 424 case SkXfermode::kOne_Coeff:
155 break; 425 break;
156 case kSC_GrBlendCoeff: 426 case SkXfermode::kSC_Coeff:
157 fsBuilder->codeAppendf(" * %s", srcColorName); 427 fsBuilder->codeAppendf(" * %s", srcColorName);
158 break; 428 break;
159 case kISC_GrBlendCoeff: 429 case SkXfermode::kISC_Coeff:
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 430 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
161 break; 431 break;
162 case kDC_GrBlendCoeff: 432 case SkXfermode::kDC_Coeff:
163 fsBuilder->codeAppendf(" * %s", dstColorName); 433 fsBuilder->codeAppendf(" * %s", dstColorName);
164 break; 434 break;
165 case kIDC_GrBlendCoeff: 435 case SkXfermode::kIDC_Coeff:
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 436 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
167 break; 437 break;
168 case kSA_GrBlendCoeff: 438 case SkXfermode::kSA_Coeff:
169 fsBuilder->codeAppendf(" * %s.a", srcColorName); 439 fsBuilder->codeAppendf(" * %s.a", srcColorName);
170 break; 440 break;
171 case kISA_GrBlendCoeff: 441 case SkXfermode::kISA_Coeff:
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 442 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
173 break; 443 break;
174 case kDA_GrBlendCoeff: 444 case SkXfermode::kDA_Coeff:
175 fsBuilder->codeAppendf(" * %s.a", dstColorName); 445 fsBuilder->codeAppendf(" * %s.a", dstColorName);
176 break; 446 break;
177 case kIDA_GrBlendCoeff: 447 case SkXfermode::kIDA_Coeff:
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); 448 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
179 break; 449 break;
180 default: 450 default:
181 SkFAIL("Unsupported Blend Coeff"); 451 SkFAIL("Unsupported Blend Coeff");
182 } 452 }
183 return true; 453 return true;
184 } 454 }
185 } 455 }
186 456
187 class GLPorterDuffXferProcessor : public GrGLXferProcessor { 457 class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188 public: 458 public:
189 GLPorterDuffXferProcessor(const GrProcessor&) {} 459 GLPorterDuffXferProcessor(const GrProcessor&) {}
190 460
191 virtual ~GLPorterDuffXferProcessor() {} 461 virtual ~GLPorterDuffXferProcessor() {}
192 462
193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, 463 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
194 GrProcessorKeyBuilder* b) { 464 GrProcessorKeyBuilder* b) {
195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>(); 465 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>();
196 b->add32(xp.primaryOutputType());
197 b->add32(xp.secondaryOutputType());
198 if (xp.willReadDstColor()) { 466 if (xp.willReadDstColor()) {
199 b->add32(xp.getSrcBlend()); 467 b->add32(xp.getXfermode()); // Parent class includes willReadDstCol or() in key.
200 b->add32(xp.getDstBlend()); 468 } else {
469 b->add32(xp.readsCoverage() |
470 (xp.getBlendFormula().fPrimaryOutputType << 1) |
471 (xp.getBlendFormula().fSecondaryOutputType << 4));
472 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
201 } 473 }
202 }; 474 };
203 475
204 private: 476 private:
205 void onEmitCode(const EmitArgs& args) override { 477 void onEmitCode(const EmitArgs& args) override {
206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>(); 478 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>();
207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 479 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutp utType()) { 480 if (!xp.willReadDstColor()) {
209 SkASSERT(!xp.willReadDstColor()); 481 BlendFormula blendFormula = xp.getBlendFormula();
210 switch(xp.secondaryOutputType()) { 482 if (blendFormula.hasSecondaryOutput()) {
211 case PorterDuffXferProcessor::kNone_SecondaryOutputType: 483 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutput Type,
212 break; 484 args.fOutputSecondary, args.fInputColor, arg s.fInputCoverage);
213 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
214 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary,
215 args.fInputCoverage);
216 break;
217 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
218 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
219 args.fOutputSecondary, args.fInputCol or,
220 args.fInputCoverage);
221 break;
222 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
223 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
224 args.fOutputSecondary, args.fInputCol or,
225 args.fInputCoverage);
226 break;
227 default:
228 SkFAIL("Unexpected Secondary Output");
229 } 485 }
230 486 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
231 switch (xp.primaryOutputType()) { 487 args.fOutputPrimary, args.fInputColor, args.fInp utCoverage);
232 case PorterDuffXferProcessor::kNone_PrimaryOutputType:
233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary) ;
234 break;
235 case PorterDuffXferProcessor::kColor_PrimaryOutputType:
236 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args .fInputColor);
237 break;
238 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
239 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args .fInputCoverage);
240 break;
241 case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
242 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
243 args.fInputCoverage);
244 break;
245 default:
246 SkFAIL("Unexpected Primary Output");
247 }
248 } else { 488 } else {
249 SkASSERT(xp.willReadDstColor()); 489 SkASSERT(xp.willReadDstColor());
250 490
491 SkXfermode::Coeff srcCoeff, dstCoeff;
492 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
493
251 const char* dstColor = fsBuilder->dstColor(); 494 const char* dstColor = fsBuilder->dstColor();
252 495
253 fsBuilder->codeAppend("vec4 colorBlend ="); 496 fsBuilder->codeAppend("vec4 colorBlend =");
254 // append src blend 497 // append src blend
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(), 498 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
256 args.fInputColor, args.fInpu tColor, 499 args.fInputColor, args.fInpu tColor,
257 dstColor, false); 500 dstColor, false);
258 // append dst blend 501 // append dst blend
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(), 502 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
260 dstColor, args.fInputColor, 503 dstColor, args.fInputColor,
261 dstColor, didAppend)); 504 dstColor, didAppend));
262 fsBuilder->codeAppend(";"); 505 fsBuilder->codeAppend(";");
263 506
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s ;", 507 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s ;",
265 args.fOutputPrimary, args.fInputCoverage, arg s.fInputCoverage, 508 args.fOutputPrimary, args.fInputCoverage, arg s.fInputCoverage,
266 dstColor); 509 dstColor);
267 } 510 }
268 } 511 }
269 512
270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {}; 513 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {};
271 514
272 typedef GrGLXferProcessor INHERITED; 515 typedef GrGLXferProcessor INHERITED;
273 }; 516 };
274 517
275 /////////////////////////////////////////////////////////////////////////////// 518 ///////////////////////////////////////////////////////////////////////////////
276 519
277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, 520 PorterDuffXferProcessor::PorterDuffXferProcessor(SkXfermode::Mode xfermode,
278 GrBlendCoeff dstBlend,
279 GrColor constant,
280 const GrDeviceCoordTexture* dst Copy, 521 const GrDeviceCoordTexture* dst Copy,
281 bool willReadDstColor) 522 bool willReadDstColor)
282 : INHERITED(dstCopy, willReadDstColor) 523 : INHERITED(dstCopy, willReadDstColor)
283 , fSrcBlend(srcBlend) 524 , fXfermode(xfermode) {
284 , fDstBlend(dstBlend)
285 , fBlendConstant(constant)
286 , fPrimaryOutputType(kModulate_PrimaryOutputType)
287 , fSecondaryOutputType(kNone_SecondaryOutputType) {
288 this->initClassID<PorterDuffXferProcessor>(); 525 this->initClassID<PorterDuffXferProcessor>();
289 } 526 }
290 527
291 PorterDuffXferProcessor::~PorterDuffXferProcessor() { 528 PorterDuffXferProcessor::~PorterDuffXferProcessor() {
292 } 529 }
293 530
294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps, 531 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
295 GrProcessorKeyBuilder* b) cons t { 532 GrProcessorKeyBuilder* b) cons t {
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b); 533 GLPorterDuffXferProcessor::GenKey(*this, caps, b);
297 } 534 }
298 535
299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { 536 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this)); 537 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
301 } 538 }
302 539
303 GrXferProcessor::OptFlags 540 GrXferProcessor::OptFlags
304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, 541 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
305 const GrProcOptInfo& coveragePOI, 542 const GrProcOptInfo& coveragePOI,
306 bool doesStencilWrite, 543 bool doesStencilWrite,
307 GrColor* overrideColor, 544 GrColor* overrideColor,
308 const GrCaps& caps) { 545 const GrCaps& caps) {
309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI ,
310 coverage POI,
311 doesSten cilWrite);
312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
313 return optFlags;
314 }
315
316 void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags ,
317 const GrCaps& caps,
318 bool hasSolidCoverage) {
319 if (this->willReadDstColor()) {
320 fPrimaryOutputType = kCustom_PrimaryOutputType;
321 return;
322 }
323
324 if (optFlags & kIgnoreColor_OptFlag) {
325 if (optFlags & kIgnoreCoverage_OptFlag) {
326 fPrimaryOutputType = kNone_PrimaryOutputType;
327 return;
328 } else {
329 fPrimaryOutputType = kCoverage_PrimaryOutputType;
330 return;
331 }
332 } else if (optFlags & kIgnoreCoverage_OptFlag) {
333 fPrimaryOutputType = kColor_PrimaryOutputType;
334 return;
335 }
336
337 // If we do have coverage determine whether it matters. Dual source blendin g is expensive so
338 // we don't do it if we are doing coverage drawing. If we aren't then We al ways do dual source
339 // blending if we have any effective coverage stages OR the geometry process or doesn't emits
340 // solid coverage.
341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
342 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
343 if (kZero_GrBlendCoeff == fDstBlend) {
344 // write the coverage value to second color
345 fSecondaryOutputType = kCoverage_SecondaryOutputType;
346 fDstBlend = kIS2C_GrBlendCoeff;
347 } else if (kSA_GrBlendCoeff == fDstBlend) {
348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
350 fDstBlend = kIS2C_GrBlendCoeff;
351 } else if (kSC_GrBlendCoeff == fDstBlend) {
352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
354 fDstBlend = kIS2C_GrBlendCoeff;
355 }
356 }
357 }
358 }
359
360 GrXferProcessor::OptFlags
361 PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
362 const GrProcOptInfo& coverageP OI,
363 bool doesStencilWrite) {
364 if (this->willReadDstColor()) { 546 if (this->willReadDstColor()) {
365 return GrXferProcessor::kNone_Opt; 547 return GrXferProcessor::kNone_Opt;
366 } 548 }
367 549
368 bool srcAIsOne = colorPOI.isOpaque(); 550 fBlendFormula = BlendFormula::Get(fXfermode, colorPOI, coveragePOI);
369 bool hasCoverage = !coveragePOI.isSolidWhite();
370 551
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || 552 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); 553 if (!fBlendFormula.modifiesDst()) {
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || 554 if (!doesStencilWrite) {
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); 555 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
375 556 }
376 // When coeffs are (0,1) there is no reason to draw at all, unless 557 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
377 // stenciling is enabled. Having color writes disabled is effectively 558 GrXferProcessor::kIgnoreCoverage_OptFlag |
378 // (0,1). 559 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { 560 } else {
380 if (doesStencilWrite) { 561 if (!fBlendFormula.usesInputColor()) {
381 return GrXferProcessor::kIgnoreColor_OptFlag | 562 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
382 GrXferProcessor::kSetCoverageDrawing_OptFlag; 563 }
383 } else { 564 if (coveragePOI.isSolidWhite()) {
384 fDstBlend = kOne_GrBlendCoeff; 565 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
385 return GrXferProcessor::kSkipDraw_OptFlag; 566 }
567 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForC overage()) {
568 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
386 } 569 }
387 } 570 }
388 571
389 // if we don't have coverage we can check whether the dst 572 return optFlags;
390 // has to read at all. If not, we'll disable blending.
391 if (!hasCoverage) {
392 if (dstCoeffIsZero) {
393 if (kOne_GrBlendCoeff == fSrcBlend) {
394 // if there is no coverage and coeffs are (1,0) then we
395 // won't need to read the dst at all, it gets replaced by src
396 fDstBlend = kZero_GrBlendCoeff;
397 return GrXferProcessor::kNone_Opt |
398 GrXferProcessor::kIgnoreCoverage_OptFlag;
399 } else if (kZero_GrBlendCoeff == fSrcBlend) {
400 // if the op is "clear" then we don't need to emit a color
401 // or blend, just write transparent black into the dst.
402 fSrcBlend = kOne_GrBlendCoeff;
403 fDstBlend = kZero_GrBlendCoeff;
404 return GrXferProcessor::kIgnoreColor_OptFlag |
405 GrXferProcessor::kIgnoreCoverage_OptFlag;
406 }
407 }
408 return GrXferProcessor::kIgnoreCoverage_OptFlag;
409 }
410
411 // check whether coverage can be safely rolled into alpha
412 // of if we can skip color computation and just emit coverage
413 if (can_tweak_alpha_for_coverage(fDstBlend)) {
414 if (colorPOI.allStagesMultiplyInput()) {
415 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
416 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
417 } else {
418 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
419
420 }
421 }
422 if (dstCoeffIsZero) {
423 if (kZero_GrBlendCoeff == fSrcBlend) {
424 // the source color is not included in the blend
425 // the dst coeff is effectively zero so blend works out to:
426 // (c)(0)D + (1-c)D = (1-c)D.
427 fDstBlend = kISA_GrBlendCoeff;
428 return GrXferProcessor::kIgnoreColor_OptFlag |
429 GrXferProcessor::kSetCoverageDrawing_OptFlag;
430 } else if (srcAIsOne) {
431 // the dst coeff is effectively zero so blend works out to:
432 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
433 // If Sa is 1 then we can replace Sa with c
434 // and set dst coeff to 1-Sa.
435 fDstBlend = kISA_GrBlendCoeff;
436 if (colorPOI.allStagesMultiplyInput()) {
437 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
439 } else {
440 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
441
442 }
443 }
444 } else if (dstCoeffIsOne) {
445 // the dst coeff is effectively one so blend works out to:
446 // cS + (c)(1)D + (1-c)D = cS + D.
447 fDstBlend = kOne_GrBlendCoeff;
448 if (colorPOI.allStagesMultiplyInput()) {
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
451 } else {
452 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
453
454 }
455 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
456 }
457
458 return GrXferProcessor::kNone_Opt;
459 }
460
461 bool PorterDuffXferProcessor::hasSecondaryOutput() const {
462 return kNone_SecondaryOutputType != fSecondaryOutputType;
463 } 573 }
464 574
465 /////////////////////////////////////////////////////////////////////////////// 575 ///////////////////////////////////////////////////////////////////////////////
466 576
467 class PDLCDXferProcessor : public GrXferProcessor { 577 class PDLCDXferProcessor : public GrXferProcessor {
468 public: 578 public:
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 579 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInf o& colorPOI);
470 const GrProcOptInfo& colorPOI);
471 580
472 ~PDLCDXferProcessor() override; 581 ~PDLCDXferProcessor() override;
473 582
474 const char* name() const override { return "Porter Duff LCD"; } 583 const char* name() const override { return "Porter Duff LCD"; }
475 584
476 GrGLXferProcessor* createGLInstance() const override; 585 GrGLXferProcessor* createGLInstance() const override;
477 586
478 bool hasSecondaryOutput() const override { return false; } 587 bool hasSecondaryOutput() const override { return false; }
479 588
480 private: 589 private:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 }; 643 };
535 644
536 /////////////////////////////////////////////////////////////////////////////// 645 ///////////////////////////////////////////////////////////////////////////////
537 646
538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) 647 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539 : fBlendConstant(blendConstant) 648 : fBlendConstant(blendConstant)
540 , fAlpha(alpha) { 649 , fAlpha(alpha) {
541 this->initClassID<PDLCDXferProcessor>(); 650 this->initClassID<PDLCDXferProcessor>();
542 } 651 }
543 652
544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 653 GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
545 const GrProcOptInfo& colorPOI) { 654 const GrProcOptInfo& colorPOI) {
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) { 655 if (SkXfermode::kSrcOver_Mode != xfermode) {
547 return NULL; 656 return NULL;
548 } 657 }
549 658
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { 659 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
551 return NULL; 660 return NULL;
552 } 661 }
553 662
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); 663 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
555 uint8_t alpha = GrColorUnpackA(blendConstant); 664 uint8_t alpha = GrColorUnpackA(blendConstant);
556 blendConstant |= (0xff << GrColor_SHIFT_A); 665 blendConstant |= (0xff << GrColor_SHIFT_A);
(...skipping 21 matching lines...) Expand all
578 const GrCaps& caps) { 687 const GrCaps& caps) {
579 // We want to force our primary output to be alpha * Coverage, where alp ha is the alpha 688 // We want to force our primary output to be alpha * Coverage, where alp ha is the alpha
580 // value of the blend the constant. We should already have valid blend c oeff's if we are at 689 // value of the blend the constant. We should already have valid blend c oeff's if we are at
581 // a point where we have RGB coverage. We don't need any color stages si nce the known color 690 // a point where we have RGB coverage. We don't need any color stages si nce the known color
582 // output is already baked into the blendConstant. 691 // output is already baked into the blendConstant.
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); 692 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
584 return GrXferProcessor::kOverrideColor_OptFlag; 693 return GrXferProcessor::kOverrideColor_OptFlag;
585 } 694 }
586 695
587 /////////////////////////////////////////////////////////////////////////////// 696 ///////////////////////////////////////////////////////////////////////////////
588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) 697
589 : fSrcCoeff(src), fDstCoeff(dst) { 698 GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
699 : fXfermode(xfermode) {
590 this->initClassID<GrPorterDuffXPFactory>(); 700 this->initClassID<GrPorterDuffXPFactory>();
591 } 701 }
592 702
593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { 703 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
594 switch (mode) { 704 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
595 case SkXfermode::kClear_Mode: { 705 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G rBlendCoeff); 706 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
597 return SkRef(&gClearPDXPF); 707 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
598 break; 708 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
599 } 709 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
600 case SkXfermode::kSrc_Mode: { 710 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBl endCoeff); 711 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
602 return SkRef(&gSrcPDXPF); 712 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
603 break; 713 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
604 } 714 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
605 case SkXfermode::kDst_Mode: { 715 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBl endCoeff); 716 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
607 return SkRef(&gDstPDXPF); 717 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
608 break; 718 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
609 } 719
610 case SkXfermode::kSrcOver_Mode: { 720 static GrPorterDuffXPFactory* gFactories[] = {
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_G rBlendCoeff); 721 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &g SrcInPDXPF,
612 return SkRef(&gSrcOverPDXPF); 722 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDX PF, &gXorPDXPF,
613 break; 723 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
614 } 724 };
615 case SkXfermode::kDstOver_Mode: { 725 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_G rBlendCoeff); 726
617 return SkRef(&gDstOverPDXPF); 727 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
618 break; 728 return NULL;
619 }
620 case SkXfermode::kSrcIn_Mode: {
621 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrB lendCoeff);
622 return SkRef(&gSrcInPDXPF);
623 break;
624 }
625 case SkXfermode::kDstIn_Mode: {
626 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrB lendCoeff);
627 return SkRef(&gDstInPDXPF);
628 break;
629 }
630 case SkXfermode::kSrcOut_Mode: {
631 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_G rBlendCoeff);
632 return SkRef(&gSrcOutPDXPF);
633 break;
634 }
635 case SkXfermode::kDstOut_Mode: {
636 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_G rBlendCoeff);
637 return SkRef(&gDstOutPDXPF);
638 break;
639 }
640 case SkXfermode::kSrcATop_Mode: {
641 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_Gr BlendCoeff);
642 return SkRef(&gSrcATopPDXPF);
643 break;
644 }
645 case SkXfermode::kDstATop_Mode: {
646 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_Gr BlendCoeff);
647 return SkRef(&gDstATopPDXPF);
648 break;
649 }
650 case SkXfermode::kXor_Mode: {
651 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBle ndCoeff);
652 return SkRef(&gXorPDXPF);
653 break;
654 }
655 case SkXfermode::kPlus_Mode: {
656 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBl endCoeff);
657 return SkRef(&gPlusPDXPF);
658 break;
659 }
660 case SkXfermode::kModulate_Mode: {
661 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_ GrBlendCoeff);
662 return SkRef(&gModulatePDXPF);
663 break;
664 }
665 case SkXfermode::kScreen_Mode: {
666 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr BlendCoeff);
667 return SkRef(&gScreenPDXPF);
668 break;
669 }
670 default:
671 return NULL;
672 } 729 }
730 return SkRef(gFactories[xfermode]);
673 } 731 }
674 732
675 GrXferProcessor* 733 GrXferProcessor*
676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, 734 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
677 const GrProcOptInfo& colorPOI, 735 const GrProcOptInfo& colorPOI,
678 const GrProcOptInfo& covPOI, 736 const GrProcOptInfo& covPOI,
679 const GrDeviceCoordTexture* dstCopy ) const { 737 const GrDeviceCoordTexture* dstCopy ) const {
680 if (covPOI.isFourChannelOutput()) { 738 if (covPOI.isFourChannelOutput()) {
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI); 739 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
682 } else { 740 } else {
683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy, 741 return PorterDuffXferProcessor::Create(fXfermode, dstCopy,
684 this->willReadDstColor(caps, colo rPOI, covPOI)); 742 this->willReadDstColor(caps, colo rPOI, covPOI));
685 } 743 }
686 } 744 }
687 745
688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, 746 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
689 uint32_t knownColorFlags) const { 747 uint32_t knownColorFlags) const {
690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && 748 if (SkXfermode::kSrcOver_Mode == fXfermode &&
691 kRGBA_GrColorComponentFlags == knownColorFlags) { 749 kRGBA_GrColorComponentFlags == knownColorFlags) {
692 return true; 750 return true;
693 } 751 }
694 return false; 752 return false;
695 } 753 }
696 754
697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 755 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
698 const GrProcOptInfo& coveragePOI, 756 const GrProcOptInfo& coveragePOI,
699 GrXPFactory::InvariantOutput* out put) const { 757 GrXPFactory::InvariantOutput* out put) const {
700 if (!coveragePOI.isSolidWhite()) { 758 const BlendFormula& blendFormula = BlendFormula::Get(fXfermode, colorPOI, co veragePOI);
759
760 if (blendFormula.usesDstColor()) {
701 output->fWillBlendWithDst = true; 761 output->fWillBlendWithDst = true;
702 output->fBlendedColorFlags = 0; 762 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
703 return; 763 return;
704 } 764 }
705 765
706 GrBlendCoeff srcCoeff = fSrcCoeff; 766 SkASSERT(coveragePOI.isSolidWhite());
707 GrBlendCoeff dstCoeff = fDstCoeff; 767 SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
708 768
709 // TODO: figure out to merge this simplify with other current optimization c ode paths and 769 output->fWillBlendWithDst = false;
710 // eventually remove from GrBlend
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags( ),
712 0, 0, 0);
713 770
714 if (GrBlendCoeffRefsDst(srcCoeff)) { 771 switch (blendFormula.fSrcCoeff) {
715 output->fWillBlendWithDst = true;
716 output->fBlendedColorFlags = 0;
717 return;
718 }
719
720 if (kZero_GrBlendCoeff != dstCoeff) {
721 bool srcAIsOne = colorPOI.isOpaque();
722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
723 output->fWillBlendWithDst = true;
724 }
725 output->fBlendedColorFlags = 0;
726 return;
727 }
728
729 switch (srcCoeff) {
730 case kZero_GrBlendCoeff: 772 case kZero_GrBlendCoeff:
731 output->fBlendedColor = 0; 773 output->fBlendedColor = 0;
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; 774 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
733 break; 775 return;
734 776
735 case kOne_GrBlendCoeff: 777 case kOne_GrBlendCoeff:
736 output->fBlendedColor = colorPOI.color(); 778 output->fBlendedColor = colorPOI.color();
737 output->fBlendedColorFlags = colorPOI.validFlags(); 779 output->fBlendedColorFlags = colorPOI.validFlags();
738 break; 780 return;
739 781
740 // The src coeff should never refer to the src and if it refers to d st then opaque 782 // TODO: update if we ever use const color.
741 // should have been false.
742 case kSC_GrBlendCoeff:
743 case kISC_GrBlendCoeff:
744 case kDC_GrBlendCoeff:
745 case kIDC_GrBlendCoeff:
746 case kSA_GrBlendCoeff:
747 case kISA_GrBlendCoeff:
748 case kDA_GrBlendCoeff:
749 case kIDA_GrBlendCoeff:
750 default: 783 default:
751 SkFAIL("srcCoeff should not refer to src or dst."); 784 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
752 break; 785 return;
753
754 // TODO: update this once GrPaint actually has a const color.
755 case kConstC_GrBlendCoeff:
756 case kIConstC_GrBlendCoeff:
757 case kConstA_GrBlendCoeff:
758 case kIConstA_GrBlendCoeff:
759 output->fBlendedColorFlags = 0;
760 break;
761 } 786 }
762
763 output->fWillBlendWithDst = false;
764 } 787 }
765 788
766 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, 789 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
767 const GrProcOptInfo& colorPOI, 790 const GrProcOptInfo& colorPOI,
768 const GrProcOptInfo& coveragePOI) c onst { 791 const GrProcOptInfo& coveragePOI) c onst {
769 // We can always blend correctly if we have dual source blending. 792 // Some formulas use dual source blending, so we fall back if it is required but not supported.
770 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 793 return !caps.shaderCaps()->dualSourceBlendingSupport() &&
771 return false; 794 BlendFormula::Get(fXfermode, colorPOI, coveragePOI).hasSecondaryOutpu t();
772 }
773
774 if (can_tweak_alpha_for_coverage(fDstCoeff)) {
775 return false;
776 }
777
778 bool srcAIsOne = colorPOI.isOpaque();
779
780 if (kZero_GrBlendCoeff == fDstCoeff) {
781 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
782 return false;
783 }
784 }
785
786 // Reduces to: coeffS * (Cov*S) + D
787 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
788 return false;
789 }
790
791 // We can always blend correctly if we have solid coverage.
792 if (coveragePOI.isSolidWhite()) {
793 return false;
794 }
795
796 return true;
797 } 795 }
798 796
799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); 797 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800 798
801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, 799 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
802 GrContext*, 800 GrContext*,
803 const GrCaps&, 801 const GrCaps&,
804 GrTexture*[]) { 802 GrTexture*[]) {
805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode)); 803 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode));
806 return GrPorterDuffXPFactory::Create(mode); 804 return GrPorterDuffXPFactory::Create(mode);
807 } 805 }
808 806
807 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
808 int* outPrimary,
809 int* outSecondary) {
810 if (!!strcmp(xp->name(), "Porter Duff")) {
811 *outPrimary = *outSecondary = -1;
812 return;
813 }
814 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)- >getBlendFormula();
815 *outPrimary = blendFormula.fPrimaryOutputType;
816 *outSecondary = blendFormula.fSecondaryOutputType;
817 }
818
OLDNEW
« src/gpu/GrBlend.h ('K') | « src/gpu/GrBlend.cpp ('k') | tests/GrPorterDuffTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698