blob: a091a48b08e21faf3dc94e524f93163fd0508939 [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 "GrInvariantOutput.h"
13#include "GrProcessor.h"
egdaniel87509242014-12-17 13:37:13 -080014#include "GrProcOptInfo.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
egdaniel87509242014-12-17 13:37:13 -080021static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
egdaniel95131432014-12-09 11:15:43 -080022 /*
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.
egdaniel95131432014-12-09 11:15:43 -080030 */
egdaniel95131432014-12-09 11:15:43 -080031 return kOne_GrBlendCoeff == dstCoeff ||
32 kISA_GrBlendCoeff == dstCoeff ||
egdaniel87509242014-12-17 13:37:13 -080033 kISC_GrBlendCoeff == dstCoeff;
egdaniel95131432014-12-09 11:15:43 -080034}
35
egdaniel378092f2014-12-03 10:40:13 -080036class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
37public:
joshualitteb2a6762014-12-04 11:35:33 -080038 GrGLPorterDuffXferProcessor(const GrProcessor&) {}
egdaniel378092f2014-12-03 10:40:13 -080039
40 virtual ~GrGLPorterDuffXferProcessor() {}
41
egdanielc2304142014-12-11 13:15:13 -080042 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
43 const GrPorterDuffXferProcessor& xp = args.fXP.cast<GrPorterDuffXferProcessor>();
44 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
45 if (xp.hasSecondaryOutput()) {
46 switch(xp.secondaryOutputType()) {
47 case GrPorterDuffXferProcessor::kCoverage_SecondaryOutputType:
48 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
49 break;
50 case GrPorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
51 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
52 args.fOutputSecondary, args.fInputColor,
53 args.fInputCoverage);
54 break;
55 case GrPorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
56 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
57 args.fOutputSecondary, args.fInputColor,
58 args.fInputCoverage);
59 break;
60 default:
61 SkFAIL("Unexpected Secondary Output");
62 }
63 }
64
joshualitt9b989322014-12-15 14:16:27 -080065 switch (xp.primaryOutputType()) {
66 case GrPorterDuffXferProcessor::kNone_PrimaryOutputType:
67 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
68 break;
69 case GrPorterDuffXferProcessor::kColor_PrimaryOutputType:
70 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
71 break;
72 case GrPorterDuffXferProcessor::kCoverage_PrimaryOutputType:
73 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
74 break;
75 case GrPorterDuffXferProcessor::kModulate_PrimaryOutputType:
76 case GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType:
77 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
78 args.fInputCoverage);
79 if (GrPorterDuffXferProcessor::kCombineWithDst_PrimaryOutputType ==
80 xp.primaryOutputType()){
81 fsBuilder->codeAppendf("%s += (vec4(1.0) - %s) * %s;", args.fOutputPrimary,
82 args.fInputCoverage, fsBuilder->dstColor());
83 }
84 break;
85 default:
86 SkFAIL("Unexpected Primary Output");
egdanielc2304142014-12-11 13:15:13 -080087 }
egdaniel378092f2014-12-03 10:40:13 -080088 }
89
egdanielc2304142014-12-11 13:15:13 -080090 virtual void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
egdaniel378092f2014-12-03 10:40:13 -080091
egdanielc2304142014-12-11 13:15:13 -080092 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
93 GrProcessorKeyBuilder* b) {
94 const GrPorterDuffXferProcessor& xp = processor.cast<GrPorterDuffXferProcessor>();
95 b->add32(xp.primaryOutputType());
96 b->add32(xp.secondaryOutputType());
97 };
egdaniel378092f2014-12-03 10:40:13 -080098
99private:
100 typedef GrGLXferProcessor INHERITED;
101};
102
103///////////////////////////////////////////////////////////////////////////////
104
egdaniel95131432014-12-09 11:15:43 -0800105GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
106 GrColor constant)
egdanielc2304142014-12-11 13:15:13 -0800107 : fSrcBlend(srcBlend)
108 , fDstBlend(dstBlend)
109 , fBlendConstant(constant)
110 , fPrimaryOutputType(kModulate_PrimaryOutputType)
111 , fSecondaryOutputType(kNone_SecondaryOutputType) {
joshualitteb2a6762014-12-04 11:35:33 -0800112 this->initClassID<GrPorterDuffXferProcessor>();
113}
egdaniel378092f2014-12-03 10:40:13 -0800114
115GrPorterDuffXferProcessor::~GrPorterDuffXferProcessor() {
116}
117
joshualitteb2a6762014-12-04 11:35:33 -0800118void GrPorterDuffXferProcessor::getGLProcessorKey(const GrGLCaps& caps,
119 GrProcessorKeyBuilder* b) const {
120 GrGLPorterDuffXferProcessor::GenKey(*this, caps, b);
121}
122
egdanielc2304142014-12-11 13:15:13 -0800123GrGLXferProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
joshualitteb2a6762014-12-04 11:35:33 -0800124 return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -0800125}
126
egdaniel95131432014-12-09 11:15:43 -0800127GrXferProcessor::OptFlags
128GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
129 const GrProcOptInfo& coveragePOI,
egdaniel95131432014-12-09 11:15:43 -0800130 bool colorWriteDisabled,
131 bool doesStencilWrite,
egdaniel54160f32014-12-15 12:38:53 -0800132 GrColor* overrideColor,
egdanielc2304142014-12-11 13:15:13 -0800133 const GrDrawTargetCaps& caps) {
egdaniel54160f32014-12-15 12:38:53 -0800134 GrXferProcessor::OptFlags optFlags;
135 // Optimizations when doing RGB Coverage
136 if (coveragePOI.isFourChannelOutput()) {
137 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
138 // value of the blend the constant. We should already have valid blend coeff's if we are at
139 // a point where we have RGB coverage. We don't need any color stages since the known color
140 // output is already baked into the blendConstant.
141 uint8_t alpha = GrColorUnpackA(fBlendConstant);
142 *overrideColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
143 optFlags = GrXferProcessor::kOverrideColor_OptFlag;
144 } else {
145 optFlags = this->internalGetOptimizations(colorPOI,
146 coveragePOI,
egdaniel54160f32014-12-15 12:38:53 -0800147 colorWriteDisabled,
joshualitt9b989322014-12-15 14:16:27 -0800148 doesStencilWrite);
egdaniel54160f32014-12-15 12:38:53 -0800149 }
egdaniel87509242014-12-17 13:37:13 -0800150 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite(),
egdanielc2304142014-12-11 13:15:13 -0800151 colorPOI.readsDst() || coveragePOI.readsDst());
152 return optFlags;
153}
154
155void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
156 const GrDrawTargetCaps& caps,
157 bool hasSolidCoverage, bool readsDst) {
joshualitt9b989322014-12-15 14:16:27 -0800158 if (optFlags & kIgnoreColor_OptFlag) {
159 if (optFlags & kIgnoreCoverage_OptFlag) {
160 fPrimaryOutputType = kNone_PrimaryOutputType;
161 return;
162 } else {
163 fPrimaryOutputType = kCoverage_PrimaryOutputType;
164 return;
165 }
166 } else if (optFlags & kIgnoreCoverage_OptFlag) {
167 fPrimaryOutputType = kColor_PrimaryOutputType;
168 return;
169 }
170
egdanielc2304142014-12-11 13:15:13 -0800171 // If we do have coverage determine whether it matters. Dual source blending is expensive so
172 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
173 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
174 // solid coverage.
175 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
176 if (caps.dualSourceBlendingSupport()) {
177 if (kZero_GrBlendCoeff == fDstBlend) {
178 // write the coverage value to second color
179 fSecondaryOutputType = kCoverage_SecondaryOutputType;
180 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
181 } else if (kSA_GrBlendCoeff == fDstBlend) {
182 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
183 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
184 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
185 } else if (kSC_GrBlendCoeff == fDstBlend) {
186 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
187 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
188 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
189 }
190 } else if (readsDst &&
191 kOne_GrBlendCoeff == fSrcBlend &&
192 kZero_GrBlendCoeff == fDstBlend) {
193 fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
194 }
195 }
196}
197
198GrXferProcessor::OptFlags
199GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
200 const GrProcOptInfo& coveragePOI,
egdanielc2304142014-12-11 13:15:13 -0800201 bool colorWriteDisabled,
joshualitt9b989322014-12-15 14:16:27 -0800202 bool doesStencilWrite) {
egdaniel95131432014-12-09 11:15:43 -0800203 if (colorWriteDisabled) {
204 fSrcBlend = kZero_GrBlendCoeff;
205 fDstBlend = kOne_GrBlendCoeff;
206 }
207
208 bool srcAIsOne;
209 bool hasCoverage;
egdaniel87509242014-12-17 13:37:13 -0800210
211 srcAIsOne = colorPOI.isOpaque();
212 hasCoverage = !coveragePOI.isSolidWhite();
egdaniel95131432014-12-09 11:15:43 -0800213
214 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
215 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
216 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
217 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
218
egdaniel95131432014-12-09 11:15:43 -0800219 // When coeffs are (0,1) there is no reason to draw at all, unless
220 // stenciling is enabled. Having color writes disabled is effectively
221 // (0,1).
222 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
223 if (doesStencilWrite) {
joshualitt9b989322014-12-15 14:16:27 -0800224 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800225 GrXferProcessor::kSetCoverageDrawing_OptFlag;
226 } else {
227 fDstBlend = kOne_GrBlendCoeff;
228 return GrXferProcessor::kSkipDraw_OptFlag;
229 }
230 }
231
232 // if we don't have coverage we can check whether the dst
233 // has to read at all. If not, we'll disable blending.
234 if (!hasCoverage) {
235 if (dstCoeffIsZero) {
236 if (kOne_GrBlendCoeff == fSrcBlend) {
237 // if there is no coverage and coeffs are (1,0) then we
238 // won't need to read the dst at all, it gets replaced by src
239 fDstBlend = kZero_GrBlendCoeff;
240 return GrXferProcessor::kNone_Opt;
241 } else if (kZero_GrBlendCoeff == fSrcBlend) {
242 // if the op is "clear" then we don't need to emit a color
243 // or blend, just write transparent black into the dst.
244 fSrcBlend = kOne_GrBlendCoeff;
245 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800246 return GrXferProcessor::kIgnoreColor_OptFlag |
247 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800248 }
249 }
egdaniel87509242014-12-17 13:37:13 -0800250 } else {
egdaniel95131432014-12-09 11:15:43 -0800251 // check whether coverage can be safely rolled into alpha
252 // of if we can skip color computation and just emit coverage
egdaniel87509242014-12-17 13:37:13 -0800253 if (can_tweak_alpha_for_coverage(fDstBlend)) {
egdaniel95131432014-12-09 11:15:43 -0800254 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
255 }
256 if (dstCoeffIsZero) {
257 if (kZero_GrBlendCoeff == fSrcBlend) {
258 // the source color is not included in the blend
259 // the dst coeff is effectively zero so blend works out to:
260 // (c)(0)D + (1-c)D = (1-c)D.
261 fDstBlend = kISA_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800262 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800263 GrXferProcessor::kSetCoverageDrawing_OptFlag;
264 } else if (srcAIsOne) {
265 // the dst coeff is effectively zero so blend works out to:
266 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
267 // If Sa is 1 then we can replace Sa with c
268 // and set dst coeff to 1-Sa.
269 fDstBlend = kISA_GrBlendCoeff;
270 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
271 }
272 } else if (dstCoeffIsOne) {
273 // the dst coeff is effectively one so blend works out to:
274 // cS + (c)(1)D + (1-c)D = cS + D.
275 fDstBlend = kOne_GrBlendCoeff;
276 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
277 }
278 }
279
280 return GrXferProcessor::kNone_Opt;
281}
egdanielc2304142014-12-11 13:15:13 -0800282
283bool GrPorterDuffXferProcessor::hasSecondaryOutput() const {
284 return kNone_SecondaryOutputType != fSecondaryOutputType;
285}
286
egdaniel378092f2014-12-03 10:40:13 -0800287///////////////////////////////////////////////////////////////////////////////
288
egdaniel915187b2014-12-05 12:58:28 -0800289GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800290 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800291 this->initClassID<GrPorterDuffXPFactory>();
292}
293
egdanielc016fb82014-12-03 11:41:54 -0800294GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
295 switch (mode) {
296 case SkXfermode::kClear_Mode: {
297 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
298 return SkRef(&gClearPDXPF);
299 break;
300 }
301 case SkXfermode::kSrc_Mode: {
302 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
303 return SkRef(&gSrcPDXPF);
304 break;
305 }
306 case SkXfermode::kDst_Mode: {
307 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
308 return SkRef(&gDstPDXPF);
309 break;
310 }
311 case SkXfermode::kSrcOver_Mode: {
312 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
313 return SkRef(&gSrcOverPDXPF);
314 break;
315 }
316 case SkXfermode::kDstOver_Mode: {
317 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
318 return SkRef(&gDstOverPDXPF);
319 break;
320 }
321 case SkXfermode::kSrcIn_Mode: {
322 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
323 return SkRef(&gSrcInPDXPF);
324 break;
325 }
326 case SkXfermode::kDstIn_Mode: {
327 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
328 return SkRef(&gDstInPDXPF);
329 break;
330 }
331 case SkXfermode::kSrcOut_Mode: {
332 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
333 return SkRef(&gSrcOutPDXPF);
334 break;
335 }
336 case SkXfermode::kDstOut_Mode: {
337 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
338 return SkRef(&gDstOutPDXPF);
339 break;
340 }
341 case SkXfermode::kSrcATop_Mode: {
342 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
343 return SkRef(&gSrcATopPDXPF);
344 break;
345 }
346 case SkXfermode::kDstATop_Mode: {
347 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
348 return SkRef(&gDstATopPDXPF);
349 break;
350 }
351 case SkXfermode::kXor_Mode: {
352 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
353 return SkRef(&gXorPDXPF);
354 break;
355 }
356 case SkXfermode::kPlus_Mode: {
357 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
358 return SkRef(&gPlusPDXPF);
359 break;
360 }
361 case SkXfermode::kModulate_Mode: {
362 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
363 return SkRef(&gModulatePDXPF);
364 break;
365 }
366 case SkXfermode::kScreen_Mode: {
367 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
368 return SkRef(&gScreenPDXPF);
369 break;
370 }
371 default:
372 return NULL;
373 }
374}
375
egdaniel95131432014-12-09 11:15:43 -0800376GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
377 const GrProcOptInfo& covPOI) const {
378 if (!covPOI.isFourChannelOutput()) {
379 return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff);
380 } else {
381 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
382 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
383 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
384 return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
385 blendConstant);
386 } else {
387 return NULL;
388 }
389 }
egdaniel378092f2014-12-03 10:40:13 -0800390}
391
392bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
393 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800394 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800395 kRGBA_GrColorComponentFlags == knownColorFlags) {
396 return true;
397 }
398 return false;
399}
400
egdaniel95131432014-12-09 11:15:43 -0800401bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
402 const GrProcOptInfo& coveragePOI,
egdaniel95131432014-12-09 11:15:43 -0800403 bool colorWriteDisabled) const {
egdaniel87509242014-12-17 13:37:13 -0800404 bool srcAIsOne = colorPOI.isOpaque();
egdaniel95131432014-12-09 11:15:43 -0800405
406 if (colorWriteDisabled) {
407 return true;
408 }
409
410 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
411 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
412 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
413 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
414
415 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
416 return true;
417 }
418
419 // if we don't have coverage we can check whether the dst
420 // has to read at all.
egdaniel87509242014-12-17 13:37:13 -0800421 // 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()) {
egdaniel95131432014-12-09 11:15:43 -0800424 return true;
egdaniel87509242014-12-17 13:37:13 -0800425 }
426 if (dstCoeffIsZero) {
427 if (kZero_GrBlendCoeff == fSrcCoeff) {
egdaniel95131432014-12-09 11:15:43 -0800428 return true;
egdaniel87509242014-12-17 13:37:13 -0800429 } else if (srcAIsOne) {
430 return true;
egdaniel95131432014-12-09 11:15:43 -0800431 }
egdaniel87509242014-12-17 13:37:13 -0800432 } else if (dstCoeffIsOne) {
433 return true;
egdaniel95131432014-12-09 11:15:43 -0800434 }
435
436 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
437 // will readDst and PD XP's don't read dst.
438 if ((colorPOI.readsDst() || coveragePOI.readsDst()) &&
439 kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) {
440 return true;
441 }
442
443 return false;
444}
445
446bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
447 const GrProcOptInfo& coveragePOI,
egdaniel95131432014-12-09 11:15:43 -0800448 bool colorWriteDisabled) const {
egdaniel87509242014-12-17 13:37:13 -0800449 if (!coveragePOI.isSolidWhite()) {
egdaniel95131432014-12-09 11:15:43 -0800450 return true;
451 }
452
453 // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
454 // will readDst and PD XP's don't read dst.
455 if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) {
456 return true;
457 }
458
459 if (GrBlendCoeffRefsDst(fSrcCoeff)) {
460 return true;
461 }
462
egdaniel87509242014-12-17 13:37:13 -0800463 bool srcAIsOne = colorPOI.isOpaque();
egdaniel95131432014-12-09 11:15:43 -0800464
465 if (!(kZero_GrBlendCoeff == fDstCoeff ||
466 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) {
467 return true;
468 }
469
470 return false;
471}
472
egdaniel87509242014-12-17 13:37:13 -0800473bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const {
474 return can_tweak_alpha_for_coverage(fDstCoeff);
egdaniel95131432014-12-09 11:15:43 -0800475}
476
477bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
478 const GrProcOptInfo& coveragePOI,
479 GrColor* solidColor,
480 uint32_t* solidColorKnownComponents) const {
481 if (!coveragePOI.isSolidWhite()) {
482 return false;
483 }
484
485 SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
486
487 GrBlendCoeff srcCoeff = fSrcCoeff;
488 GrBlendCoeff dstCoeff = fDstCoeff;
489
490 // TODO: figure out to merge this simplify with other current optimization code paths and
491 // eventually remove from GrBlend
492 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
493 0, 0, 0);
494
495 bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff);
496 if (solidColor) {
497 if (opaque) {
498 switch (srcCoeff) {
499 case kZero_GrBlendCoeff:
500 *solidColor = 0;
501 *solidColorKnownComponents = kRGBA_GrColorComponentFlags;
502 break;
503
504 case kOne_GrBlendCoeff:
505 *solidColor = colorPOI.color();
506 *solidColorKnownComponents = colorPOI.validFlags();
507 break;
508
509 // The src coeff should never refer to the src and if it refers to dst then opaque
510 // should have been false.
511 case kSC_GrBlendCoeff:
512 case kISC_GrBlendCoeff:
513 case kDC_GrBlendCoeff:
514 case kIDC_GrBlendCoeff:
515 case kSA_GrBlendCoeff:
516 case kISA_GrBlendCoeff:
517 case kDA_GrBlendCoeff:
518 case kIDA_GrBlendCoeff:
519 default:
520 SkFAIL("srcCoeff should not refer to src or dst.");
521 break;
522
523 // TODO: update this once GrPaint actually has a const color.
524 case kConstC_GrBlendCoeff:
525 case kIConstC_GrBlendCoeff:
526 case kConstA_GrBlendCoeff:
527 case kIConstA_GrBlendCoeff:
528 *solidColorKnownComponents = 0;
529 break;
530 }
531 } else {
532 solidColorKnownComponents = 0;
533 }
534 }
535 return opaque;
536}
537
egdanielc2304142014-12-11 13:15:13 -0800538GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
539
540GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
541 GrContext*,
542 const GrDrawTargetCaps&,
543 GrTexture*[]) {
544 GrBlendCoeff src;
545 do {
546 src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
547 } while (GrBlendCoeffRefsSrc(src));
548
549 GrBlendCoeff dst;
550 do {
551 dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
552 } while (GrBlendCoeffRefsDst(dst));
553
554 return GrPorterDuffXPFactory::Create(src, dst);
555}
egdaniel95131432014-12-09 11:15:43 -0800556