blob: 09ccf4eecc732c1530ac58e6832661c01da9792d [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
egdaniel41d4f092015-02-09 07:51:00 -080035class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -080036public:
egdaniel41d4f092015-02-09 07:51:00 -080037 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
38 GrColor constant, const GrDeviceCoordTexture* dstCopy,
39 bool willReadDstColor) {
40 return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant, dstCopy,
41 willReadDstColor));
42 }
egdaniel378092f2014-12-03 10:40:13 -080043
egdaniel41d4f092015-02-09 07:51:00 -080044 ~PorterDuffXferProcessor() SK_OVERRIDE;
45
46 const char* name() const SK_OVERRIDE { return "Porter Duff"; }
47
48 GrGLXferProcessor* createGLInstance() const SK_OVERRIDE;
49
50 bool hasSecondaryOutput() const SK_OVERRIDE;
51
52 ///////////////////////////////////////////////////////////////////////////
53 /// @name Stage Output Types
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 };
63
64 enum SecondaryOutputType {
65 // There is no secondary output
66 kNone_SecondaryOutputType,
67 // Writes coverage as the secondary output. Only set if dual source blending is supported
68 // and primary output is kModulate.
69 kCoverage_SecondaryOutputType,
70 // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending
71 // is supported and primary output is kModulate.
72 kCoverageISA_SecondaryOutputType,
73 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source
74 // blending is supported and primary output is kModulate.
75 kCoverageISC_SecondaryOutputType,
76
77 kSecondaryOutputTypeCnt,
78 };
79
80 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
81 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
82
83 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
84 const GrProcOptInfo& coveragePOI,
85 bool doesStencilWrite,
86 GrColor* overrideColor,
87 const GrDrawTargetCaps& caps) SK_OVERRIDE;
88
89 void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE {
90 blendInfo->fSrcBlend = fSrcBlend;
91 blendInfo->fDstBlend = fDstBlend;
92 blendInfo->fBlendConstant = fBlendConstant;
93 }
94
95private:
96 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
97 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
98
99 void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE;
100
101 bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE {
102 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
103 if (fSrcBlend != xp.fSrcBlend ||
104 fDstBlend != xp.fDstBlend ||
105 fBlendConstant != xp.fBlendConstant ||
106 fPrimaryOutputType != xp.fPrimaryOutputType ||
107 fSecondaryOutputType != xp.fSecondaryOutputType) {
108 return false;
109 }
110 return true;
111 }
112
113 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
114 const GrProcOptInfo& coveragePOI,
115 bool doesStencilWrite);
116
117 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps,
118 bool hasSolidCoverage);
119
120 GrBlendCoeff fSrcBlend;
121 GrBlendCoeff fDstBlend;
122 GrColor fBlendConstant;
123 PrimaryOutputType fPrimaryOutputType;
124 SecondaryOutputType fSecondaryOutputType;
125
126 typedef GrXferProcessor INHERITED;
127};
128
129///////////////////////////////////////////////////////////////////////////////
130
131class GLPorterDuffXferProcessor : public GrGLXferProcessor {
132public:
133 GLPorterDuffXferProcessor(const GrProcessor&) {}
134
135 virtual ~GLPorterDuffXferProcessor() {}
egdaniel378092f2014-12-03 10:40:13 -0800136
bsalomon50785a32015-02-06 07:02:37 -0800137 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
138 GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800139 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
bsalomon50785a32015-02-06 07:02:37 -0800140 b->add32(xp.primaryOutputType());
141 b->add32(xp.secondaryOutputType());
142 };
143
144private:
145 void onEmitCode(const EmitArgs& args) SK_OVERRIDE {
egdaniel41d4f092015-02-09 07:51:00 -0800146 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdanielc2304142014-12-11 13:15:13 -0800147 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
148 if (xp.hasSecondaryOutput()) {
149 switch(xp.secondaryOutputType()) {
egdaniel41d4f092015-02-09 07:51:00 -0800150 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
egdanielc2304142014-12-11 13:15:13 -0800151 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary, args.fInputCoverage);
152 break;
egdaniel41d4f092015-02-09 07:51:00 -0800153 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
egdanielc2304142014-12-11 13:15:13 -0800154 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
155 args.fOutputSecondary, args.fInputColor,
156 args.fInputCoverage);
157 break;
egdaniel41d4f092015-02-09 07:51:00 -0800158 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
egdanielc2304142014-12-11 13:15:13 -0800159 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
160 args.fOutputSecondary, args.fInputColor,
161 args.fInputCoverage);
162 break;
163 default:
164 SkFAIL("Unexpected Secondary Output");
165 }
166 }
167
joshualitt9b989322014-12-15 14:16:27 -0800168 switch (xp.primaryOutputType()) {
egdaniel41d4f092015-02-09 07:51:00 -0800169 case PorterDuffXferProcessor::kNone_PrimaryOutputType:
joshualitt9b989322014-12-15 14:16:27 -0800170 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
171 break;
egdaniel41d4f092015-02-09 07:51:00 -0800172 case PorterDuffXferProcessor::kColor_PrimaryOutputType:
joshualitt9b989322014-12-15 14:16:27 -0800173 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
174 break;
egdaniel41d4f092015-02-09 07:51:00 -0800175 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
joshualitt9b989322014-12-15 14:16:27 -0800176 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
177 break;
egdaniel41d4f092015-02-09 07:51:00 -0800178 case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
joshualitt9b989322014-12-15 14:16:27 -0800179 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
180 args.fInputCoverage);
joshualitt9b989322014-12-15 14:16:27 -0800181 break;
182 default:
183 SkFAIL("Unexpected Primary Output");
egdanielc2304142014-12-11 13:15:13 -0800184 }
egdaniel378092f2014-12-03 10:40:13 -0800185 }
186
bsalomon50785a32015-02-06 07:02:37 -0800187 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {};
egdaniel378092f2014-12-03 10:40:13 -0800188
egdaniel378092f2014-12-03 10:40:13 -0800189 typedef GrGLXferProcessor INHERITED;
190};
191
192///////////////////////////////////////////////////////////////////////////////
193
egdaniel41d4f092015-02-09 07:51:00 -0800194PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend,
195 GrBlendCoeff dstBlend,
196 GrColor constant,
197 const GrDeviceCoordTexture* dstCopy,
198 bool willReadDstColor)
egdanielc2304142014-12-11 13:15:13 -0800199 : fSrcBlend(srcBlend)
200 , fDstBlend(dstBlend)
201 , fBlendConstant(constant)
202 , fPrimaryOutputType(kModulate_PrimaryOutputType)
203 , fSecondaryOutputType(kNone_SecondaryOutputType) {
egdaniel41d4f092015-02-09 07:51:00 -0800204 this->initClassID<PorterDuffXferProcessor>();
joshualitteb2a6762014-12-04 11:35:33 -0800205}
egdaniel378092f2014-12-03 10:40:13 -0800206
egdaniel41d4f092015-02-09 07:51:00 -0800207PorterDuffXferProcessor::~PorterDuffXferProcessor() {
egdaniel378092f2014-12-03 10:40:13 -0800208}
209
egdaniel41d4f092015-02-09 07:51:00 -0800210void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLCaps& caps,
211 GrProcessorKeyBuilder* b) const {
212 GLPorterDuffXferProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800213}
214
egdaniel41d4f092015-02-09 07:51:00 -0800215GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
216 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -0800217}
218
egdaniel95131432014-12-09 11:15:43 -0800219GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800220PorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
221 const GrProcOptInfo& coveragePOI,
222 bool doesStencilWrite,
223 GrColor* overrideColor,
224 const GrDrawTargetCaps& caps) {
egdaniel54160f32014-12-15 12:38:53 -0800225 GrXferProcessor::OptFlags optFlags;
226 // Optimizations when doing RGB Coverage
227 if (coveragePOI.isFourChannelOutput()) {
228 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
229 // value of the blend the constant. We should already have valid blend coeff's if we are at
230 // a point where we have RGB coverage. We don't need any color stages since the known color
231 // output is already baked into the blendConstant.
232 uint8_t alpha = GrColorUnpackA(fBlendConstant);
233 *overrideColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
234 optFlags = GrXferProcessor::kOverrideColor_OptFlag;
235 } else {
236 optFlags = this->internalGetOptimizations(colorPOI,
237 coveragePOI,
joshualitt9b989322014-12-15 14:16:27 -0800238 doesStencilWrite);
egdaniel54160f32014-12-15 12:38:53 -0800239 }
egdaniel71e236c2015-01-20 06:34:51 -0800240 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
egdanielc2304142014-12-11 13:15:13 -0800241 return optFlags;
242}
243
egdaniel41d4f092015-02-09 07:51:00 -0800244void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
245 const GrDrawTargetCaps& caps,
246 bool hasSolidCoverage) {
joshualitt9b989322014-12-15 14:16:27 -0800247 if (optFlags & kIgnoreColor_OptFlag) {
248 if (optFlags & kIgnoreCoverage_OptFlag) {
249 fPrimaryOutputType = kNone_PrimaryOutputType;
250 return;
251 } else {
252 fPrimaryOutputType = kCoverage_PrimaryOutputType;
253 return;
254 }
255 } else if (optFlags & kIgnoreCoverage_OptFlag) {
256 fPrimaryOutputType = kColor_PrimaryOutputType;
257 return;
258 }
259
egdanielc2304142014-12-11 13:15:13 -0800260 // If we do have coverage determine whether it matters. Dual source blending is expensive so
261 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
262 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
263 // solid coverage.
264 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
265 if (caps.dualSourceBlendingSupport()) {
266 if (kZero_GrBlendCoeff == fDstBlend) {
267 // write the coverage value to second color
268 fSecondaryOutputType = kCoverage_SecondaryOutputType;
269 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
270 } else if (kSA_GrBlendCoeff == fDstBlend) {
271 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
272 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
273 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
274 } else if (kSC_GrBlendCoeff == fDstBlend) {
275 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
276 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
277 fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
278 }
egdanielc2304142014-12-11 13:15:13 -0800279 }
280 }
281}
282
283GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800284PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
285 const GrProcOptInfo& coveragePOI,
286 bool doesStencilWrite) {
egdaniel95131432014-12-09 11:15:43 -0800287 bool srcAIsOne;
288 bool hasCoverage;
egdaniel87509242014-12-17 13:37:13 -0800289
290 srcAIsOne = colorPOI.isOpaque();
291 hasCoverage = !coveragePOI.isSolidWhite();
egdaniel95131432014-12-09 11:15:43 -0800292
293 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
294 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
295 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
296 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
297
egdaniel95131432014-12-09 11:15:43 -0800298 // When coeffs are (0,1) there is no reason to draw at all, unless
299 // stenciling is enabled. Having color writes disabled is effectively
300 // (0,1).
301 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
302 if (doesStencilWrite) {
joshualitt9b989322014-12-15 14:16:27 -0800303 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800304 GrXferProcessor::kSetCoverageDrawing_OptFlag;
305 } else {
306 fDstBlend = kOne_GrBlendCoeff;
307 return GrXferProcessor::kSkipDraw_OptFlag;
308 }
309 }
310
311 // if we don't have coverage we can check whether the dst
312 // has to read at all. If not, we'll disable blending.
313 if (!hasCoverage) {
314 if (dstCoeffIsZero) {
315 if (kOne_GrBlendCoeff == fSrcBlend) {
316 // if there is no coverage and coeffs are (1,0) then we
317 // won't need to read the dst at all, it gets replaced by src
318 fDstBlend = kZero_GrBlendCoeff;
319 return GrXferProcessor::kNone_Opt;
320 } else if (kZero_GrBlendCoeff == fSrcBlend) {
321 // if the op is "clear" then we don't need to emit a color
322 // or blend, just write transparent black into the dst.
323 fSrcBlend = kOne_GrBlendCoeff;
324 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800325 return GrXferProcessor::kIgnoreColor_OptFlag |
326 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800327 }
328 }
egdaniel87509242014-12-17 13:37:13 -0800329 } else {
egdaniel95131432014-12-09 11:15:43 -0800330 // check whether coverage can be safely rolled into alpha
331 // of if we can skip color computation and just emit coverage
egdaniel87509242014-12-17 13:37:13 -0800332 if (can_tweak_alpha_for_coverage(fDstBlend)) {
egdaniel95131432014-12-09 11:15:43 -0800333 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
334 }
335 if (dstCoeffIsZero) {
336 if (kZero_GrBlendCoeff == fSrcBlend) {
337 // the source color is not included in the blend
338 // the dst coeff is effectively zero so blend works out to:
339 // (c)(0)D + (1-c)D = (1-c)D.
340 fDstBlend = kISA_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800341 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800342 GrXferProcessor::kSetCoverageDrawing_OptFlag;
343 } else if (srcAIsOne) {
344 // the dst coeff is effectively zero so blend works out to:
345 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
346 // If Sa is 1 then we can replace Sa with c
347 // and set dst coeff to 1-Sa.
348 fDstBlend = kISA_GrBlendCoeff;
349 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
350 }
351 } else if (dstCoeffIsOne) {
352 // the dst coeff is effectively one so blend works out to:
353 // cS + (c)(1)D + (1-c)D = cS + D.
354 fDstBlend = kOne_GrBlendCoeff;
355 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
356 }
357 }
358
359 return GrXferProcessor::kNone_Opt;
360}
egdanielc2304142014-12-11 13:15:13 -0800361
egdaniel41d4f092015-02-09 07:51:00 -0800362bool PorterDuffXferProcessor::hasSecondaryOutput() const {
egdanielc2304142014-12-11 13:15:13 -0800363 return kNone_SecondaryOutputType != fSecondaryOutputType;
364}
365
egdaniel378092f2014-12-03 10:40:13 -0800366///////////////////////////////////////////////////////////////////////////////
367
egdaniel915187b2014-12-05 12:58:28 -0800368GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800369 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800370 this->initClassID<GrPorterDuffXPFactory>();
371}
372
egdanielc016fb82014-12-03 11:41:54 -0800373GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
374 switch (mode) {
375 case SkXfermode::kClear_Mode: {
376 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
377 return SkRef(&gClearPDXPF);
378 break;
379 }
380 case SkXfermode::kSrc_Mode: {
381 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
382 return SkRef(&gSrcPDXPF);
383 break;
384 }
385 case SkXfermode::kDst_Mode: {
386 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
387 return SkRef(&gDstPDXPF);
388 break;
389 }
390 case SkXfermode::kSrcOver_Mode: {
391 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
392 return SkRef(&gSrcOverPDXPF);
393 break;
394 }
395 case SkXfermode::kDstOver_Mode: {
396 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
397 return SkRef(&gDstOverPDXPF);
398 break;
399 }
400 case SkXfermode::kSrcIn_Mode: {
401 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
402 return SkRef(&gSrcInPDXPF);
403 break;
404 }
405 case SkXfermode::kDstIn_Mode: {
406 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
407 return SkRef(&gDstInPDXPF);
408 break;
409 }
410 case SkXfermode::kSrcOut_Mode: {
411 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
412 return SkRef(&gSrcOutPDXPF);
413 break;
414 }
415 case SkXfermode::kDstOut_Mode: {
416 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
417 return SkRef(&gDstOutPDXPF);
418 break;
419 }
420 case SkXfermode::kSrcATop_Mode: {
421 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
422 return SkRef(&gSrcATopPDXPF);
423 break;
424 }
425 case SkXfermode::kDstATop_Mode: {
426 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
427 return SkRef(&gDstATopPDXPF);
428 break;
429 }
430 case SkXfermode::kXor_Mode: {
431 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
432 return SkRef(&gXorPDXPF);
433 break;
434 }
435 case SkXfermode::kPlus_Mode: {
436 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
437 return SkRef(&gPlusPDXPF);
438 break;
439 }
440 case SkXfermode::kModulate_Mode: {
441 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
442 return SkRef(&gModulatePDXPF);
443 break;
444 }
445 case SkXfermode::kScreen_Mode: {
446 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
447 return SkRef(&gScreenPDXPF);
448 break;
449 }
450 default:
451 return NULL;
452 }
453}
454
bsalomon50785a32015-02-06 07:02:37 -0800455GrXferProcessor*
456GrPorterDuffXPFactory::onCreateXferProcessor(const GrProcOptInfo& colorPOI,
457 const GrProcOptInfo& covPOI,
458 const GrDeviceCoordTexture* dstCopy) const {
egdaniel95131432014-12-09 11:15:43 -0800459 if (!covPOI.isFourChannelOutput()) {
egdaniel41d4f092015-02-09 07:51:00 -0800460 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
461 this->willReadDstColor());
egdaniel95131432014-12-09 11:15:43 -0800462 } else {
463 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
464 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
465 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
egdaniel41d4f092015-02-09 07:51:00 -0800466 return PorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
467 blendConstant, dstCopy,
468 this->willReadDstColor());
egdaniel95131432014-12-09 11:15:43 -0800469 } else {
470 return NULL;
471 }
472 }
egdaniel378092f2014-12-03 10:40:13 -0800473}
474
475bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
476 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800477 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800478 kRGBA_GrColorComponentFlags == knownColorFlags) {
479 return true;
480 }
481 return false;
482}
483
egdaniel95131432014-12-09 11:15:43 -0800484bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
egdaniel080e6732014-12-22 07:35:52 -0800485 const GrProcOptInfo& coveragePOI) const {
egdaniel87509242014-12-17 13:37:13 -0800486 bool srcAIsOne = colorPOI.isOpaque();
egdaniel95131432014-12-09 11:15:43 -0800487
egdaniel95131432014-12-09 11:15:43 -0800488 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
489 (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
490 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
491 (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
492
493 if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
494 return true;
495 }
496
497 // if we don't have coverage we can check whether the dst
498 // has to read at all.
egdaniel87509242014-12-17 13:37:13 -0800499 // check whether coverage can be safely rolled into alpha
500 // of if we can skip color computation and just emit coverage
501 if (this->canTweakAlphaForCoverage()) {
egdaniel95131432014-12-09 11:15:43 -0800502 return true;
egdaniel87509242014-12-17 13:37:13 -0800503 }
504 if (dstCoeffIsZero) {
505 if (kZero_GrBlendCoeff == fSrcCoeff) {
egdaniel95131432014-12-09 11:15:43 -0800506 return true;
egdaniel87509242014-12-17 13:37:13 -0800507 } else if (srcAIsOne) {
508 return true;
egdaniel95131432014-12-09 11:15:43 -0800509 }
egdaniel87509242014-12-17 13:37:13 -0800510 } else if (dstCoeffIsOne) {
511 return true;
egdaniel95131432014-12-09 11:15:43 -0800512 }
513
egdaniel95131432014-12-09 11:15:43 -0800514 return false;
515}
516
egdaniel87509242014-12-17 13:37:13 -0800517bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const {
518 return can_tweak_alpha_for_coverage(fDstCoeff);
egdaniel95131432014-12-09 11:15:43 -0800519}
520
egdaniel9e4ecdc2014-12-18 12:44:55 -0800521void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
522 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800523 GrXPFactory::InvariantOutput* output) const {
egdaniel95131432014-12-09 11:15:43 -0800524 if (!coveragePOI.isSolidWhite()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800525 output->fWillBlendWithDst = true;
526 output->fBlendedColorFlags = 0;
527 return;
egdaniel95131432014-12-09 11:15:43 -0800528 }
529
egdaniel95131432014-12-09 11:15:43 -0800530 GrBlendCoeff srcCoeff = fSrcCoeff;
531 GrBlendCoeff dstCoeff = fDstCoeff;
532
533 // TODO: figure out to merge this simplify with other current optimization code paths and
534 // eventually remove from GrBlend
535 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
536 0, 0, 0);
537
egdaniel9e4ecdc2014-12-18 12:44:55 -0800538 if (GrBlendCoeffRefsDst(srcCoeff)) {
539 output->fWillBlendWithDst = true;
540 output->fBlendedColorFlags = 0;
541 return;
egdaniel95131432014-12-09 11:15:43 -0800542 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800543
544 if (kZero_GrBlendCoeff != dstCoeff) {
545 bool srcAIsOne = colorPOI.isOpaque();
546 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
547 output->fWillBlendWithDst = true;
548 }
549 output->fBlendedColorFlags = 0;
550 return;
551 }
552
553 switch (srcCoeff) {
554 case kZero_GrBlendCoeff:
555 output->fBlendedColor = 0;
556 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
557 break;
558
559 case kOne_GrBlendCoeff:
560 output->fBlendedColor = colorPOI.color();
561 output->fBlendedColorFlags = colorPOI.validFlags();
562 break;
563
564 // The src coeff should never refer to the src and if it refers to dst then opaque
565 // should have been false.
566 case kSC_GrBlendCoeff:
567 case kISC_GrBlendCoeff:
568 case kDC_GrBlendCoeff:
569 case kIDC_GrBlendCoeff:
570 case kSA_GrBlendCoeff:
571 case kISA_GrBlendCoeff:
572 case kDA_GrBlendCoeff:
573 case kIDA_GrBlendCoeff:
574 default:
575 SkFAIL("srcCoeff should not refer to src or dst.");
576 break;
577
578 // TODO: update this once GrPaint actually has a const color.
579 case kConstC_GrBlendCoeff:
580 case kIConstC_GrBlendCoeff:
581 case kConstA_GrBlendCoeff:
582 case kIConstA_GrBlendCoeff:
583 output->fBlendedColorFlags = 0;
584 break;
585 }
586
egdaniel9e4ecdc2014-12-18 12:44:55 -0800587 output->fWillBlendWithDst = false;
egdaniel95131432014-12-09 11:15:43 -0800588}
589
bsalomon50785a32015-02-06 07:02:37 -0800590bool GrPorterDuffXPFactory::willReadDstColor() const {
591 return false;
592}
593
egdanielc2304142014-12-11 13:15:13 -0800594GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
595
596GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
597 GrContext*,
598 const GrDrawTargetCaps&,
599 GrTexture*[]) {
600 GrBlendCoeff src;
601 do {
602 src = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
603 } while (GrBlendCoeffRefsSrc(src));
604
605 GrBlendCoeff dst;
606 do {
607 dst = GrBlendCoeff(random->nextRangeU(kFirstPublicGrBlendCoeff, kLastPublicGrBlendCoeff));
608 } while (GrBlendCoeffRefsDst(dst));
609
610 return GrPorterDuffXPFactory::Create(src, dst);
611}
egdaniel95131432014-12-09 11:15:43 -0800612