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

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: Use resource provider instead of gpu for tests Created 5 years, 6 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/GrCaps.cpp ('k') | tests/GrPorterDuffTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "GrCaps.h" 11 #include "GrCaps.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.
29 */ 28 */
30 return kOne_GrBlendCoeff == dstCoeff || 29 enum OutputType {
31 kISA_GrBlendCoeff == dstCoeff || 30 kNone_OutputType, //<! 0
32 kISC_GrBlendCoeff == dstCoeff; 31 kCoverage_OutputType, //<! inputCoverage
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 Properties {
40 kModifiesDst_Property = 1,
41 kUsesDstColor_Property = 1 << 1,
42 kUsesInputColor_Property = 1 << 2,
43 kCanTweakAlphaForCoverage_Property = 1 << 3,
44
45 kLast_Property = kCanTweakAlphaForCoverage_Property
46 };
47
48 BlendFormula& operator =(const BlendFormula& other) {
49 fData = other.fData;
50 return *this;
51 }
52
53 bool operator ==(const BlendFormula& other) const {
54 return fData == other.fData;
55 }
56
57 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutpu tType; }
58 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
59 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property) ; }
60 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Prope rty); }
61 bool canTweakAlphaForCoverage() const {
62 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
63 }
64
65 /**
66 * Deduce the properties of a compile-time constant BlendFormula.
67 */
68 template<OutputType PrimaryOut, OutputType SecondaryOut,
69 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
70 struct get_properties : SkTIntegralConstant<Properties, static_cast<Properti es>(
71
72 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
73 kModifiesDst_Property : 0) |
74
75 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
76 kUsesDstColor_Property : 0) |
77
78 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(Sr cCoeff,DstCoeff)) ||
79 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCo eff)) ?
80 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff do esn't ref src2.
81
82 (kModulate_OutputType == PrimaryOut &&
83 kNone_OutputType == SecondaryOut &&
84 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff ) ?
85 kCanTweakAlphaForCoverage_Property : 0))> {
86
87 // The provided formula should already be optimized.
88 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
89 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
90 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
91 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
92 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
93 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == Prima ryOut);
94 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == S econdaryOut);
95 };
96
97 union {
98 struct {
99 // We allot the enums one more bit than they require because MSVC se ems to sign-extend
100 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
101 OutputType fPrimaryOutputType : 4;
102 OutputType fSecondaryOutputType : 4;
103 GrBlendEquation fBlendEquation : 6;
104 GrBlendCoeff fSrcCoeff : 6;
105 GrBlendCoeff fDstCoeff : 6;
106 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
107 };
108 uint32_t fData;
109 };
110
111 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
112 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
113 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
114 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
115 };
116
117 GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
118
119 GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
120
121 /**
122 * Initialize a compile-time constant BlendFormula and automatically deduce fPro ps.
123 */
124 #define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF , DST_COEFF) \
125 {{{PRIMARY_OUT, \
126 SECONDARY_OUT, \
127 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
128 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
129 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value }}}
130
131 /**
132 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
133 * Porter Duff formula.
134 */
135 #define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
136 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
137 BlendFormula::kNone_OutputType, \
138 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
139
140 /**
141 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
142 * the primary output type to none.
143 */
144 #define DST_CLEAR_FORMULA \
145 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
146 BlendFormula::kNone_OutputType, \
147 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCo eff)
148
149 /**
150 * When the coeffs are (Zero, One), we don't write to the dst at all. This formu la has its own macro
151 * so we can set the primary output type to none.
152 */
153 #define NO_DST_WRITE_FORMULA \
154 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
155 BlendFormula::kNone_OutputType, \
156 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoe ff)
157
158 /**
159 * When there is coverage, the equation with f=coverage is:
160 *
161 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
162 *
163 * This can be rewritten as:
164 *
165 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
166 *
167 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary c olor and replace the
168 * HW dst coeff with IS2C.
169 *
170 * Xfer modes: dst-atop (Sa!=1)
171 */
172 #define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
173 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
174 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
175 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
176
177 /**
178 * When there is coverage and the src coeff is Zero, the equation with f=coverag e becomes:
179 *
180 * D' = f * D * dstCoeff + (1-f) * D
181 *
182 * This can be rewritten as:
183 *
184 * D' = D - D * [f * (1 - dstCoeff)]
185 *
186 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary col or and use a reverse
187 * subtract HW blend equation with coeffs of (DC, One).
188 *
189 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
190 */
191 #define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
192 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
193 BlendFormula::kNone_OutputType, \
194 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_ GrBlendCoeff)
195
196 /**
197 * When there is coverage and the dst coeff is Zero, the equation with f=coverag e becomes:
198 *
199 * D' = f * S * srcCoeff + (1-f) * D
200 *
201 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
202 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using IS A.)
203 *
204 * Xfer modes (Sa!=1): src, src-in, src-out
205 */
206 #define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
207 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
208 BlendFormula::kCoverage_OutputType, \
209 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
210
211 /**
212 * This table outlines the blend formulas we will use with each xfermode, with a nd without coverage,
213 * with and without an opaque input color. Optimization properties are deduced a t compile time so we
214 * can make runtime decisions quickly. RGB coverage is not supported.
215 */
216 static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
217
218 /*>> No coverage, input color unknown <<*/ {{
219
220 /* clear */ DST_CLEAR_FORMULA,
221 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
222 /* dst */ NO_DST_WRITE_FORMULA,
223 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
224 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
225 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
226 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
227 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
228 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
229 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
230 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
231 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
232 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
233 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
234 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
235
236 }, /*>> Has coverage, input color unknown <<*/ {
237
238 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
239 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
240 /* dst */ NO_DST_WRITE_FORMULA,
241 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
242 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
243 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
244 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_ OutputType),
245 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
246 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
247 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
248 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kID A_GrBlendCoeff),
249 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
250 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
251 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_ OutputType),
252 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
253
254 }}, /*>> No coverage, input color opaque <<*/ {{
255
256 /* clear */ DST_CLEAR_FORMULA,
257 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
258 /* dst */ NO_DST_WRITE_FORMULA,
259 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
260 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
261 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
262 /* dst-in */ NO_DST_WRITE_FORMULA,
263 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
264 /* dst-out */ DST_CLEAR_FORMULA,
265 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
266 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
267 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
268 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
269 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
270 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
271
272 }, /*>> Has coverage, input color opaque <<*/ {
273
274 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
275 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
276 /* dst */ NO_DST_WRITE_FORMULA,
277 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
278 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
279 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
280 /* dst-in */ NO_DST_WRITE_FORMULA,
281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
282 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
287 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_ OutputType),
288 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
289 }}};
290
291 static BlendFormula get_blend_formula(SkXfermode::Mode xfermode,
292 const GrProcOptInfo& colorPOI,
293 const GrProcOptInfo& coveragePOI) {
294 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
295 SkASSERT(!coveragePOI.isFourChannelOutput());
296
297 return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermod e];
33 } 298 }
34 299
300 ///////////////////////////////////////////////////////////////////////////////
301
35 class PorterDuffXferProcessor : public GrXferProcessor { 302 class PorterDuffXferProcessor : public GrXferProcessor {
36 public: 303 public:
37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 304 static GrXferProcessor* Create(BlendFormula blendFormula) {
38 GrColor constant, const DstTexture* dstTextur e, 305 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
39 bool willReadDstColor) { 306 }
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant , dstTexture,
41 willReadDstColor));
42 }
43
44 ~PorterDuffXferProcessor() override;
45 307
46 const char* name() const override { return "Porter Duff"; } 308 const char* name() const override { return "Porter Duff"; }
309 bool hasSecondaryOutput() const override { return fBlendFormula.hasSecondary Output(); }
47 310
48 GrGLXferProcessor* createGLInstance() const override; 311 GrGLXferProcessor* createGLInstance() const override;
49 312
50 bool hasSecondaryOutput() const override; 313 BlendFormula getBlendFormula() const { return fBlendFormula; }
51
52 ///////////////////////////////////////////////////////////////////////////
53 /// @name Stage Output Types
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 314
90 private: 315 private:
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColo r constant, 316 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendForm ula) {
92 const DstTexture*, bool willReadDstColor); 317 this->initClassID<PorterDuffXferProcessor>();
318 }
93 319
94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 320 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
95 const GrProcOptInfo& coveragePO I, 321 const GrProcOptInfo& coveragePO I,
96 bool doesStencilWrite, 322 bool doesStencilWrite,
97 GrColor* overrideColor, 323 GrColor* overrideColor,
98 const GrCaps& caps) override; 324 const GrCaps& caps) override;
99 325
100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override; 326 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override;
101 327
102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 328 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
103 if (!this->willReadDstColor()) { 329 blendInfo->fEquation = fBlendFormula.fBlendEquation;
104 blendInfo->fSrcBlend = fSrcBlend; 330 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
105 blendInfo->fDstBlend = fDstBlend; 331 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
106 } else { 332 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
108 blendInfo->fDstBlend = kZero_GrBlendCoeff;
109 }
110 blendInfo->fBlendConstant = fBlendConstant;
111 } 333 }
112 334
113 bool onIsEqual(const GrXferProcessor& xpBase) const override { 335 bool onIsEqual(const GrXferProcessor& xpBase) const override {
114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> (); 336 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> ();
115 if (fSrcBlend != xp.fSrcBlend || 337 return fBlendFormula == xp.fBlendFormula;
116 fDstBlend != xp.fDstBlend ||
117 fBlendConstant != xp.fBlendConstant ||
118 fPrimaryOutputType != xp.fPrimaryOutputType ||
119 fSecondaryOutputType != xp.fSecondaryOutputType) {
120 return false;
121 }
122 return true;
123 } 338 }
124 339
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colo rPOI, 340 const BlendFormula fBlendFormula;
126 const GrProcOptInfo& cove ragePOI,
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 341
138 typedef GrXferProcessor INHERITED; 342 typedef GrXferProcessor INHERITED;
139 }; 343 };
140 344
141 /////////////////////////////////////////////////////////////////////////////// 345 ///////////////////////////////////////////////////////////////////////////////
142 346
143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff , 347 static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen tBuilder* fsBuilder,
144 const char* colorName, const char* srcColorName, 348 BlendFormula::OutputType outputType, const char* output,
145 const char* dstColorName, bool hasPrevious) { 349 const char* inColor, const char* inCoverage) {
146 if (kZero_GrBlendCoeff == coeff) { 350 switch (outputType) {
147 return hasPrevious; 351 case BlendFormula::kNone_OutputType:
148 } else { 352 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
149 if (hasPrevious) { 353 break;
150 fsBuilder->codeAppend(" + "); 354 case BlendFormula::kCoverage_OutputType:
151 } 355 fsBuilder->codeAppendf("%s = %s;",
152 fsBuilder->codeAppendf("%s", colorName); 356 output, xp.readsCoverage() ? inCoverage : "ve c4(1.0)");
153 switch (coeff) { 357 break;
154 case kOne_GrBlendCoeff: 358 case BlendFormula::kModulate_OutputType:
155 break; 359 if (xp.readsCoverage()) {
156 case kSC_GrBlendCoeff: 360 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover age);
157 fsBuilder->codeAppendf(" * %s", srcColorName); 361 } else {
158 break; 362 fsBuilder->codeAppendf("%s = %s;", output, inColor);
159 case kISC_GrBlendCoeff: 363 }
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 364 break;
161 break; 365 case BlendFormula::kISAModulate_OutputType:
162 case kDC_GrBlendCoeff: 366 if (xp.readsCoverage()) {
163 fsBuilder->codeAppendf(" * %s", dstColorName); 367 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColo r, inCoverage);
164 break; 368 } else {
165 case kIDC_GrBlendCoeff: 369 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor );
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 370 }
167 break; 371 break;
168 case kSA_GrBlendCoeff: 372 case BlendFormula::kISCModulate_OutputType:
169 fsBuilder->codeAppendf(" * %s.a", srcColorName); 373 if (xp.readsCoverage()) {
170 break; 374 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, in Color, inCoverage);
171 case kISA_GrBlendCoeff: 375 } else {
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 376 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
173 break; 377 }
174 case kDA_GrBlendCoeff: 378 break;
175 fsBuilder->codeAppendf(" * %s.a", dstColorName); 379 default:
176 break; 380 SkFAIL("Unsupported output type.");
177 case kIDA_GrBlendCoeff: 381 break;
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
179 break;
180 default:
181 SkFAIL("Unsupported Blend Coeff");
182 }
183 return true;
184 } 382 }
185 } 383 }
186 384
187 class GLPorterDuffXferProcessor : public GrGLXferProcessor { 385 class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188 public: 386 public:
189 GLPorterDuffXferProcessor(const GrProcessor&) {} 387 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
190
191 virtual ~GLPorterDuffXferProcessor() {}
192
193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
194 GrProcessorKeyBuilder* b) {
195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>(); 388 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>();
196 b->add32(xp.primaryOutputType()); 389 b->add32(SkToInt(xp.readsCoverage()) |
197 b->add32(xp.secondaryOutputType()); 390 (xp.getBlendFormula().fPrimaryOutputType << 1) |
198 if (xp.willReadDstColor()) { 391 (xp.getBlendFormula().fSecondaryOutputType << 4));
199 b->add32(xp.getSrcBlend()); 392 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
200 b->add32(xp.getDstBlend());
201 }
202 }; 393 };
203 394
204 private: 395 private:
205 void onEmitCode(const EmitArgs& args) override { 396 void onEmitCode(const EmitArgs& args) override {
206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>(); 397 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>();
207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 398 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutp utType()) {
209 SkASSERT(!xp.willReadDstColor());
210 switch(xp.secondaryOutputType()) {
211 case PorterDuffXferProcessor::kNone_SecondaryOutputType:
212 break;
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 }
230 399
231 switch (xp.primaryOutputType()) { 400 BlendFormula blendFormula = xp.getBlendFormula();
232 case PorterDuffXferProcessor::kNone_PrimaryOutputType: 401 if (blendFormula.hasSecondaryOutput()) {
233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary) ; 402 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType ,
234 break; 403 args.fOutputSecondary, args.fInputColor, args.fI nputCoverage);
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 {
249 SkASSERT(xp.willReadDstColor());
250
251 const char* dstColor = fsBuilder->dstColor();
252
253 fsBuilder->codeAppend("vec4 colorBlend =");
254 // append src blend
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(),
256 args.fInputColor, args.fInpu tColor,
257 dstColor, false);
258 // append dst blend
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(),
260 dstColor, args.fInputColor,
261 dstColor, didAppend));
262 fsBuilder->codeAppend(";");
263
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s ;",
265 args.fOutputPrimary, args.fInputCoverage, arg s.fInputCoverage,
266 dstColor);
267 } 404 }
405 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
406 args.fOutputPrimary, args.fInputColor, args.fInputCo verage);
268 } 407 }
269 408
270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {}; 409 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {}
271 410
272 typedef GrGLXferProcessor INHERITED; 411 typedef GrGLXferProcessor INHERITED;
273 }; 412 };
274 413
275 /////////////////////////////////////////////////////////////////////////////// 414 ///////////////////////////////////////////////////////////////////////////////
276 415
277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, 416 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
278 GrBlendCoeff dstBlend,
279 GrColor constant,
280 const DstTexture* dstTexture,
281 bool willReadDstColor)
282 : INHERITED(dstTexture, willReadDstColor)
283 , fSrcBlend(srcBlend)
284 , fDstBlend(dstBlend)
285 , fBlendConstant(constant)
286 , fPrimaryOutputType(kModulate_PrimaryOutputType)
287 , fSecondaryOutputType(kNone_SecondaryOutputType) {
288 this->initClassID<PorterDuffXferProcessor>();
289 }
290
291 PorterDuffXferProcessor::~PorterDuffXferProcessor() {
292 }
293
294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
295 GrProcessorKeyBuilder* b) cons t { 417 GrProcessorKeyBuilder* b) cons t {
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b); 418 GLPorterDuffXferProcessor::GenKey(*this, b);
297 } 419 }
298 420
299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { 421 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this)); 422 return SkNEW(GLPorterDuffXferProcessor);
301 } 423 }
302 424
303 GrXferProcessor::OptFlags 425 GrXferProcessor::OptFlags
304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, 426 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
305 const GrProcOptInfo& coveragePOI, 427 const GrProcOptInfo& coveragePOI,
306 bool doesStencilWrite, 428 bool doesStencilWrite,
307 GrColor* overrideColor, 429 GrColor* overrideColor,
308 const GrCaps& caps) { 430 const GrCaps& caps) {
309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI , 431 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
310 coverage POI, 432 if (!fBlendFormula.modifiesDst()) {
311 doesSten cilWrite); 433 if (!doesStencilWrite) {
312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite()); 434 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
435 }
436 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
437 GrXferProcessor::kIgnoreCoverage_OptFlag |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
439 } else {
440 if (!fBlendFormula.usesInputColor()) {
441 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
442 }
443 if (coveragePOI.isSolidWhite()) {
444 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
445 }
446 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForC overage()) {
447 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
448 }
449 }
313 return optFlags; 450 return optFlags;
314 } 451 }
315 452
316 void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags , 453 ///////////////////////////////////////////////////////////////////////////////
317 const GrCaps& caps, 454
318 bool hasSolidCoverage) { 455 class ShaderPDXferProcessor : public GrXferProcessor {
319 if (this->willReadDstColor()) { 456 public:
320 fPrimaryOutputType = kCustom_PrimaryOutputType; 457 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
321 return; 458 return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
322 } 459 }
323 460
324 if (optFlags & kIgnoreColor_OptFlag) { 461 const char* name() const override { return "Porter Duff Shader"; }
325 if (optFlags & kIgnoreCoverage_OptFlag) { 462 bool hasSecondaryOutput() const override { return false; }
326 fPrimaryOutputType = kNone_PrimaryOutputType; 463
327 return; 464 GrGLXferProcessor* createGLInstance() const override;
328 } else { 465
329 fPrimaryOutputType = kCoverage_PrimaryOutputType; 466 SkXfermode::Mode getXfermode() const { return fXfermode; }
330 return; 467
331 } 468 private:
332 } else if (optFlags & kIgnoreCoverage_OptFlag) { 469 ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTextur e)
333 fPrimaryOutputType = kColor_PrimaryOutputType; 470 : INHERITED(dstTexture, true)
334 return; 471 , fXfermode(xfermode) {
472 this->initClassID<ShaderPDXferProcessor>();
335 } 473 }
336 474
337 // If we do have coverage determine whether it matters. Dual source blendin g is expensive so 475 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrP rocOptInfo&,
338 // we don't do it if we are doing coverage drawing. If we aren't then We al ways do dual source 476 bool, GrColor*, const GrCaps&) override {
339 // blending if we have any effective coverage stages OR the geometry process or doesn't emits 477 return kNone_Opt;
340 // solid coverage. 478 }
341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) { 479
342 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 480 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override;
343 if (kZero_GrBlendCoeff == fDstBlend) { 481
344 // write the coverage value to second color 482 bool onIsEqual(const GrXferProcessor& xpBase) const override {
345 fSecondaryOutputType = kCoverage_SecondaryOutputType; 483 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
346 fDstBlend = kIS2C_GrBlendCoeff; 484 return fXfermode == xp.fXfermode;
347 } else if (kSA_GrBlendCoeff == fDstBlend) { 485 }
348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 486
349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType; 487 const SkXfermode::Mode fXfermode;
350 fDstBlend = kIS2C_GrBlendCoeff; 488
351 } else if (kSC_GrBlendCoeff == fDstBlend) { 489 typedef GrXferProcessor INHERITED;
352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered. 490 };
353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType; 491
354 fDstBlend = kIS2C_GrBlendCoeff; 492 ///////////////////////////////////////////////////////////////////////////////
355 } 493
494 static bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode: :Coeff coeff,
495 const char* colorName, const char* srcColorNa me,
496 const char* dstColorName, bool hasPrevious) {
497 if (SkXfermode::kZero_Coeff == coeff) {
498 return hasPrevious;
499 } else {
500 if (hasPrevious) {
501 fsBuilder->codeAppend(" + ");
356 } 502 }
503 fsBuilder->codeAppendf("%s", colorName);
504 switch (coeff) {
505 case SkXfermode::kOne_Coeff:
506 break;
507 case SkXfermode::kSC_Coeff:
508 fsBuilder->codeAppendf(" * %s", srcColorName);
509 break;
510 case SkXfermode::kISC_Coeff:
511 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
512 break;
513 case SkXfermode::kDC_Coeff:
514 fsBuilder->codeAppendf(" * %s", dstColorName);
515 break;
516 case SkXfermode::kIDC_Coeff:
517 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
518 break;
519 case SkXfermode::kSA_Coeff:
520 fsBuilder->codeAppendf(" * %s.a", srcColorName);
521 break;
522 case SkXfermode::kISA_Coeff:
523 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
524 break;
525 case SkXfermode::kDA_Coeff:
526 fsBuilder->codeAppendf(" * %s.a", dstColorName);
527 break;
528 case SkXfermode::kIDA_Coeff:
529 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
530 break;
531 default:
532 SkFAIL("Unsupported Blend Coeff");
533 }
534 return true;
357 } 535 }
358 } 536 }
359 537
360 GrXferProcessor::OptFlags 538 class GLShaderPDXferProcessor : public GrGLXferProcessor {
361 PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, 539 public:
362 const GrProcOptInfo& coverageP OI, 540 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
363 bool doesStencilWrite) { 541 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>( );
364 if (this->willReadDstColor()) { 542 b->add32(xp.getXfermode());
365 return GrXferProcessor::kNone_Opt;
366 } 543 }
367 544
368 bool srcAIsOne = colorPOI.isOpaque(); 545 private:
369 bool hasCoverage = !coveragePOI.isSolidWhite(); 546 void onEmitCode(const EmitArgs& args) override {
547 const ShaderPDXferProcessor& xp = args.fXP.cast<ShaderPDXferProcessor>() ;
548 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
370 549
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || 550 SkXfermode::Coeff srcCoeff, dstCoeff;
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); 551 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
375 552
376 // When coeffs are (0,1) there is no reason to draw at all, unless 553 const char* dstColor = fsBuilder->dstColor();
377 // stenciling is enabled. Having color writes disabled is effectively 554
378 // (0,1). 555 fsBuilder->codeAppend("vec4 colorBlend =");
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { 556 // append src blend
380 if (doesStencilWrite) { 557 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
381 return GrXferProcessor::kIgnoreColor_OptFlag | 558 args.fInputColor, args.fInputCol or,
382 GrXferProcessor::kSetCoverageDrawing_OptFlag; 559 dstColor, false);
383 } else { 560 // append dst blend
384 fDstBlend = kOne_GrBlendCoeff; 561 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
385 return GrXferProcessor::kSkipDraw_OptFlag; 562 dstColor, args.fInputColor,
386 } 563 dstColor, didAppend));
564 fsBuilder->codeAppend(";");
565
566 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
567 args.fOutputPrimary, args.fInputCoverage, args.fI nputCoverage,
568 dstColor);
387 } 569 }
388 570
389 // if we don't have coverage we can check whether the dst 571 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {}
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 572
411 // check whether coverage can be safely rolled into alpha 573 typedef GrGLXferProcessor INHERITED;
412 // of if we can skip color computation and just emit coverage 574 };
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 575
420 } 576 ///////////////////////////////////////////////////////////////////////////////
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 577
442 } 578 void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
443 } 579 GrProcessorKeyBuilder* b) cons t {
444 } else if (dstCoeffIsOne) { 580 GLShaderPDXferProcessor::GenKey(*this, b);
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 } 581 }
460 582
461 bool PorterDuffXferProcessor::hasSecondaryOutput() const { 583 GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
462 return kNone_SecondaryOutputType != fSecondaryOutputType; 584 return SkNEW(GLShaderPDXferProcessor);
463 } 585 }
464 586
465 /////////////////////////////////////////////////////////////////////////////// 587 ///////////////////////////////////////////////////////////////////////////////
466 588
467 class PDLCDXferProcessor : public GrXferProcessor { 589 class PDLCDXferProcessor : public GrXferProcessor {
468 public: 590 public:
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 591 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInf o& colorPOI);
470 const GrProcOptInfo& colorPOI);
471 592
472 ~PDLCDXferProcessor() override; 593 ~PDLCDXferProcessor() override;
473 594
474 const char* name() const override { return "Porter Duff LCD"; } 595 const char* name() const override { return "Porter Duff LCD"; }
475 596
476 GrGLXferProcessor* createGLInstance() const override; 597 GrGLXferProcessor* createGLInstance() const override;
477 598
478 bool hasSecondaryOutput() const override { return false; } 599 bool hasSecondaryOutput() const override { return false; }
479 600
480 private: 601 private:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 }; 655 };
535 656
536 /////////////////////////////////////////////////////////////////////////////// 657 ///////////////////////////////////////////////////////////////////////////////
537 658
538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) 659 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539 : fBlendConstant(blendConstant) 660 : fBlendConstant(blendConstant)
540 , fAlpha(alpha) { 661 , fAlpha(alpha) {
541 this->initClassID<PDLCDXferProcessor>(); 662 this->initClassID<PDLCDXferProcessor>();
542 } 663 }
543 664
544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 665 GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
545 const GrProcOptInfo& colorPOI) { 666 const GrProcOptInfo& colorPOI) {
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) { 667 if (SkXfermode::kSrcOver_Mode != xfermode) {
547 return NULL; 668 return NULL;
548 } 669 }
549 670
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { 671 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
551 return NULL; 672 return NULL;
552 } 673 }
553 674
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); 675 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
555 uint8_t alpha = GrColorUnpackA(blendConstant); 676 uint8_t alpha = GrColorUnpackA(blendConstant);
556 blendConstant |= (0xff << GrColor_SHIFT_A); 677 blendConstant |= (0xff << GrColor_SHIFT_A);
(...skipping 21 matching lines...) Expand all
578 const GrCaps& caps) { 699 const GrCaps& caps) {
579 // We want to force our primary output to be alpha * Coverage, where alp ha is the alpha 700 // 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 701 // 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 702 // 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. 703 // output is already baked into the blendConstant.
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); 704 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
584 return GrXferProcessor::kOverrideColor_OptFlag; 705 return GrXferProcessor::kOverrideColor_OptFlag;
585 } 706 }
586 707
587 /////////////////////////////////////////////////////////////////////////////// 708 ///////////////////////////////////////////////////////////////////////////////
588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) 709
589 : fSrcCoeff(src), fDstCoeff(dst) { 710 GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
711 : fXfermode(xfermode) {
590 this->initClassID<GrPorterDuffXPFactory>(); 712 this->initClassID<GrPorterDuffXPFactory>();
591 } 713 }
592 714
593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { 715 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
594 switch (mode) { 716 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
595 case SkXfermode::kClear_Mode: { 717 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G rBlendCoeff); 718 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
597 return SkRef(&gClearPDXPF); 719 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
598 break; 720 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
599 } 721 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
600 case SkXfermode::kSrc_Mode: { 722 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBl endCoeff); 723 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
602 return SkRef(&gSrcPDXPF); 724 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
603 break; 725 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
604 } 726 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
605 case SkXfermode::kDst_Mode: { 727 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBl endCoeff); 728 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
607 return SkRef(&gDstPDXPF); 729 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
608 break; 730 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
609 } 731
610 case SkXfermode::kSrcOver_Mode: { 732 static GrPorterDuffXPFactory* gFactories[] = {
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_G rBlendCoeff); 733 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &g SrcInPDXPF,
612 return SkRef(&gSrcOverPDXPF); 734 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDX PF, &gXorPDXPF,
613 break; 735 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
614 } 736 };
615 case SkXfermode::kDstOver_Mode: { 737 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_G rBlendCoeff); 738
617 return SkRef(&gDstOverPDXPF); 739 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
618 break; 740 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 } 741 }
742 return SkRef(gFactories[xfermode]);
673 } 743 }
674 744
675 GrXferProcessor* 745 GrXferProcessor*
676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, 746 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
677 const GrProcOptInfo& colorPOI, 747 const GrProcOptInfo& colorPOI,
678 const GrProcOptInfo& covPOI, 748 const GrProcOptInfo& covPOI,
679 const DstTexture* dstTexture) const { 749 const DstTexture* dstTexture) const {
680 if (covPOI.isFourChannelOutput()) { 750 if (covPOI.isFourChannelOutput()) {
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI); 751 SkASSERT(!dstTexture || !dstTexture->texture());
682 } else { 752 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstTextu re,
684 this->willReadDstColor(caps, colo rPOI, covPOI));
685 } 753 }
754
755 BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
756 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlend ingSupport()) {
757 return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
758 }
759
760 SkASSERT(!dstTexture || !dstTexture->texture());
761 return PorterDuffXferProcessor::Create(blendFormula);
686 } 762 }
687 763
688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, 764 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
689 uint32_t knownColorFlags) const { 765 uint32_t knownColorFlags) const {
690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && 766 if (SkXfermode::kSrcOver_Mode == fXfermode &&
691 kRGBA_GrColorComponentFlags == knownColorFlags) { 767 kRGBA_GrColorComponentFlags == knownColorFlags) {
692 return true; 768 return true;
693 } 769 }
694 return false; 770 return false;
695 } 771 }
696 772
697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 773 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
698 const GrProcOptInfo& coveragePOI, 774 const GrProcOptInfo& coveragePOI,
699 GrXPFactory::InvariantOutput* out put) const { 775 GrXPFactory::InvariantOutput* out put) const {
700 if (!coveragePOI.isSolidWhite()) { 776 output->fWillBlendWithDst = true;
701 output->fWillBlendWithDst = true; 777 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
702 output->fBlendedColorFlags = 0; 778
779 // The blend table doesn't support LCD coverage, but these formulas never ha ve invariant output.
780 if (coveragePOI.isFourChannelOutput()) {
703 return; 781 return;
704 } 782 }
705 783
706 GrBlendCoeff srcCoeff = fSrcCoeff; 784 const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, co veragePOI);
707 GrBlendCoeff dstCoeff = fDstCoeff; 785 if (blendFormula.usesDstColor()) {
708
709 // TODO: figure out to merge this simplify with other current optimization c ode paths and
710 // eventually remove from GrBlend
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags( ),
712 0, 0, 0);
713
714 if (GrBlendCoeffRefsDst(srcCoeff)) {
715 output->fWillBlendWithDst = true;
716 output->fBlendedColorFlags = 0;
717 return; 786 return;
718 } 787 }
719 788
720 if (kZero_GrBlendCoeff != dstCoeff) { 789 SkASSERT(coveragePOI.isSolidWhite());
721 bool srcAIsOne = colorPOI.isOpaque(); 790 SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
723 output->fWillBlendWithDst = true;
724 }
725 output->fBlendedColorFlags = 0;
726 return;
727 }
728 791
729 switch (srcCoeff) { 792 output->fWillBlendWithDst = false;
793
794 switch (blendFormula.fSrcCoeff) {
730 case kZero_GrBlendCoeff: 795 case kZero_GrBlendCoeff:
731 output->fBlendedColor = 0; 796 output->fBlendedColor = 0;
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; 797 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
733 break; 798 return;
734 799
735 case kOne_GrBlendCoeff: 800 case kOne_GrBlendCoeff:
736 output->fBlendedColor = colorPOI.color(); 801 output->fBlendedColor = colorPOI.color();
737 output->fBlendedColorFlags = colorPOI.validFlags(); 802 output->fBlendedColorFlags = colorPOI.validFlags();
738 break; 803 return;
739 804
740 // The src coeff should never refer to the src and if it refers to d st then opaque 805 default: return;
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:
751 SkFAIL("srcCoeff should not refer to src or dst.");
752 break;
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 } 806 }
762
763 output->fWillBlendWithDst = false;
764 } 807 }
765 808
766 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, 809 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
767 const GrProcOptInfo& colorPOI, 810 const GrProcOptInfo& colorPOI,
768 const GrProcOptInfo& coveragePOI) c onst { 811 const GrProcOptInfo& coveragePOI) c onst {
769 // We can always blend correctly if we have dual source blending. 812 if (coveragePOI.isFourChannelOutput()) {
770 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 813 return false; // The LCD XP never does a dst read.
771 return false;
772 } 814 }
773 815
774 if (can_tweak_alpha_for_coverage(fDstCoeff)) { 816 // We fallback on the shader XP when the blend formula would use dual source blending but we
775 return false; 817 // don't have support for it.
776 } 818 return !caps.shaderCaps()->dualSourceBlendingSupport() &&
777 819 get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutpu t();
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 } 820 }
798 821
799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); 822 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800 823
801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, 824 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
802 GrContext*, 825 GrContext*,
803 const GrCaps&, 826 const GrCaps&,
804 GrTexture*[]) { 827 GrTexture*[]) {
805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode)); 828 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode));
806 return GrPorterDuffXPFactory::Create(mode); 829 return GrPorterDuffXPFactory::Create(mode);
807 } 830 }
808 831
832 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
833 int* outPrimary,
834 int* outSecondary) {
835 if (!!strcmp(xp->name(), "Porter Duff")) {
836 *outPrimary = *outSecondary = -1;
837 return;
838 }
839 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)- >getBlendFormula();
840 *outPrimary = blendFormula.fPrimaryOutputType;
841 *outSecondary = blendFormula.fSecondaryOutputType;
842 }
843
OLDNEW
« no previous file with comments | « src/gpu/GrCaps.cpp ('k') | tests/GrPorterDuffTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698