blob: 320d943392898fcb4f1a6d4490841fe44567282c [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"
egdanielc2304142014-12-11 13:15:13 -080011#include "GrDrawTargetCaps.h"
egdaniel378092f2014-12-03 10:40:13 -080012#include "GrProcessor.h"
egdaniel87509242014-12-17 13:37:13 -080013#include "GrProcOptInfo.h"
egdaniel378092f2014-12-03 10:40:13 -080014#include "GrTypes.h"
15#include "GrXferProcessor.h"
egdanielc2304142014-12-11 13:15:13 -080016#include "gl/GrGLXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080017#include "gl/builders/GrGLFragmentShaderBuilder.h"
18#include "gl/builders/GrGLProgramBuilder.h"
19
egdaniel87509242014-12-17 13:37:13 -080020static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
egdaniel95131432014-12-09 11:15:43 -080021 /*
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 source 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 possibilities for Cd we
28 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
egdaniel95131432014-12-09 11:15:43 -080029 */
egdaniel95131432014-12-09 11:15:43 -080030 return kOne_GrBlendCoeff == dstCoeff ||
31 kISA_GrBlendCoeff == dstCoeff ||
egdaniel87509242014-12-17 13:37:13 -080032 kISC_GrBlendCoeff == dstCoeff;
egdaniel95131432014-12-09 11:15:43 -080033}
34
egdaniel378092f2014-12-03 10:40:13 -080035class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
36public:
joshualitteb2a6762014-12-04 11:35:33 -080037 GrGLPorterDuffXferProcessor(const GrProcessor&) {}
egdaniel378092f2014-12-03 10:40:13 -080038
39 virtual ~GrGLPorterDuffXferProcessor() {}
40
bsalomon50785a32015-02-06 07:02:37 -080041 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
42 GrProcessorKeyBuilder* b) {
43 const GrPorterDuffXferProcessor& xp = processor.cast<GrPorterDuffXferProcessor>();
44 b->add32(xp.primaryOutputType());
45 b->add32(xp.secondaryOutputType());
46 };
47
48private:
49 void onEmitCode(const EmitArgs& args) SK_OVERRIDE {
egdanielc2304142014-12-11 13:15:13 -080050 const GrPorterDuffXferProcessor& xp = args.fXP.cast<GrPorterDuffXferProcessor>();
51 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
52 if (xp.hasSecondaryOutput()) {
53 switch(xp.secondaryOutputType()) {
54 case GrPorterDuffXferProcessor::kCoverage_SecondaryOutputType:
55 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
56 break;
57 case GrPorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
58 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
59 args.fOutputSecondary, args.fInputColor,
60 args.fInputCoverage);
61 break;
62 case GrPorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
63 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
64 args.fOutputSecondary, args.fInputColor,
65 args.fInputCoverage);
66 break;
67 default:
68 SkFAIL("Unexpected Secondary Output");
69 }
70 }
71
joshualitt9b989322014-12-15 14:16:27 -080072 switch (xp.primaryOutputType()) {
73 case GrPorterDuffXferProcessor::kNone_PrimaryOutputType:
74 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
75 break;
76 case GrPorterDuffXferProcessor::kColor_PrimaryOutputType:
77 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
78 break;
79 case GrPorterDuffXferProcessor::kCoverage_PrimaryOutputType:
80 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
81 break;
82 case GrPorterDuffXferProcessor::kModulate_PrimaryOutputType:
joshualitt9b989322014-12-15 14:16:27 -080083 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
84 args.fInputCoverage);
joshualitt9b989322014-12-15 14:16:27 -080085 break;
86 default:
87 SkFAIL("Unexpected Primary Output");
egdanielc2304142014-12-11 13:15:13 -080088 }
egdaniel378092f2014-12-03 10:40:13 -080089 }
90
bsalomon50785a32015-02-06 07:02:37 -080091 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
egdaniel378092f2014-12-03 10:40:13 -080092
egdaniel378092f2014-12-03 10:40:13 -080093 typedef GrGLXferProcessor INHERITED;
94};
95
96///////////////////////////////////////////////////////////////////////////////
97
bsalomon50785a32015-02-06 07:02:37 -080098GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend,
99 GrBlendCoeff dstBlend,
100 GrColor constant,
101 const GrDeviceCoordTexture* dstCopy,
102 bool willReadDstColor)
egdanielc2304142014-12-11 13:15:13 -0800103 : fSrcBlend(srcBlend)
104 , fDstBlend(dstBlend)
105 , fBlendConstant(constant)
106 , fPrimaryOutputType(kModulate_PrimaryOutputType)
107 , fSecondaryOutputType(kNone_SecondaryOutputType) {
joshualitteb2a6762014-12-04 11:35:33 -0800108 this->initClassID<GrPorterDuffXferProcessor>();
109}
egdaniel378092f2014-12-03 10:40:13 -0800110
111GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() {
112}
113
bsalomon50785a32015-02-06 07:02:37 -0800114void GrPorterDuffXferProcessor::onGetGLProcessorKey(const GrGLCaps& caps,
115 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800116 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b);
117}
118
egdanielc2304142014-12-11 13:15:13 -0800119GrGLXferProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800120 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -0800121}
122
egdaniel95131432014-12-09 11:15:43 -0800123GrXferProcessor::OptFlags
124GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
125 const GrProcOptInfo& coveragePOI,
egdaniel95131432014-12-09 11:15:43 -0800126 bool doesStencilWrite,
egdaniel54160f32014-12-15 12:38:53 -0800127 GrColor* overrideColor,
egdanielc2304142014-12-11 13:15:13 -0800128 const GrDrawTargetCaps& caps) {
egdaniel54160f32014-12-15 12:38:53 -0800129 GrXferProcessor::OptFlags optFlags;
130 // Optimizations when doing RGB Coverage
131 if (coveragePOI.isFourChannelOutput()) {
132 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
133 // value of the blend the constant. We should already have valid blend coeff's if we are at
134 // a point where we have RGB coverage. We don't need any color stages since the known color
135 // output is already baked into the blendConstant.
136 uint8_t alpha = GrColorUnpackA(fBlendConstant);
137 *overrideColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
138 optFlags = GrXferProcessor::kOverrideColor_OptFlag;
139 } else {
140 optFlags = this->internalGetOptimizations(colorPOI,
141 coveragePOI,
joshualitt9b989322014-12-15 14:16:27 -0800142 doesStencilWrite);
egdaniel54160f32014-12-15 12:38:53 -0800143 }
egdaniel71e236c2015-01-20 06:34:51 -0800144 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
egdanielc2304142014-12-11 13:15:13 -0800145 return optFlags;
146}
147
148void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
149 const GrDrawTargetCaps& caps,
egdaniel71e236c2015-01-20 06:34:51 -0800150 bool hasSolidCoverage) {
joshualitt9b989322014-12-15 14:16:27 -0800151 if (optFlags & kIgnoreColor_OptFlag) {
152 if (optFlags & kIgnoreCoverage_OptFlag) {
153 fPrimaryOutputType = kNone_PrimaryOutputType;
154 return;
155 } else {
156 fPrimaryOutputType = kCoverage_PrimaryOutputType;
157 return;
158 }
159 } else if (optFlags & kIgnoreCoverage_OptFlag) {
160 fPrimaryOutputType = kColor_PrimaryOutputType;
161 return;
162 }
163
egdanielc2304142014-12-11 13:15:13 -0800164 // If we do have coverage determine whether it matters. Dual source blending is expensive so
165 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
166 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
167 // solid coverage.
168 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
169 if (caps.dualSourceBlendingSupport()) {
170 if (kZero_GrBlendCoeff == fDstBlend) {
171 // write the coverage value to second color
172 fSecondaryOutputType = kCoverage_SecondaryOutputType;
173 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
174 } else if (kSA_GrBlendCoeff == fDstBlend) {
175 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
176 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
177 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
178 } else if (kSC_GrBlendCoeff == fDstBlend) {
179 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
180 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
181 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
182 }
egdanielc2304142014-12-11 13:15:13 -0800183 }
184 }
185}
186
187GrXferProcessor::OptFlags
188GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
189 const GrProcOptInfo& coveragePOI,
joshualitt9b989322014-12-15 14:16:27 -0800190 bool doesStencilWrite) {
egdaniel95131432014-12-09 11:15:43 -0800191 bool srcAIsOne;
192 bool hasCoverage;
egdaniel87509242014-12-17 13:37:13 -0800193
194 srcAIsOne = colorPOI.isOpaque();
195 hasCoverage = !coveragePOI.isSolidWhite();
egdaniel95131432014-12-09 11:15:43 -0800196
197 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
198 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
199 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
200 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
201
egdaniel95131432014-12-09 11:15:43 -0800202 // When coeffs are (0,1) there is no reason to draw at all, unless
203 // stenciling is enabled. Having color writes disabled is effectively
204 // (0,1).
205 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
206 if (doesStencilWrite) {
joshualitt9b989322014-12-15 14:16:27 -0800207 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800208 GrXferProcessor::kSetCoverageDrawing_OptFlag;
209 } else {
210 fDstBlend = kOne_GrBlendCoeff;
211 return GrXferProcessor::kSkipDraw_OptFlag;
212 }
213 }
214
215 // if we don't have coverage we can check whether the dst
216 // has to read at all. If not, we'll disable blending.
217 if (!hasCoverage) {
218 if (dstCoeffIsZero) {
219 if (kOne_GrBlendCoeff == fSrcBlend) {
220 // if there is no coverage and coeffs are (1,0) then we
221 // won't need to read the dst at all, it gets replaced by src
222 fDstBlend = kZero_GrBlendCoeff;
223 return GrXferProcessor::kNone_Opt;
224 } else if (kZero_GrBlendCoeff == fSrcBlend) {
225 // if the op is "clear" then we don't need to emit a color
226 // or blend, just write transparent black into the dst.
227 fSrcBlend = kOne_GrBlendCoeff;
228 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800229 return GrXferProcessor::kIgnoreColor_OptFlag |
230 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800231 }
232 }
egdaniel87509242014-12-17 13:37:13 -0800233 } else {
egdaniel95131432014-12-09 11:15:43 -0800234 // check whether coverage can be safely rolled into alpha
235 // of if we can skip color computation and just emit coverage
egdaniel87509242014-12-17 13:37:13 -0800236 if (can_tweak_alpha_for_coverage(fDstBlend)) {
egdaniel95131432014-12-09 11:15:43 -0800237 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
238 }
239 if (dstCoeffIsZero) {
240 if (kZero_GrBlendCoeff == fSrcBlend) {
241 // the source color is not included in the blend
242 // the dst coeff is effectively zero so blend works out to:
243 // (c)(0)D + (1-c)D = (1-c)D.
244 fDstBlend = kISA_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800245 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800246 GrXferProcessor::kSetCoverageDrawing_OptFlag;
247 } else if (srcAIsOne) {
248 // the dst coeff is effectively zero so blend works out to:
249 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
250 // If Sa is 1 then we can replace Sa with c
251 // and set dst coeff to 1-Sa.
252 fDstBlend = kISA_GrBlendCoeff;
253 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
254 }
255 } else if (dstCoeffIsOne) {
256 // the dst coeff is effectively one so blend works out to:
257 // cS + (c)(1)D + (1-c)D = cS + D.
258 fDstBlend = kOne_GrBlendCoeff;
259 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
260 }
261 }
262
263 return GrXferProcessor::kNone_Opt;
264}
egdanielc2304142014-12-11 13:15:13 -0800265
266bool GrPorterDuffXferProcessor::hasSecondaryOutput() const {
267 return kNone_SecondaryOutputType != fSecondaryOutputType;
268}
269
egdaniel378092f2014-12-03 10:40:13 -0800270///////////////////////////////////////////////////////////////////////////////
271
egdaniel915187b2014-12-05 12:58:28 -0800272GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800273 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800274 this->initClassID<GrPorterDuffXPFactory>();
275}
276
egdanielc016fb82014-12-03 11:41:54 -0800277GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
278 switch (mode) {
279 case SkXfermode::kClear_Mode: {
280 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
281 return SkRef(&gClearPDXPF);
282 break;
283 }
284 case SkXfermode::kSrc_Mode: {
285 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
286 return SkRef(&gSrcPDXPF);
287 break;
288 }
289 case SkXfermode::kDst_Mode: {
290 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
291 return SkRef(&gDstPDXPF);
292 break;
293 }
294 case SkXfermode::kSrcOver_Mode: {
295 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
296 return SkRef(&gSrcOverPDXPF);
297 break;
298 }
299 case SkXfermode::kDstOver_Mode: {
300 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
301 return SkRef(&gDstOverPDXPF);
302 break;
303 }
304 case SkXfermode::kSrcIn_Mode: {
305 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
306 return SkRef(&gSrcInPDXPF);
307 break;
308 }
309 case SkXfermode::kDstIn_Mode: {
310 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
311 return SkRef(&gDstInPDXPF);
312 break;
313 }
314 case SkXfermode::kSrcOut_Mode: {
315 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
316 return SkRef(&gSrcOutPDXPF);
317 break;
318 }
319 case SkXfermode::kDstOut_Mode: {
320 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
321 return SkRef(&gDstOutPDXPF);
322 break;
323 }
324 case SkXfermode::kSrcATop_Mode: {
325 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
326 return SkRef(&gSrcATopPDXPF);
327 break;
328 }
329 case SkXfermode::kDstATop_Mode: {
330 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
331 return SkRef(&gDstATopPDXPF);
332 break;
333 }
334 case SkXfermode::kXor_Mode: {
335 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
336 return SkRef(&gXorPDXPF);
337 break;
338 }
339 case SkXfermode::kPlus_Mode: {
340 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
341 return SkRef(&gPlusPDXPF);
342 break;
343 }
344 case SkXfermode::kModulate_Mode: {
345 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
346 return SkRef(&gModulatePDXPF);
347 break;
348 }
349 case SkXfermode::kScreen_Mode: {
350 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
351 return SkRef(&gScreenPDXPF);
352 break;
353 }
354 default:
355 return NULL;
356 }
357}
358
bsalomon50785a32015-02-06 07:02:37 -0800359GrXferProcessor*
360GrPorterDuffXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI,
361 const GrProcOptInfo& covPOI,
362 const GrDeviceCoordTexture* dstCopy) const {
egdaniel95131432014-12-09 11:15:43 -0800363 if (!covPOI.isFourChannelOutput()) {
bsalomon50785a32015-02-06 07:02:37 -0800364 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
365 this->willReadDstColor());
egdaniel95131432014-12-09 11:15:43 -0800366 } else {
367 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
368 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
369 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
370 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
bsalomon50785a32015-02-06 07:02:37 -0800371 blendConstant, dstCopy,
372 this->willReadDstColor());
egdaniel95131432014-12-09 11:15:43 -0800373 } else {
374 return NULL;
375 }
376 }
egdaniel378092f2014-12-03 10:40:13 -0800377}
378
379bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
380 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800381 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800382 kRGBA_GrColorComponentFlags == knownColorFlags) {
383 return true;
384 }
385 return false;
386}
387
egdaniel95131432014-12-09 11:15:43 -0800388bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
egdaniel080e6732014-12-22 07:35:52 -0800389 const GrProcOptInfo& coveragePOI) const {
egdaniel87509242014-12-17 13:37:13 -0800390 bool srcAIsOne = colorPOI.isOpaque();
egdaniel95131432014-12-09 11:15:43 -0800391
egdaniel95131432014-12-09 11:15:43 -0800392 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
393 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
394 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
395 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
396
397 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
398 return true;
399 }
400
401 // if we don't have coverage we can check whether the dst
402 // has to read at all.
egdaniel87509242014-12-17 13:37:13 -0800403 // check whether coverage can be safely rolled into alpha
404 // of if we can skip color computation and just emit coverage
405 if (this->canTweakAlphaForCoverage()) {
egdaniel95131432014-12-09 11:15:43 -0800406 return true;
egdaniel87509242014-12-17 13:37:13 -0800407 }
408 if (dstCoeffIsZero) {
409 if (kZero_GrBlendCoeff == fSrcCoeff) {
egdaniel95131432014-12-09 11:15:43 -0800410 return true;
egdaniel87509242014-12-17 13:37:13 -0800411 } else if (srcAIsOne) {
412 return true;
egdaniel95131432014-12-09 11:15:43 -0800413 }
egdaniel87509242014-12-17 13:37:13 -0800414 } else if (dstCoeffIsOne) {
415 return true;
egdaniel95131432014-12-09 11:15:43 -0800416 }
417
egdaniel95131432014-12-09 11:15:43 -0800418 return false;
419}
420
egdaniel87509242014-12-17 13:37:13 -0800421bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const {
422 return can_tweak_alpha_for_coverage(fDstCoeff);
egdaniel95131432014-12-09 11:15:43 -0800423}
424
egdaniel9e4ecdc2014-12-18 12:44:55 -0800425void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
426 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800427 GrXPFactory::InvariantOutput* output) const {
egdaniel95131432014-12-09 11:15:43 -0800428 if (!coveragePOI.isSolidWhite()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800429 output->fWillBlendWithDst = true;
430 output->fBlendedColorFlags = 0;
431 return;
egdaniel95131432014-12-09 11:15:43 -0800432 }
433
egdaniel95131432014-12-09 11:15:43 -0800434 GrBlendCoeff srcCoeff = fSrcCoeff;
435 GrBlendCoeff dstCoeff = fDstCoeff;
436
437 // TODO: figure out to merge this simplify with other current optimization code paths and
438 // eventually remove from GrBlend
439 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
440 0, 0, 0);
441
egdaniel9e4ecdc2014-12-18 12:44:55 -0800442 if (GrBlendCoeffRefsDst(srcCoeff)) {
443 output->fWillBlendWithDst = true;
444 output->fBlendedColorFlags = 0;
445 return;
egdaniel95131432014-12-09 11:15:43 -0800446 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800447
448 if (kZero_GrBlendCoeff != dstCoeff) {
449 bool srcAIsOne = colorPOI.isOpaque();
450 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
451 output->fWillBlendWithDst = true;
452 }
453 output->fBlendedColorFlags = 0;
454 return;
455 }
456
457 switch (srcCoeff) {
458 case kZero_GrBlendCoeff:
459 output->fBlendedColor = 0;
460 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
461 break;
462
463 case kOne_GrBlendCoeff:
464 output->fBlendedColor = colorPOI.color();
465 output->fBlendedColorFlags = colorPOI.validFlags();
466 break;
467
468 // The src coeff should never refer to the src and if it refers to dst then opaque
469 // should have been false.
470 case kSC_GrBlendCoeff:
471 case kISC_GrBlendCoeff:
472 case kDC_GrBlendCoeff:
473 case kIDC_GrBlendCoeff:
474 case kSA_GrBlendCoeff:
475 case kISA_GrBlendCoeff:
476 case kDA_GrBlendCoeff:
477 case kIDA_GrBlendCoeff:
478 default:
479 SkFAIL("srcCoeff should not refer to src or dst.");
480 break;
481
482 // TODO: update this once GrPaint actually has a const color.
483 case kConstC_GrBlendCoeff:
484 case kIConstC_GrBlendCoeff:
485 case kConstA_GrBlendCoeff:
486 case kIConstA_GrBlendCoeff:
487 output->fBlendedColorFlags = 0;
488 break;
489 }
490
egdaniel9e4ecdc2014-12-18 12:44:55 -0800491 output->fWillBlendWithDst = false;
egdaniel95131432014-12-09 11:15:43 -0800492}
493
bsalomon50785a32015-02-06 07:02:37 -0800494bool GrPorterDuffXPFactory::willReadDstColor() const {
495 return false;
496}
497
egdanielc2304142014-12-11 13:15:13 -0800498GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
499
500GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
501 GrContext*,
502 const GrDrawTargetCaps&,
503 GrTexture*[]) {
504 GrBlendCoeff src;
505 do {
506 src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
507 } while (GrBlendCoeffRefsSrc(src));
508
509 GrBlendCoeff dst;
510 do {
511 dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
512 } while (GrBlendCoeffRefsDst(dst));
513
514 return GrPorterDuffXPFactory::Create(src, dst);
515}
egdaniel95131432014-12-09 11:15:43 -0800516