blob: 6255e4a9138773db51495591f9d7244c270f3727 [file] [log] [blame]
egdaniel378092f2014-12-03 10:40:13 -08001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
egdanielced90102014-12-05 12:40:52 -08008#include "effects/GrPorterDuffXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -08009
egdaniel95131432014-12-09 11:15:43 -080010#include "GrBlend.h"
egdaniel378092f2014-12-03 10:40:13 -080011#include "GrDrawState.h"
egdanielc2304142014-12-11 13:15:13 -080012#include "GrDrawTargetCaps.h"
egdaniel378092f2014-12-03 10:40:13 -080013#include "GrInvariantOutput.h"
14#include "GrProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080015#include "GrTypes.h"
16#include "GrXferProcessor.h"
egdanielc2304142014-12-11 13:15:13 -080017#include "gl/GrGLXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080018#include "gl/builders/GrGLFragmentShaderBuilder.h"
19#include "gl/builders/GrGLProgramBuilder.h"
20
egdaniel95131432014-12-09 11:15:43 -080021static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) {
22 /*
23 The fractional coverage is f.
24 The src and dst coeffs are Cs and Cd.
25 The dst and src colors are S and D.
26 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
27 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
28 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
29 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
30 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
31 color by definition.
32 */
33 // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here
34 return kOne_GrBlendCoeff == dstCoeff ||
35 kISA_GrBlendCoeff == dstCoeff ||
36 kISC_GrBlendCoeff == dstCoeff ||
37 isCoverageDrawing;
38}
39
egdaniel378092f2014-12-03 10:40:13 -080040class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
41public:
joshualitteb2a6762014-12-04 11:35:33 -080042 GrGLPorterDuffXferProcessor(const GrProcessor&) {}
egdaniel378092f2014-12-03 10:40:13 -080043
44 virtual ~GrGLPorterDuffXferProcessor() {}
45
egdanielc2304142014-12-11 13:15:13 -080046 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
47 const GrPorterDuffXferProcessor& xp = args.fXP.cast<GrPorterDuffXferProcessor>();
48 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
49 if (xp.hasSecondaryOutput()) {
50 switch(xp.secondaryOutputType()) {
51 case GrPorterDuffXferProcessor::kCoverage_SecondaryOutputType:
52 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
53 break;
54 case GrPorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
55 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
56 args.fOutputSecondary, args.fInputColor,
57 args.fInputCoverage);
58 break;
59 case GrPorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
60 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
61 args.fOutputSecondary, args.fInputColor,
62 args.fInputCoverage);
63 break;
64 default:
65 SkFAIL("Unexpected Secondary Output");
66 }
67 }
68
69 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
70 args.fInputCoverage);
71 if (GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType == xp.primaryOutputType()){
72 fsBuilder->codeAppendf("%s += (vec4(1.0) - %s) * %s;", args.fOutputPrimary,
73 args.fInputCoverage, fsBuilder->dstColor());
74 }
egdaniel378092f2014-12-03 10:40:13 -080075 }
76
egdanielc2304142014-12-11 13:15:13 -080077 virtual void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
egdaniel378092f2014-12-03 10:40:13 -080078
egdanielc2304142014-12-11 13:15:13 -080079 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
80 GrProcessorKeyBuilder* b) {
81 const GrPorterDuffXferProcessor& xp = processor.cast<GrPorterDuffXferProcessor>();
82 b->add32(xp.primaryOutputType());
83 b->add32(xp.secondaryOutputType());
84 };
egdaniel378092f2014-12-03 10:40:13 -080085
86private:
87 typedef GrGLXferProcessor INHERITED;
88};
89
90///////////////////////////////////////////////////////////////////////////////
91
egdaniel95131432014-12-09 11:15:43 -080092GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
93 GrColor constant)
egdanielc2304142014-12-11 13:15:13 -080094 : fSrcBlend(srcBlend)
95 , fDstBlend(dstBlend)
96 , fBlendConstant(constant)
97 , fPrimaryOutputType(kModulate_PrimaryOutputType)
98 , fSecondaryOutputType(kNone_SecondaryOutputType) {
joshualitteb2a6762014-12-04 11:35:33 -080099 this->initClassID<GrPorterDuffXferProcessor>();
100}
egdaniel378092f2014-12-03 10:40:13 -0800101
102GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() {
103}
104
joshualitteb2a6762014-12-04 11:35:33 -0800105void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps,
106 GrProcessorKeyBuilder* b) const {
107 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b);
108}
109
egdanielc2304142014-12-11 13:15:13 -0800110GrGLXferProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800111 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -0800112}
113
114void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
egdaniel95131432014-12-09 11:15:43 -0800115 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
egdaniel378092f2014-12-03 10:40:13 -0800116}
117
egdaniel95131432014-12-09 11:15:43 -0800118GrXferProcessor::OptFlags
119GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
120 const GrProcOptInfo& coveragePOI,
121 bool isCoverageDrawing,
122 bool colorWriteDisabled,
123 bool doesStencilWrite,
egdanielc2304142014-12-11 13:15:13 -0800124 GrColor* color, uint8_t* coverage,
125 const GrDrawTargetCaps& caps) {
126 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI,
127 coveragePOI,
128 isCoverageDrawing,
129 colorWriteDisabled,
130 doesStencilWrite,
131 color,
132 coverage);
133
134 this->calcOutputTypes(optFlags, caps, isCoverageDrawing || coveragePOI.isSolidWhite(),
135 colorPOI.readsDst() || coveragePOI.readsDst());
136 return optFlags;
137}
138
139void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
140 const GrDrawTargetCaps& caps,
141 bool hasSolidCoverage, bool readsDst) {
142 // If we do have coverage determine whether it matters. Dual source blending is expensive so
143 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
144 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
145 // solid coverage.
146 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
147 if (caps.dualSourceBlendingSupport()) {
148 if (kZero_GrBlendCoeff == fDstBlend) {
149 // write the coverage value to second color
150 fSecondaryOutputType = kCoverage_SecondaryOutputType;
151 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
152 } else if (kSA_GrBlendCoeff == fDstBlend) {
153 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
154 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
155 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
156 } else if (kSC_GrBlendCoeff == fDstBlend) {
157 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
158 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
159 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
160 }
161 } else if (readsDst &&
162 kOne_GrBlendCoeff == fSrcBlend &&
163 kZero_GrBlendCoeff == fDstBlend) {
164 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
165 }
166 }
167}
168
169GrXferProcessor::OptFlags
170GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
171 const GrProcOptInfo& coveragePOI,
172 bool isCoverageDrawing,
173 bool colorWriteDisabled,
174 bool doesStencilWrite,
175 GrColor* color, uint8_t* coverage) {
egdaniel95131432014-12-09 11:15:43 -0800176 if (colorWriteDisabled) {
177 fSrcBlend = kZero_GrBlendCoeff;
178 fDstBlend = kOne_GrBlendCoeff;
179 }
180
181 bool srcAIsOne;
182 bool hasCoverage;
183 if (isCoverageDrawing) {
184 srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque();
185 hasCoverage = false;
186 } else {
187 srcAIsOne = colorPOI.isOpaque();
188 hasCoverage = !coveragePOI.isSolidWhite();
189 }
190
191 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
192 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
193 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
194 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
195
196 // Optimizations when doing RGB Coverage
197 if (coveragePOI.isFourChannelOutput()) {
198 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
199 // value of the blend the constant. We should already have valid blend coeff's if we are at
200 // a point where we have RGB coverage. We don't need any color stages since the known color
201 // output is already baked into the blendConstant.
202 uint8_t alpha = GrColorUnpackA(fBlendConstant);
203 *color = GrColorPackRGBA(alpha, alpha, alpha, alpha);
204 return GrXferProcessor::kClearColorStages_OptFlag;
205 }
206
207 // When coeffs are (0,1) there is no reason to draw at all, unless
208 // stenciling is enabled. Having color writes disabled is effectively
209 // (0,1).
210 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
211 if (doesStencilWrite) {
212 *color = 0xffffffff;
213 return GrXferProcessor::kClearColorStages_OptFlag |
214 GrXferProcessor::kSetCoverageDrawing_OptFlag;
215 } else {
216 fDstBlend = kOne_GrBlendCoeff;
217 return GrXferProcessor::kSkipDraw_OptFlag;
218 }
219 }
220
221 // if we don't have coverage we can check whether the dst
222 // has to read at all. If not, we'll disable blending.
223 if (!hasCoverage) {
224 if (dstCoeffIsZero) {
225 if (kOne_GrBlendCoeff == fSrcBlend) {
226 // if there is no coverage and coeffs are (1,0) then we
227 // won't need to read the dst at all, it gets replaced by src
228 fDstBlend = kZero_GrBlendCoeff;
229 return GrXferProcessor::kNone_Opt;
230 } else if (kZero_GrBlendCoeff == fSrcBlend) {
231 // if the op is "clear" then we don't need to emit a color
232 // or blend, just write transparent black into the dst.
233 fSrcBlend = kOne_GrBlendCoeff;
234 fDstBlend = kZero_GrBlendCoeff;
235 *color = 0;
236 *coverage = 0xff;
237 return GrXferProcessor::kClearColorStages_OptFlag |
238 GrXferProcessor::kClearCoverageStages_OptFlag;
239 }
240 }
241 } else if (isCoverageDrawing) {
242 // we have coverage but we aren't distinguishing it from alpha by request.
243 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
244 } else {
245 // check whether coverage can be safely rolled into alpha
246 // of if we can skip color computation and just emit coverage
247 if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) {
248 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
249 }
250 if (dstCoeffIsZero) {
251 if (kZero_GrBlendCoeff == fSrcBlend) {
252 // the source color is not included in the blend
253 // the dst coeff is effectively zero so blend works out to:
254 // (c)(0)D + (1-c)D = (1-c)D.
255 fDstBlend = kISA_GrBlendCoeff;
256 *color = 0xffffffff;
257 return GrXferProcessor::kClearColorStages_OptFlag |
258 GrXferProcessor::kSetCoverageDrawing_OptFlag;
259 } else if (srcAIsOne) {
260 // the dst coeff is effectively zero so blend works out to:
261 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
262 // If Sa is 1 then we can replace Sa with c
263 // and set dst coeff to 1-Sa.
264 fDstBlend = kISA_GrBlendCoeff;
265 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
266 }
267 } else if (dstCoeffIsOne) {
268 // the dst coeff is effectively one so blend works out to:
269 // cS + (c)(1)D + (1-c)D = cS + D.
270 fDstBlend = kOne_GrBlendCoeff;
271 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
272 }
273 }
274
275 return GrXferProcessor::kNone_Opt;
276}
egdanielc2304142014-12-11 13:15:13 -0800277
278bool GrPorterDuffXferProcessor::hasSecondaryOutput() const {
279 return kNone_SecondaryOutputType != fSecondaryOutputType;
280}
281
egdaniel378092f2014-12-03 10:40:13 -0800282///////////////////////////////////////////////////////////////////////////////
283
egdaniel915187b2014-12-05 12:58:28 -0800284GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800285 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800286 this->initClassID<GrPorterDuffXPFactory>();
287}
288
egdanielc016fb82014-12-03 11:41:54 -0800289GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
290 switch (mode) {
291 case SkXfermode::kClear_Mode: {
292 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
293 return SkRef(&gClearPDXPF);
294 break;
295 }
296 case SkXfermode::kSrc_Mode: {
297 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
298 return SkRef(&gSrcPDXPF);
299 break;
300 }
301 case SkXfermode::kDst_Mode: {
302 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
303 return SkRef(&gDstPDXPF);
304 break;
305 }
306 case SkXfermode::kSrcOver_Mode: {
307 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
308 return SkRef(&gSrcOverPDXPF);
309 break;
310 }
311 case SkXfermode::kDstOver_Mode: {
312 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
313 return SkRef(&gDstOverPDXPF);
314 break;
315 }
316 case SkXfermode::kSrcIn_Mode: {
317 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
318 return SkRef(&gSrcInPDXPF);
319 break;
320 }
321 case SkXfermode::kDstIn_Mode: {
322 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
323 return SkRef(&gDstInPDXPF);
324 break;
325 }
326 case SkXfermode::kSrcOut_Mode: {
327 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
328 return SkRef(&gSrcOutPDXPF);
329 break;
330 }
331 case SkXfermode::kDstOut_Mode: {
332 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
333 return SkRef(&gDstOutPDXPF);
334 break;
335 }
336 case SkXfermode::kSrcATop_Mode: {
337 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
338 return SkRef(&gSrcATopPDXPF);
339 break;
340 }
341 case SkXfermode::kDstATop_Mode: {
342 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
343 return SkRef(&gDstATopPDXPF);
344 break;
345 }
346 case SkXfermode::kXor_Mode: {
347 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
348 return SkRef(&gXorPDXPF);
349 break;
350 }
351 case SkXfermode::kPlus_Mode: {
352 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
353 return SkRef(&gPlusPDXPF);
354 break;
355 }
356 case SkXfermode::kModulate_Mode: {
357 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
358 return SkRef(&gModulatePDXPF);
359 break;
360 }
361 case SkXfermode::kScreen_Mode: {
362 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
363 return SkRef(&gScreenPDXPF);
364 break;
365 }
366 default:
367 return NULL;
368 }
369}
370
egdaniel95131432014-12-09 11:15:43 -0800371GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
372 const GrProcOptInfo& covPOI) const {
373 if (!covPOI.isFourChannelOutput()) {
374 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff);
375 } else {
376 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
377 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
378 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
379 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
380 blendConstant);
381 } else {
382 return NULL;
383 }
384 }
egdaniel378092f2014-12-03 10:40:13 -0800385}
386
387bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
388 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800389 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800390 kRGBA_GrColorComponentFlags == knownColorFlags) {
391 return true;
392 }
393 return false;
394}
395
egdaniel95131432014-12-09 11:15:43 -0800396bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
397 const GrProcOptInfo& coveragePOI,
398 bool isCoverageDrawing,
399 bool colorWriteDisabled) const {
400 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
401
402 if (colorWriteDisabled) {
403 return true;
404 }
405
406 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
407 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
408 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
409 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
410
411 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
412 return true;
413 }
414
415 // if we don't have coverage we can check whether the dst
416 // has to read at all.
417 if (isCoverageDrawing) {
418 // we have coverage but we aren't distinguishing it from alpha by request.
419 return true;
420 } else {
421 // check whether coverage can be safely rolled into alpha
422 // of if we can skip color computation and just emit coverage
423 if (this->canTweakAlphaForCoverage(isCoverageDrawing)) {
424 return true;
425 }
426 if (dstCoeffIsZero) {
427 if (kZero_GrBlendCoeff == fSrcCoeff) {
428 return true;
429 } else if (srcAIsOne) {
430 return true;
431 }
432 } else if (dstCoeffIsOne) {
433 return true;
434 }
435 }
436
437 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
438 // will readDst and PD XP's don't read dst.
439 if ((colorPOI.readsDst() || coveragePOI.readsDst()) &&
440 kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) {
441 return true;
442 }
443
444 return false;
445}
446
447bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
448 const GrProcOptInfo& coveragePOI,
449 bool isCoverageDrawing,
450 bool colorWriteDisabled) const {
451 if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) {
452 return true;
453 }
454
455 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
456 // will readDst and PD XP's don't read dst.
457 if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) {
458 return true;
459 }
460
461 if (GrBlendCoeffRefsDst(fSrcCoeff)) {
462 return true;
463 }
464
465 bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
466
467 if (!(kZero_GrBlendCoeff == fDstCoeff ||
468 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) {
469 return true;
470 }
471
472 return false;
473}
474
475bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const {
476 return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing);
477}
478
479bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
480 const GrProcOptInfo& coveragePOI,
481 GrColor* solidColor,
482 uint32_t* solidColorKnownComponents) const {
483 if (!coveragePOI.isSolidWhite()) {
484 return false;
485 }
486
487 SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
488
489 GrBlendCoeff srcCoeff = fSrcCoeff;
490 GrBlendCoeff dstCoeff = fDstCoeff;
491
492 // TODO: figure out to merge this simplify with other current optimization code paths and
493 // eventually remove from GrBlend
494 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
495 0, 0, 0);
496
497 bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff);
498 if (solidColor) {
499 if (opaque) {
500 switch (srcCoeff) {
501 case kZero_GrBlendCoeff:
502 *solidColor = 0;
503 *solidColorKnownComponents = kRGBA_GrColorComponentFlags;
504 break;
505
506 case kOne_GrBlendCoeff:
507 *solidColor = colorPOI.color();
508 *solidColorKnownComponents = colorPOI.validFlags();
509 break;
510
511 // The src coeff should never refer to the src and if it refers to dst then opaque
512 // should have been false.
513 case kSC_GrBlendCoeff:
514 case kISC_GrBlendCoeff:
515 case kDC_GrBlendCoeff:
516 case kIDC_GrBlendCoeff:
517 case kSA_GrBlendCoeff:
518 case kISA_GrBlendCoeff:
519 case kDA_GrBlendCoeff:
520 case kIDA_GrBlendCoeff:
521 default:
522 SkFAIL("srcCoeff should not refer to src or dst.");
523 break;
524
525 // TODO: update this once GrPaint actually has a const color.
526 case kConstC_GrBlendCoeff:
527 case kIConstC_GrBlendCoeff:
528 case kConstA_GrBlendCoeff:
529 case kIConstA_GrBlendCoeff:
530 *solidColorKnownComponents = 0;
531 break;
532 }
533 } else {
534 solidColorKnownComponents = 0;
535 }
536 }
537 return opaque;
538}
539
egdanielc2304142014-12-11 13:15:13 -0800540GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
541
542GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
543 GrContext*,
544 const GrDrawTargetCaps&,
545 GrTexture*[]) {
546 GrBlendCoeff src;
547 do {
548 src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
549 } while (GrBlendCoeffRefsSrc(src));
550
551 GrBlendCoeff dst;
552 do {
553 dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
554 } while (GrBlendCoeffRefsDst(dst));
555
556 return GrPorterDuffXPFactory::Create(src, dst);
557}
egdaniel95131432014-12-09 11:15:43 -0800558