OLD | NEW |
---|---|
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 "GrDrawState.h" | 11 #include "GrDrawState.h" |
11 #include "GrInvariantOutput.h" | 12 #include "GrInvariantOutput.h" |
12 #include "GrProcessor.h" | 13 #include "GrProcessor.h" |
13 #include "GrTypes.h" | 14 #include "GrTypes.h" |
14 #include "GrXferProcessor.h" | 15 #include "GrXferProcessor.h" |
15 #include "gl/GrGLProcessor.h" | 16 #include "gl/GrGLProcessor.h" |
16 #include "gl/builders/GrGLFragmentShaderBuilder.h" | 17 #include "gl/builders/GrGLFragmentShaderBuilder.h" |
17 #include "gl/builders/GrGLProgramBuilder.h" | 18 #include "gl/builders/GrGLProgramBuilder.h" |
18 | 19 |
20 static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageD rawing) { | |
21 /* | |
22 The fractional coverage is f. | |
23 The src and dst coeffs are Cs and Cd. | |
24 The dst and src colors are S and D. | |
25 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the sou rce color's alpha | |
26 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second | |
27 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various poss ibilities for Cd we | |
28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. | |
29 Also, if we're directly rendering coverage (isCoverageDrawing) then coverag e is treated as | |
30 color by definition. | |
31 */ | |
32 // TODO: Once we have a CoverageDrawing XP, we don't need to check is Covera geDrawing here | |
33 return kOne_GrBlendCoeff == dstCoeff || | |
34 kISA_GrBlendCoeff == dstCoeff || | |
35 kISC_GrBlendCoeff == dstCoeff || | |
36 isCoverageDrawing; | |
37 } | |
38 | |
19 class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { | 39 class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { |
20 public: | 40 public: |
21 GrGLPorterDuffXferProcessor(const GrProcessor&) {} | 41 GrGLPorterDuffXferProcessor(const GrProcessor&) {} |
22 | 42 |
23 virtual ~GrGLPorterDuffXferProcessor() {} | 43 virtual ~GrGLPorterDuffXferProcessor() {} |
24 | 44 |
25 virtual void emitCode(GrGLFPBuilder* builder, | 45 virtual void emitCode(GrGLFPBuilder* builder, |
26 const GrFragmentProcessor& fp, | 46 const GrFragmentProcessor& fp, |
27 const char* outputColor, | 47 const char* outputColor, |
28 const char* inputColor, | 48 const char* inputColor, |
29 const TransformedCoordsArray& coords, | 49 const TransformedCoordsArray& coords, |
30 const TextureSamplerArray& samplers) SK_OVERRIDE { | 50 const TextureSamplerArray& samplers) SK_OVERRIDE { |
31 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); | 51 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
32 fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); | 52 fsBuilder->codeAppendf("%s = %s;", outputColor, inputColor); |
33 } | 53 } |
34 | 54 |
35 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_O VERRIDE {}; | 55 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_O VERRIDE {}; |
36 | 56 |
37 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyB uilder* b) {}; | 57 static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyB uilder* b) {}; |
38 | 58 |
39 private: | 59 private: |
40 typedef GrGLXferProcessor INHERITED; | 60 typedef GrGLXferProcessor INHERITED; |
41 }; | 61 }; |
42 | 62 |
43 /////////////////////////////////////////////////////////////////////////////// | 63 /////////////////////////////////////////////////////////////////////////////// |
44 | 64 |
45 GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBl endCoeff dstBlend) | 65 GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBl endCoeff dstBlend, |
46 : fSrcBlend(srcBlend), fDstBlend(dstBlend) { | 66 GrColor constant) |
67 : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) { | |
bsalomon
2014/12/08 15:38:51
Why does this take a constant? Shouldn't it deduce
egdaniel
2014/12/08 16:24:01
The currently the constant gets deduced during the
bsalomon
2014/12/08 18:35:22
You can ignore my comment. I was thinking this was
| |
47 this->initClassID<GrPorterDuffXferProcessor>(); | 68 this->initClassID<GrPorterDuffXferProcessor>(); |
48 } | 69 } |
49 | 70 |
50 GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() { | 71 GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() { |
51 } | 72 } |
52 | 73 |
53 void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps, | 74 void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps, |
54 GrProcessorKeyBuilder* b) cons t { | 75 GrProcessorKeyBuilder* b) cons t { |
55 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b); | 76 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b); |
56 } | 77 } |
57 | 78 |
58 GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const { | 79 GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const { |
59 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this)); | 80 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this)); |
60 } | 81 } |
61 | 82 |
62 void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inou t) const { | 83 void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inou t) const { |
63 inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput); | 84 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); |
64 } | 85 } |
65 | 86 |
87 GrXferProcessor::OptFlags | |
88 GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, | |
89 const GrProcOptInfo& coveragePOI, | |
90 bool isCoverageDrawing, | |
91 bool colorWriteDisabled, | |
92 bool doesStencilWrite, | |
93 GrColor* color, uint8_t* coverage) { | |
94 if (colorWriteDisabled) { | |
95 fSrcBlend = kZero_GrBlendCoeff; | |
96 fDstBlend = kOne_GrBlendCoeff; | |
97 } | |
98 | |
99 bool srcAIsOne; | |
100 bool hasCoverage; | |
101 if (isCoverageDrawing) { | |
102 srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque(); | |
103 hasCoverage = false; | |
104 } else { | |
105 srcAIsOne = colorPOI.isOpaque(); | |
106 hasCoverage = !coveragePOI.isSolidWhite(); | |
107 } | |
108 | |
109 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || | |
110 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); | |
111 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend || | |
112 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne); | |
113 | |
114 // Optimizations when doing RGB Coverage | |
115 if (!coveragePOI.isSingleComponent()) { | |
116 // We want to force our primary output to be alpha * Coverage, where alp ha is the alpha | |
117 // value of the blend the constant. We should already have valid blend c oeff's if we are at | |
118 // a point where we have RGB coverage. We don't need any color stages si nce the known color | |
119 // output is already baked into the blendConstant. | |
120 uint8_t alpha = GrColorUnpackA(fBlendConstant); | |
121 *color = GrColorPackRGBA(alpha, alpha, alpha, alpha); | |
122 return GrXferProcessor::kClearColorStages_OptFlag; | |
123 } | |
124 | |
125 // When coeffs are (0,1) there is no reason to draw at all, unless | |
126 // stenciling is enabled. Having color writes disabled is effectively | |
127 // (0,1). | |
128 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) { | |
129 if (doesStencilWrite) { | |
130 *color = 0xffffffff; | |
131 return GrXferProcessor::kClearColorStages_OptFlag | | |
132 GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
133 } else { | |
134 fDstBlend = kOne_GrBlendCoeff; | |
135 return GrXferProcessor::kSkipDraw_OptFlag; | |
136 } | |
137 } | |
138 | |
139 // if we don't have coverage we can check whether the dst | |
140 // has to read at all. If not, we'll disable blending. | |
141 if (!hasCoverage) { | |
142 if (dstCoeffIsZero) { | |
143 if (kOne_GrBlendCoeff == fSrcBlend) { | |
144 // if there is no coverage and coeffs are (1,0) then we | |
145 // won't need to read the dst at all, it gets replaced by src | |
146 fDstBlend = kZero_GrBlendCoeff; | |
147 return GrXferProcessor::kNone_Opt; | |
148 } else if (kZero_GrBlendCoeff == fSrcBlend) { | |
149 // if the op is "clear" then we don't need to emit a color | |
150 // or blend, just write transparent black into the dst. | |
151 fSrcBlend = kOne_GrBlendCoeff; | |
152 fDstBlend = kZero_GrBlendCoeff; | |
153 *color = 0; | |
154 *coverage = 0xff; | |
155 return GrXferProcessor::kClearColorStages_OptFlag | | |
156 GrXferProcessor::kClearCoverageStages_OptFlag; | |
157 } | |
158 } | |
159 } else if (isCoverageDrawing) { | |
160 // we have coverage but we aren't distinguishing it from alpha by reques t. | |
161 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
162 } else { | |
163 // check whether coverage can be safely rolled into alpha | |
164 // of if we can skip color computation and just emit coverage | |
165 if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) { | |
166 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
167 } | |
168 if (dstCoeffIsZero) { | |
169 if (kZero_GrBlendCoeff == fSrcBlend) { | |
170 // the source color is not included in the blend | |
171 // the dst coeff is effectively zero so blend works out to: | |
172 // (c)(0)D + (1-c)D = (1-c)D. | |
173 fDstBlend = kISA_GrBlendCoeff; | |
174 *color = 0xffffffff; | |
175 return GrXferProcessor::kClearColorStages_OptFlag | | |
176 GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
177 } else if (srcAIsOne) { | |
178 // the dst coeff is effectively zero so blend works out to: | |
179 // cS + (c)(0)D + (1-c)D = cS + (1-c)D. | |
180 // If Sa is 1 then we can replace Sa with c | |
181 // and set dst coeff to 1-Sa. | |
182 fDstBlend = kISA_GrBlendCoeff; | |
183 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
184 } | |
185 } else if (dstCoeffIsOne) { | |
186 // the dst coeff is effectively one so blend works out to: | |
187 // cS + (c)(1)D + (1-c)D = cS + D. | |
188 fDstBlend = kOne_GrBlendCoeff; | |
189 return GrXferProcessor::kSetCoverageDrawing_OptFlag; | |
190 } | |
191 } | |
192 | |
193 return GrXferProcessor::kNone_Opt; | |
194 } | |
66 /////////////////////////////////////////////////////////////////////////////// | 195 /////////////////////////////////////////////////////////////////////////////// |
67 | 196 |
68 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) | 197 GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst) |
69 : fSrc(src), fDst(dst) { | 198 : fSrcCoeff(src), fDstCoeff(dst) { |
70 this->initClassID<GrPorterDuffXPFactory>(); | 199 this->initClassID<GrPorterDuffXPFactory>(); |
71 } | 200 } |
72 | 201 |
73 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { | 202 GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) { |
74 switch (mode) { | 203 switch (mode) { |
75 case SkXfermode::kClear_Mode: { | 204 case SkXfermode::kClear_Mode: { |
76 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G rBlendCoeff); | 205 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_G rBlendCoeff); |
77 return SkRef(&gClearPDXPF); | 206 return SkRef(&gClearPDXPF); |
78 break; | 207 break; |
79 } | 208 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 case SkXfermode::kScreen_Mode: { | 274 case SkXfermode::kScreen_Mode: { |
146 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr BlendCoeff); | 275 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_Gr BlendCoeff); |
147 return SkRef(&gScreenPDXPF); | 276 return SkRef(&gScreenPDXPF); |
148 break; | 277 break; |
149 } | 278 } |
150 default: | 279 default: |
151 return NULL; | 280 return NULL; |
152 } | 281 } |
153 } | 282 } |
154 | 283 |
155 const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const { | 284 GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI, |
156 return GrPorterDuffXferProcessor::Create(fSrc, fDst); | 285 const GrProcOptInfo& covPOI) const { |
286 if (covPOI.isSingleComponent()) { | |
287 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff); | |
288 } else { | |
289 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) { | |
290 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags()); | |
291 GrColor blendConstant = GrUnPreMulColor(colorPOI.color()); | |
292 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_ GrBlendCoeff, | |
293 blendConstant); | |
294 } else { | |
295 return NULL; | |
296 } | |
297 } | |
157 } | 298 } |
158 | 299 |
159 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, | 300 bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, |
160 uint32_t knownColorFlags) const { | 301 uint32_t knownColorFlags) const { |
161 if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst && | 302 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff && |
162 kRGBA_GrColorComponentFlags == knownColorFlags) { | 303 kRGBA_GrColorComponentFlags == knownColorFlags) { |
163 return true; | 304 return true; |
164 } | 305 } |
165 return false; | 306 return false; |
166 } | 307 } |
167 | 308 |
309 bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, | |
310 const GrProcOptInfo& coveragePOI, | |
311 bool isCoverageDrawing, | |
312 bool colorWriteDisabled) const { | |
313 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.i sOpaque()); | |
314 | |
315 if (colorWriteDisabled) { | |
316 return true; | |
317 } | |
318 | |
319 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff || | |
320 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne); | |
321 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff || | |
322 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne); | |
323 | |
324 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) { | |
325 return true; | |
326 } | |
327 | |
328 // if we don't have coverage we can check whether the dst | |
329 // has to read at all. | |
330 if (isCoverageDrawing) { | |
331 // we have coverage but we aren't distinguishing it from alpha by reques t. | |
332 return true; | |
333 } else { | |
334 // check whether coverage can be safely rolled into alpha | |
335 // of if we can skip color computation and just emit coverage | |
336 if (this->canTweakAlphaForCoverage(isCoverageDrawing)) { | |
337 return true; | |
338 } | |
339 if (dstCoeffIsZero) { | |
340 if (kZero_GrBlendCoeff == fSrcCoeff) { | |
341 return true; | |
342 } else if (srcAIsOne) { | |
343 return true; | |
344 } | |
345 } else if (dstCoeffIsOne) { | |
346 return true; | |
347 } | |
348 } | |
349 | |
350 // TODO: once all SkXferEffects are XP's then we will never reads dst here s ince only XP's | |
351 // will readDst and PD XP's don't read dst. | |
352 if ((colorPOI.readsDst() || coveragePOI.readsDst()) && | |
353 kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) { | |
354 return true; | |
355 } | |
356 | |
357 return false; | |
358 } | |
359 | |
360 bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, | |
361 const GrProcOptInfo& coveragePOI, | |
362 bool isCoverageDrawing, | |
363 bool colorWriteDisabled) const { | |
364 if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) { | |
365 return true; | |
366 } | |
367 | |
368 // TODO: once all SkXferEffects are XP's then we will never reads dst here s ince only XP's | |
369 // will readDst and PD XP's don't read dst. | |
370 if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) { | |
371 return true; | |
372 } | |
373 | |
374 if (GrBlendCoeffRefsDst(fSrcCoeff)) { | |
375 return true; | |
376 } | |
377 | |
378 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.i sOpaque()); | |
379 | |
380 if (!(kZero_GrBlendCoeff == fDstCoeff || | |
381 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) { | |
382 return true; | |
383 } | |
384 | |
385 return false; | |
386 } | |
387 | |
388 bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) con st { | |
389 return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing); | |
390 } | |
391 | |
392 bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI , | |
393 const GrProcOptInfo& coverage POI, | |
394 GrColor* solidColor, | |
395 uint32_t* solidColorKnownComp onents) const { | |
396 if (!coveragePOI.isSolidWhite()) { | |
397 return false; | |
398 } | |
399 | |
400 SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents)); | |
401 | |
402 GrBlendCoeff srcCoeff = fSrcCoeff; | |
403 GrBlendCoeff dstCoeff = fDstCoeff; | |
404 | |
405 // TODO: figure out to merge this simplify with other current optimization c ode paths and | |
406 // eventually remove from GrBlend | |
407 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags( ), | |
408 0, 0, 0); | |
409 | |
410 bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoef f); | |
411 if (solidColor) { | |
412 if (opaque) { | |
413 switch (srcCoeff) { | |
414 case kZero_GrBlendCoeff: | |
415 *solidColor = 0; | |
416 *solidColorKnownComponents = kRGBA_GrColorComponentFlags; | |
417 break; | |
418 | |
419 case kOne_GrBlendCoeff: | |
420 *solidColor = colorPOI.color(); | |
421 *solidColorKnownComponents = colorPOI.validFlags(); | |
422 break; | |
423 | |
424 // The src coeff should never refer to the src and if it refers to dst then opaque | |
425 // should have been false. | |
426 case kSC_GrBlendCoeff: | |
427 case kISC_GrBlendCoeff: | |
428 case kDC_GrBlendCoeff: | |
429 case kIDC_GrBlendCoeff: | |
430 case kSA_GrBlendCoeff: | |
431 case kISA_GrBlendCoeff: | |
432 case kDA_GrBlendCoeff: | |
433 case kIDA_GrBlendCoeff: | |
434 default: | |
435 SkFAIL("srcCoeff should not refer to src or dst."); | |
436 break; | |
437 | |
438 // TODO: update this once GrPaint actually has a const color. | |
439 case kConstC_GrBlendCoeff: | |
440 case kIConstC_GrBlendCoeff: | |
441 case kConstA_GrBlendCoeff: | |
442 case kIConstA_GrBlendCoeff: | |
443 *solidColorKnownComponents = 0; | |
444 break; | |
445 } | |
446 } else { | |
447 solidColorKnownComponents = 0; | |
448 } | |
449 } | |
450 return opaque; | |
451 } | |
452 | |
453 | |
OLD | NEW |