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

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: Fix issues with clang and msvc 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
« no previous file with comments | « src/gpu/GrBlend.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 "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.
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 have a bug
100 // where it will sign-extend them if the last bit is set.
Chris Dalton 2015/05/22 17:35:01 This appears in violation of the C++03 9.6/4 stand
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));
Chris Dalton 2015/05/22 17:35:02 Oops, I meant to add these before but they got los
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 /*>> Has coverage, input color unknown <<*/ {{
219
220 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
221 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_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 */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
226 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_ OutputType),
227 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
228 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
229 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
230 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kID A_GrBlendCoeff),
231 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
232 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
233 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_ OutputType),
234 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
235
236 }, /*>> No coverage, input color unknown <<*/ {
237
238 /* clear */ DST_CLEAR_FORMULA,
239 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_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 */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
244 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
245 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
246 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
247 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
248 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
249 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
250 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
251 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
252 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
253
254 }}, /*>> Has coverage, input color opaque <<*/ {{
255
256 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
257 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
258 /* dst */ NO_DST_WRITE_FORMULA,
259 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
260 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
261 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
262 /* dst-in */ NO_DST_WRITE_FORMULA,
263 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
264 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_Out putType),
265 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
266 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
267 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
268 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
269 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_ OutputType),
270 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
271
272 }, /*>> No coverage, input color opaque <<*/ {
273
274 /* clear */ DST_CLEAR_FORMULA,
275 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
276 /* dst */ NO_DST_WRITE_FORMULA,
277 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
278 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
279 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
280 /* dst-in */ NO_DST_WRITE_FORMULA,
281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
282 /* dst-out */ DST_CLEAR_FORMULA,
283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
287 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
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()][xfermode ];
33 } 298 }
34 299
300 static BlendFormula get_unoptimized_blend_formula(SkXfermode::Mode xfermode) {
301 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
302
303 return gBlendTable[0][0][xfermode];
304 }
305
306 ///////////////////////////////////////////////////////////////////////////////
307
35 class PorterDuffXferProcessor : public GrXferProcessor { 308 class PorterDuffXferProcessor : public GrXferProcessor {
36 public: 309 public:
37 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 310 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrDeviceCoor dTexture* dstCopy,
38 GrColor constant, const GrDeviceCoordTexture* dstCopy,
39 bool willReadDstColor) { 311 bool willReadDstColor) {
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant , dstCopy, 312 return SkNEW_ARGS(PorterDuffXferProcessor, (xfermode, dstCopy, willReadD stColor));
41 willReadDstColor));
42 } 313 }
43 314
44 ~PorterDuffXferProcessor() override; 315 ~PorterDuffXferProcessor() override;
45 316
46 const char* name() const override { return "Porter Duff"; } 317 const char* name() const override { return "Porter Duff"; }
47 318
48 GrGLXferProcessor* createGLInstance() const override; 319 GrGLXferProcessor* createGLInstance() const override;
49 320
50 bool hasSecondaryOutput() const override; 321 bool hasSecondaryOutput() const override {
322 return fBlendFormula.hasSecondaryOutput();
323 }
51 324
52 /////////////////////////////////////////////////////////////////////////// 325 SkXfermode::Mode getXfermode() const { return fXfermode; }
53 /// @name Stage Output Types 326 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 327
90 private: 328 private:
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColo r constant, 329 PorterDuffXferProcessor(SkXfermode::Mode, const GrDeviceCoordTexture* dstCop y,
92 const GrDeviceCoordTexture* dstCopy, bool willReadDs tColor); 330 bool willReadDstColor);
93 331
94 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI, 332 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
95 const GrProcOptInfo& coveragePO I, 333 const GrProcOptInfo& coveragePO I,
96 bool doesStencilWrite, 334 bool doesStencilWrite,
97 GrColor* overrideColor, 335 GrColor* overrideColor,
98 const GrCaps& caps) override; 336 const GrCaps& caps) override;
99 337
100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override; 338 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c onst override;
101 339
102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override { 340 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
103 if (!this->willReadDstColor()) { 341 if (!this->willReadDstColor()) {
104 blendInfo->fSrcBlend = fSrcBlend; 342 blendInfo->fEquation = fBlendFormula.fBlendEquation;
105 blendInfo->fDstBlend = fDstBlend; 343 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
106 } else { 344 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff; 345 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
108 blendInfo->fDstBlend = kZero_GrBlendCoeff;
109 } 346 }
110 blendInfo->fBlendConstant = fBlendConstant;
111 } 347 }
112 348
113 bool onIsEqual(const GrXferProcessor& xpBase) const override { 349 bool onIsEqual(const GrXferProcessor& xpBase) const override {
114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> (); 350 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor> ();
115 if (fSrcBlend != xp.fSrcBlend || 351 return fXfermode == xp.fXfermode &&
116 fDstBlend != xp.fDstBlend || 352 fBlendFormula == xp.fBlendFormula;
117 fBlendConstant != xp.fBlendConstant ||
118 fPrimaryOutputType != xp.fPrimaryOutputType ||
119 fSecondaryOutputType != xp.fSecondaryOutputType) {
120 return false;
121 }
122 return true;
123 } 353 }
124 354
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colo rPOI, 355 SkXfermode::Mode fXfermode;
126 const GrProcOptInfo& cove ragePOI, 356 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 357
138 typedef GrXferProcessor INHERITED; 358 typedef GrXferProcessor INHERITED;
139 }; 359 };
140 360
141 /////////////////////////////////////////////////////////////////////////////// 361 ///////////////////////////////////////////////////////////////////////////////
142 362
143 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff , 363 void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilde r* fsBuilder,
364 BlendFormula::OutputType outputType, const char* output ,
365 const char* inColor, const char* inCoverage) {
366 switch (outputType) {
367 case BlendFormula::kNone_OutputType:
368 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
369 break;
370 case BlendFormula::kCoverage_OutputType:
371 fsBuilder->codeAppendf("%s = %s;",
372 output, xp.readsCoverage() ? inCoverage : "ve c4(1.0)");
373 break;
374 case BlendFormula::kModulate_OutputType:
375 if (xp.readsCoverage()) {
376 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCover age);
377 } else {
378 fsBuilder->codeAppendf("%s = %s;", output, inColor);
379 }
380 break;
381 case BlendFormula::kISAModulate_OutputType:
382 if (xp.readsCoverage()) {
383 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColo r, inCoverage);
384 } else {
385 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor );
386 }
387 break;
388 case BlendFormula::kISCModulate_OutputType:
389 if (xp.readsCoverage()) {
390 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, in Color, inCoverage);
391 } else {
392 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
393 }
394 break;
395 default:
396 SkFAIL("Unsupported output type.");
397 break;
398 }
399 }
400
401 bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
144 const char* colorName, const char* srcColorName, 402 const char* colorName, const char* srcColorName,
145 const char* dstColorName, bool hasPrevious) { 403 const char* dstColorName, bool hasPrevious) {
146 if (kZero_GrBlendCoeff == coeff) { 404 if (SkXfermode::kZero_Coeff == coeff) {
147 return hasPrevious; 405 return hasPrevious;
148 } else { 406 } else {
149 if (hasPrevious) { 407 if (hasPrevious) {
150 fsBuilder->codeAppend(" + "); 408 fsBuilder->codeAppend(" + ");
151 } 409 }
152 fsBuilder->codeAppendf("%s", colorName); 410 fsBuilder->codeAppendf("%s", colorName);
153 switch (coeff) { 411 switch (coeff) {
154 case kOne_GrBlendCoeff: 412 case SkXfermode::kOne_Coeff:
155 break; 413 break;
156 case kSC_GrBlendCoeff: 414 case SkXfermode::kSC_Coeff:
157 fsBuilder->codeAppendf(" * %s", srcColorName); 415 fsBuilder->codeAppendf(" * %s", srcColorName);
158 break; 416 break;
159 case kISC_GrBlendCoeff: 417 case SkXfermode::kISC_Coeff:
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName); 418 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
161 break; 419 break;
162 case kDC_GrBlendCoeff: 420 case SkXfermode::kDC_Coeff:
163 fsBuilder->codeAppendf(" * %s", dstColorName); 421 fsBuilder->codeAppendf(" * %s", dstColorName);
164 break; 422 break;
165 case kIDC_GrBlendCoeff: 423 case SkXfermode::kIDC_Coeff:
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName); 424 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
167 break; 425 break;
168 case kSA_GrBlendCoeff: 426 case SkXfermode::kSA_Coeff:
169 fsBuilder->codeAppendf(" * %s.a", srcColorName); 427 fsBuilder->codeAppendf(" * %s.a", srcColorName);
170 break; 428 break;
171 case kISA_GrBlendCoeff: 429 case SkXfermode::kISA_Coeff:
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName); 430 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
173 break; 431 break;
174 case kDA_GrBlendCoeff: 432 case SkXfermode::kDA_Coeff:
175 fsBuilder->codeAppendf(" * %s.a", dstColorName); 433 fsBuilder->codeAppendf(" * %s.a", dstColorName);
176 break; 434 break;
177 case kIDA_GrBlendCoeff: 435 case SkXfermode::kIDA_Coeff:
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName); 436 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
179 break; 437 break;
180 default: 438 default:
181 SkFAIL("Unsupported Blend Coeff"); 439 SkFAIL("Unsupported Blend Coeff");
182 } 440 }
183 return true; 441 return true;
184 } 442 }
185 } 443 }
186 444
187 class GLPorterDuffXferProcessor : public GrGLXferProcessor { 445 class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188 public: 446 public:
189 GLPorterDuffXferProcessor(const GrProcessor&) {} 447 GLPorterDuffXferProcessor(const GrProcessor&) {}
190 448
191 virtual ~GLPorterDuffXferProcessor() {} 449 virtual ~GLPorterDuffXferProcessor() {}
192 450
193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps, 451 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
194 GrProcessorKeyBuilder* b) { 452 GrProcessorKeyBuilder* b) {
195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>(); 453 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcess or>();
196 b->add32(xp.primaryOutputType());
197 b->add32(xp.secondaryOutputType());
198 if (xp.willReadDstColor()) { 454 if (xp.willReadDstColor()) {
199 b->add32(xp.getSrcBlend()); 455 b->add32(xp.getXfermode()); // Parent class includes willReadDstCol or() in key.
200 b->add32(xp.getDstBlend()); 456 } else {
457 b->add32(SkToInt(xp.readsCoverage()) |
458 (xp.getBlendFormula().fPrimaryOutputType << 1) |
459 (xp.getBlendFormula().fSecondaryOutputType << 4));
460 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
201 } 461 }
202 }; 462 };
203 463
204 private: 464 private:
205 void onEmitCode(const EmitArgs& args) override { 465 void onEmitCode(const EmitArgs& args) override {
206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>(); 466 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcesso r>();
207 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 467 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutp utType()) { 468 if (!xp.willReadDstColor()) {
209 SkASSERT(!xp.willReadDstColor()); 469 BlendFormula blendFormula = xp.getBlendFormula();
210 switch(xp.secondaryOutputType()) { 470 if (blendFormula.hasSecondaryOutput()) {
211 case PorterDuffXferProcessor::kNone_SecondaryOutputType: 471 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutput Type,
212 break; 472 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 } 473 }
230 474 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
231 switch (xp.primaryOutputType()) { 475 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 { 476 } else {
249 SkASSERT(xp.willReadDstColor()); 477 SkASSERT(xp.willReadDstColor());
250 478
479 SkXfermode::Coeff srcCoeff, dstCoeff;
480 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
481
251 const char* dstColor = fsBuilder->dstColor(); 482 const char* dstColor = fsBuilder->dstColor();
252 483
253 fsBuilder->codeAppend("vec4 colorBlend ="); 484 fsBuilder->codeAppend("vec4 colorBlend =");
254 // append src blend 485 // append src blend
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(), 486 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
256 args.fInputColor, args.fInpu tColor, 487 args.fInputColor, args.fInpu tColor,
257 dstColor, false); 488 dstColor, false);
258 // append dst blend 489 // append dst blend
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(), 490 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
260 dstColor, args.fInputColor, 491 dstColor, args.fInputColor,
261 dstColor, didAppend)); 492 dstColor, didAppend));
262 fsBuilder->codeAppend(";"); 493 fsBuilder->codeAppend(";");
263 494
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s ;", 495 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s ;",
265 args.fOutputPrimary, args.fInputCoverage, arg s.fInputCoverage, 496 args.fOutputPrimary, args.fInputCoverage, arg s.fInputCoverage,
266 dstColor); 497 dstColor);
267 } 498 }
268 } 499 }
269 500
270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {}; 501 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) overri de {};
271 502
272 typedef GrGLXferProcessor INHERITED; 503 typedef GrGLXferProcessor INHERITED;
273 }; 504 };
274 505
275 /////////////////////////////////////////////////////////////////////////////// 506 ///////////////////////////////////////////////////////////////////////////////
276 507
277 PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend, 508 PorterDuffXferProcessor::PorterDuffXferProcessor(SkXfermode::Mode xfermode,
278 GrBlendCoeff dstBlend,
279 GrColor constant,
280 const GrDeviceCoordTexture* dst Copy, 509 const GrDeviceCoordTexture* dst Copy,
281 bool willReadDstColor) 510 bool willReadDstColor)
282 : INHERITED(dstCopy, willReadDstColor) 511 : INHERITED(dstCopy, willReadDstColor)
283 , fSrcBlend(srcBlend) 512 , fXfermode(xfermode)
284 , fDstBlend(dstBlend) 513 , fBlendFormula(get_unoptimized_blend_formula(xfermode)) {
285 , fBlendConstant(constant)
286 , fPrimaryOutputType(kModulate_PrimaryOutputType)
287 , fSecondaryOutputType(kNone_SecondaryOutputType) {
288 this->initClassID<PorterDuffXferProcessor>(); 514 this->initClassID<PorterDuffXferProcessor>();
289 } 515 }
290 516
291 PorterDuffXferProcessor::~PorterDuffXferProcessor() { 517 PorterDuffXferProcessor::~PorterDuffXferProcessor() {
292 } 518 }
293 519
294 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps, 520 void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
295 GrProcessorKeyBuilder* b) cons t { 521 GrProcessorKeyBuilder* b) cons t {
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b); 522 GLPorterDuffXferProcessor::GenKey(*this, caps, b);
297 } 523 }
298 524
299 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const { 525 GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this)); 526 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
301 } 527 }
302 528
303 GrXferProcessor::OptFlags 529 GrXferProcessor::OptFlags
304 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI, 530 PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
305 const GrProcOptInfo& coveragePOI, 531 const GrProcOptInfo& coveragePOI,
306 bool doesStencilWrite, 532 bool doesStencilWrite,
307 GrColor* overrideColor, 533 GrColor* overrideColor,
308 const GrCaps& caps) { 534 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()) { 535 if (this->willReadDstColor()) {
365 return GrXferProcessor::kNone_Opt; 536 return GrXferProcessor::kNone_Opt;
366 } 537 }
367 538
368 bool srcAIsOne = colorPOI.isOpaque(); 539 fBlendFormula = get_blend_formula(fXfermode, colorPOI, coveragePOI);
369 bool hasCoverage = !coveragePOI.isSolidWhite();
370 540
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || 541 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); 542 if (!fBlendFormula.modifiesDst()) {
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || 543 if (!doesStencilWrite) {
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); 544 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
375 545 }
376 // When coeffs are (0,1) there is no reason to draw at all, unless 546 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
377 // stenciling is enabled. Having color writes disabled is effectively 547 GrXferProcessor::kIgnoreCoverage_OptFlag |
378 // (0,1). 548 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { 549 } else {
380 if (doesStencilWrite) { 550 if (!fBlendFormula.usesInputColor()) {
381 return GrXferProcessor::kIgnoreColor_OptFlag | 551 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
382 GrXferProcessor::kSetCoverageDrawing_OptFlag; 552 }
383 } else { 553 if (coveragePOI.isSolidWhite()) {
384 fDstBlend = kOne_GrBlendCoeff; 554 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
385 return GrXferProcessor::kSkipDraw_OptFlag; 555 }
556 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForC overage()) {
557 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
386 } 558 }
387 } 559 }
388 560
389 // if we don't have coverage we can check whether the dst 561 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 } 562 }
464 563
465 /////////////////////////////////////////////////////////////////////////////// 564 ///////////////////////////////////////////////////////////////////////////////
466 565
467 class PDLCDXferProcessor : public GrXferProcessor { 566 class PDLCDXferProcessor : public GrXferProcessor {
468 public: 567 public:
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 568 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInf o& colorPOI);
470 const GrProcOptInfo& colorPOI);
471 569
472 ~PDLCDXferProcessor() override; 570 ~PDLCDXferProcessor() override;
473 571
474 const char* name() const override { return "Porter Duff LCD"; } 572 const char* name() const override { return "Porter Duff LCD"; }
475 573
476 GrGLXferProcessor* createGLInstance() const override; 574 GrGLXferProcessor* createGLInstance() const override;
477 575
478 bool hasSecondaryOutput() const override { return false; } 576 bool hasSecondaryOutput() const override { return false; }
479 577
480 private: 578 private:
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
534 }; 632 };
535 633
536 /////////////////////////////////////////////////////////////////////////////// 634 ///////////////////////////////////////////////////////////////////////////////
537 635
538 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha) 636 PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539 : fBlendConstant(blendConstant) 637 : fBlendConstant(blendConstant)
540 , fAlpha(alpha) { 638 , fAlpha(alpha) {
541 this->initClassID<PDLCDXferProcessor>(); 639 this->initClassID<PDLCDXferProcessor>();
542 } 640 }
543 641
544 GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, 642 GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
545 const GrProcOptInfo& colorPOI) { 643 const GrProcOptInfo& colorPOI) {
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) { 644 if (SkXfermode::kSrcOver_Mode != xfermode) {
547 return NULL; 645 return NULL;
548 } 646 }
549 647
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) { 648 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
551 return NULL; 649 return NULL;
552 } 650 }
553 651
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); 652 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
555 uint8_t alpha = GrColorUnpackA(blendConstant); 653 uint8_t alpha = GrColorUnpackA(blendConstant);
556 blendConstant |= (0xff << GrColor_SHIFT_A); 654 blendConstant |= (0xff << GrColor_SHIFT_A);
(...skipping 21 matching lines...) Expand all
578 const GrCaps& caps) { 676 const GrCaps& caps) {
579 // We want to force our primary output to be alpha * Coverage, where alp ha is the alpha 677 // 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 678 // 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 679 // 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. 680 // output is already baked into the blendConstant.
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha); 681 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
584 return GrXferProcessor::kOverrideColor_OptFlag; 682 return GrXferProcessor::kOverrideColor_OptFlag;
585 } 683 }
586 684
587 /////////////////////////////////////////////////////////////////////////////// 685 ///////////////////////////////////////////////////////////////////////////////
588 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) 686
589 : fSrcCoeff(src), fDstCoeff(dst) { 687 GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
688 : fXfermode(xfermode) {
590 this->initClassID<GrPorterDuffXPFactory>(); 689 this->initClassID<GrPorterDuffXPFactory>();
591 } 690 }
592 691
593 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { 692 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
594 switch (mode) { 693 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
595 case SkXfermode::kClear_Mode: { 694 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G rBlendCoeff); 695 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
597 return SkRef(&gClearPDXPF); 696 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
598 break; 697 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
599 } 698 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
600 case SkXfermode::kSrc_Mode: { 699 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBl endCoeff); 700 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
602 return SkRef(&gSrcPDXPF); 701 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
603 break; 702 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
604 } 703 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
605 case SkXfermode::kDst_Mode: { 704 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBl endCoeff); 705 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
607 return SkRef(&gDstPDXPF); 706 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
608 break; 707 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
609 } 708
610 case SkXfermode::kSrcOver_Mode: { 709 static GrPorterDuffXPFactory* gFactories[] = {
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_G rBlendCoeff); 710 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &g SrcInPDXPF,
612 return SkRef(&gSrcOverPDXPF); 711 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDX PF, &gXorPDXPF,
613 break; 712 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
614 } 713 };
615 case SkXfermode::kDstOver_Mode: { 714 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_G rBlendCoeff); 715
617 return SkRef(&gDstOverPDXPF); 716 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
618 break; 717 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 } 718 }
719 return SkRef(gFactories[xfermode]);
673 } 720 }
674 721
675 GrXferProcessor* 722 GrXferProcessor*
676 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps, 723 GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
677 const GrProcOptInfo& colorPOI, 724 const GrProcOptInfo& colorPOI,
678 const GrProcOptInfo& covPOI, 725 const GrProcOptInfo& covPOI,
679 const GrDeviceCoordTexture* dstCopy ) const { 726 const GrDeviceCoordTexture* dstCopy ) const {
680 if (covPOI.isFourChannelOutput()) { 727 if (covPOI.isFourChannelOutput()) {
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI); 728 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
682 } else { 729 } else {
683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy, 730 return PorterDuffXferProcessor::Create(fXfermode, dstCopy,
684 this->willReadDstColor(caps, colo rPOI, covPOI)); 731 this->willReadDstColor(caps, colo rPOI, covPOI));
685 } 732 }
686 } 733 }
687 734
688 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, 735 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
689 uint32_t knownColorFlags) const { 736 uint32_t knownColorFlags) const {
690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && 737 if (SkXfermode::kSrcOver_Mode == fXfermode &&
691 kRGBA_GrColorComponentFlags == knownColorFlags) { 738 kRGBA_GrColorComponentFlags == knownColorFlags) {
692 return true; 739 return true;
693 } 740 }
694 return false; 741 return false;
695 } 742 }
696 743
697 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, 744 void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
698 const GrProcOptInfo& coveragePOI, 745 const GrProcOptInfo& coveragePOI,
699 GrXPFactory::InvariantOutput* out put) const { 746 GrXPFactory::InvariantOutput* out put) const {
700 if (!coveragePOI.isSolidWhite()) { 747 const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, co veragePOI);
748
749 if (blendFormula.usesDstColor()) {
701 output->fWillBlendWithDst = true; 750 output->fWillBlendWithDst = true;
702 output->fBlendedColorFlags = 0; 751 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
703 return; 752 return;
704 } 753 }
705 754
706 GrBlendCoeff srcCoeff = fSrcCoeff; 755 SkASSERT(coveragePOI.isSolidWhite());
707 GrBlendCoeff dstCoeff = fDstCoeff; 756 SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
708 757
709 // TODO: figure out to merge this simplify with other current optimization c ode paths and 758 output->fWillBlendWithDst = false;
710 // eventually remove from GrBlend
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags( ),
712 0, 0, 0);
713 759
714 if (GrBlendCoeffRefsDst(srcCoeff)) { 760 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: 761 case kZero_GrBlendCoeff:
731 output->fBlendedColor = 0; 762 output->fBlendedColor = 0;
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags; 763 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
733 break; 764 return;
734 765
735 case kOne_GrBlendCoeff: 766 case kOne_GrBlendCoeff:
736 output->fBlendedColor = colorPOI.color(); 767 output->fBlendedColor = colorPOI.color();
737 output->fBlendedColorFlags = colorPOI.validFlags(); 768 output->fBlendedColorFlags = colorPOI.validFlags();
738 break; 769 return;
739 770
740 // The src coeff should never refer to the src and if it refers to d st then opaque 771 // 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: 772 default:
751 SkFAIL("srcCoeff should not refer to src or dst."); 773 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
752 break; 774 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 } 775 }
762
763 output->fWillBlendWithDst = false;
764 } 776 }
765 777
766 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, 778 bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
767 const GrProcOptInfo& colorPOI, 779 const GrProcOptInfo& colorPOI,
768 const GrProcOptInfo& coveragePOI) c onst { 780 const GrProcOptInfo& coveragePOI) c onst {
769 // We can always blend correctly if we have dual source blending. 781 // Some formulas use dual source blending, so we fall back if it is required but not supported.
770 if (caps.shaderCaps()->dualSourceBlendingSupport()) { 782 return !caps.shaderCaps()->dualSourceBlendingSupport() &&
771 return false; 783 get_blend_formula(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 } 784 }
798 785
799 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory); 786 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800 787
801 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random, 788 GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
802 GrContext*, 789 GrContext*,
803 const GrCaps&, 790 const GrCaps&,
804 GrTexture*[]) { 791 GrTexture*[]) {
805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode)); 792 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::k LastCoeffMode));
806 return GrPorterDuffXPFactory::Create(mode); 793 return GrPorterDuffXPFactory::Create(mode);
807 } 794 }
808 795
796 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
797 int* outPrimary,
798 int* outSecondary) {
799 if (!!strcmp(xp->name(), "Porter Duff")) {
800 *outPrimary = *outSecondary = -1;
801 return;
802 }
803 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)- >getBlendFormula();
804 *outPrimary = blendFormula.fPrimaryOutputType;
805 *outSecondary = blendFormula.fSecondaryOutputType;
806 }
807
OLDNEW
« no previous file with comments | « src/gpu/GrBlend.cpp ('k') | tests/GrPorterDuffTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698