blob: 2735ac3c22eceefc9049a382c4c751a746a1d23b [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
mtklein36352bf2015-03-25 18:17:31 -070044 ~PorterDuffXferProcessor() override;
egdaniel41d4f092015-02-09 07:51:00 -080045
mtklein36352bf2015-03-25 18:17:31 -070046 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -080047
mtklein36352bf2015-03-25 18:17:31 -070048 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -080049
mtklein36352bf2015-03-25 18:17:31 -070050 bool hasSecondaryOutput() const override;
egdaniel41d4f092015-02-09 07:51:00 -080051
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,
egdaniel3ad65702015-02-17 11:15:47 -080062 // Custom Porter-Duff output, used for when we explictly are reading the dst and blending
63 // in the shader. Secondary Output must be none if you use this. The custom blend uses the
64 // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D
65 kCustom_PrimaryOutputType
egdaniel41d4f092015-02-09 07:51:00 -080066 };
67
68 enum SecondaryOutputType {
69 // There is no secondary output
70 kNone_SecondaryOutputType,
71 // Writes coverage as the secondary output. Only set if dual source blending is supported
72 // and primary output is kModulate.
73 kCoverage_SecondaryOutputType,
74 // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending
75 // is supported and primary output is kModulate.
76 kCoverageISA_SecondaryOutputType,
77 // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source
78 // blending is supported and primary output is kModulate.
79 kCoverageISC_SecondaryOutputType,
80
81 kSecondaryOutputTypeCnt,
82 };
83
84 PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
85 SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
86
87 GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI,
88 const GrProcOptInfo& coveragePOI,
89 bool doesStencilWrite,
90 GrColor* overrideColor,
mtklein36352bf2015-03-25 18:17:31 -070091 const GrDrawTargetCaps& caps) override;
egdaniel41d4f092015-02-09 07:51:00 -080092
mtklein36352bf2015-03-25 18:17:31 -070093 void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
egdaniel3ad65702015-02-17 11:15:47 -080094 if (!this->willReadDstColor()) {
95 blendInfo->fSrcBlend = fSrcBlend;
96 blendInfo->fDstBlend = fDstBlend;
97 } else {
98 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
99 blendInfo->fDstBlend = kZero_GrBlendCoeff;
100 }
egdaniel41d4f092015-02-09 07:51:00 -0800101 blendInfo->fBlendConstant = fBlendConstant;
102 }
103
egdaniel3ad65702015-02-17 11:15:47 -0800104 GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
105 GrBlendCoeff getDstBlend() const { return fDstBlend; }
106
egdaniel41d4f092015-02-09 07:51:00 -0800107private:
108 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
109 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
110
mtklein36352bf2015-03-25 18:17:31 -0700111 void onGetGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const override;
egdaniel41d4f092015-02-09 07:51:00 -0800112
mtklein36352bf2015-03-25 18:17:31 -0700113 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800114 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
115 if (fSrcBlend != xp.fSrcBlend ||
116 fDstBlend != xp.fDstBlend ||
117 fBlendConstant != xp.fBlendConstant ||
118 fPrimaryOutputType != xp.fPrimaryOutputType ||
119 fSecondaryOutputType != xp.fSecondaryOutputType) {
120 return false;
121 }
122 return true;
123 }
124
125 GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
126 const GrProcOptInfo& coveragePOI,
127 bool doesStencilWrite);
128
129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrDrawTargetCaps& caps,
130 bool hasSolidCoverage);
131
132 GrBlendCoeff fSrcBlend;
133 GrBlendCoeff fDstBlend;
134 GrColor fBlendConstant;
135 PrimaryOutputType fPrimaryOutputType;
136 SecondaryOutputType fSecondaryOutputType;
137
138 typedef GrXferProcessor INHERITED;
139};
140
141///////////////////////////////////////////////////////////////////////////////
142
egdaniel3ad65702015-02-17 11:15:47 -0800143bool append_porterduff_term(GrGLFPFragmentBuilder* fsBuilder, GrBlendCoeff coeff,
144 const char* colorName, const char* srcColorName,
145 const char* dstColorName, bool hasPrevious) {
146 if (kZero_GrBlendCoeff == coeff) {
147 return hasPrevious;
148 } else {
149 if (hasPrevious) {
150 fsBuilder->codeAppend(" + ");
151 }
152 fsBuilder->codeAppendf("%s", colorName);
153 switch (coeff) {
154 case kOne_GrBlendCoeff:
155 break;
156 case kSC_GrBlendCoeff:
157 fsBuilder->codeAppendf(" * %s", srcColorName);
158 break;
159 case kISC_GrBlendCoeff:
160 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
161 break;
162 case kDC_GrBlendCoeff:
163 fsBuilder->codeAppendf(" * %s", dstColorName);
164 break;
165 case kIDC_GrBlendCoeff:
166 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
167 break;
168 case kSA_GrBlendCoeff:
169 fsBuilder->codeAppendf(" * %s.a", srcColorName);
170 break;
171 case kISA_GrBlendCoeff:
172 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
173 break;
174 case kDA_GrBlendCoeff:
175 fsBuilder->codeAppendf(" * %s.a", dstColorName);
176 break;
177 case kIDA_GrBlendCoeff:
178 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
179 break;
180 default:
181 SkFAIL("Unsupported Blend Coeff");
182 }
183 return true;
184 }
185}
186
egdaniel41d4f092015-02-09 07:51:00 -0800187class GLPorterDuffXferProcessor : public GrGLXferProcessor {
188public:
189 GLPorterDuffXferProcessor(const GrProcessor&) {}
190
191 virtual ~GLPorterDuffXferProcessor() {}
egdaniel378092f2014-12-03 10:40:13 -0800192
bsalomon50785a32015-02-06 07:02:37 -0800193 static void GenKey(const GrProcessor& processor, const GrGLCaps& caps,
194 GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800195 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
bsalomon50785a32015-02-06 07:02:37 -0800196 b->add32(xp.primaryOutputType());
197 b->add32(xp.secondaryOutputType());
egdaniel3ad65702015-02-17 11:15:47 -0800198 if (xp.willReadDstColor()) {
199 b->add32(xp.getSrcBlend());
200 b->add32(xp.getDstBlend());
201 }
bsalomon50785a32015-02-06 07:02:37 -0800202 };
203
204private:
mtklein36352bf2015-03-25 18:17:31 -0700205 void onEmitCode(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800206 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdanielc2304142014-12-11 13:15:13 -0800207 GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel3ad65702015-02-17 11:15:47 -0800208 if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) {
209 SkASSERT(!xp.willReadDstColor());
egdanielc2304142014-12-11 13:15:13 -0800210 switch(xp.secondaryOutputType()) {
egdaniel3ad65702015-02-17 11:15:47 -0800211 case PorterDuffXferProcessor::kNone_SecondaryOutputType:
212 break;
egdaniel41d4f092015-02-09 07:51:00 -0800213 case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
egdaniel3ad65702015-02-17 11:15:47 -0800214 fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary,
215 args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800216 break;
egdaniel41d4f092015-02-09 07:51:00 -0800217 case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
egdanielc2304142014-12-11 13:15:13 -0800218 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
219 args.fOutputSecondary, args.fInputColor,
220 args.fInputCoverage);
221 break;
egdaniel41d4f092015-02-09 07:51:00 -0800222 case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
egdanielc2304142014-12-11 13:15:13 -0800223 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
224 args.fOutputSecondary, args.fInputColor,
225 args.fInputCoverage);
226 break;
227 default:
228 SkFAIL("Unexpected Secondary Output");
229 }
egdaniel3ad65702015-02-17 11:15:47 -0800230
231 switch (xp.primaryOutputType()) {
232 case PorterDuffXferProcessor::kNone_PrimaryOutputType:
233 fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
234 break;
235 case PorterDuffXferProcessor::kColor_PrimaryOutputType:
236 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
237 break;
238 case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
239 fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
240 break;
241 case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
242 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
243 args.fInputCoverage);
244 break;
245 default:
246 SkFAIL("Unexpected Primary Output");
247 }
248 } else {
249 SkASSERT(xp.willReadDstColor());
250
251 const char* dstColor = fsBuilder->dstColor();
252
253 fsBuilder->codeAppend("vec4 colorBlend =");
254 // append src blend
255 bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(),
256 args.fInputColor, args.fInputColor,
257 dstColor, false);
258 // append dst blend
259 SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(),
260 dstColor, args.fInputColor,
261 dstColor, didAppend));
262 fsBuilder->codeAppend(";");
263
264 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
265 args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage,
266 dstColor);
egdanielc2304142014-12-11 13:15:13 -0800267 }
egdaniel378092f2014-12-03 10:40:13 -0800268 }
269
mtklein36352bf2015-03-25 18:17:31 -0700270 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
egdaniel378092f2014-12-03 10:40:13 -0800271
egdaniel378092f2014-12-03 10:40:13 -0800272 typedef GrGLXferProcessor INHERITED;
273};
274
275///////////////////////////////////////////////////////////////////////////////
276
egdaniel41d4f092015-02-09 07:51:00 -0800277PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend,
278 GrBlendCoeff dstBlend,
279 GrColor constant,
280 const GrDeviceCoordTexture* dstCopy,
281 bool willReadDstColor)
egdaniel3ad65702015-02-17 11:15:47 -0800282 : INHERITED(dstCopy, willReadDstColor)
283 , fSrcBlend(srcBlend)
egdanielc2304142014-12-11 13:15:13 -0800284 , fDstBlend(dstBlend)
285 , fBlendConstant(constant)
286 , fPrimaryOutputType(kModulate_PrimaryOutputType)
287 , fSecondaryOutputType(kNone_SecondaryOutputType) {
egdaniel41d4f092015-02-09 07:51:00 -0800288 this->initClassID<PorterDuffXferProcessor>();
joshualitteb2a6762014-12-04 11:35:33 -0800289}
egdaniel378092f2014-12-03 10:40:13 -0800290
egdaniel41d4f092015-02-09 07:51:00 -0800291PorterDuffXferProcessor::~PorterDuffXferProcessor() {
egdaniel378092f2014-12-03 10:40:13 -0800292}
293
egdaniel41d4f092015-02-09 07:51:00 -0800294void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLCaps& caps,
295 GrProcessorKeyBuilder* b) const {
296 GLPorterDuffXferProcessor::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800297}
298
egdaniel41d4f092015-02-09 07:51:00 -0800299GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
300 return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
egdaniel378092f2014-12-03 10:40:13 -0800301}
302
egdaniel95131432014-12-09 11:15:43 -0800303GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800304PorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
305 const GrProcOptInfo& coveragePOI,
306 bool doesStencilWrite,
307 GrColor* overrideColor,
308 const GrDrawTargetCaps& caps) {
egdaniel54160f32014-12-15 12:38:53 -0800309 GrXferProcessor::OptFlags optFlags;
310 // Optimizations when doing RGB Coverage
311 if (coveragePOI.isFourChannelOutput()) {
312 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
313 // value of the blend the constant. We should already have valid blend coeff's if we are at
314 // a point where we have RGB coverage. We don't need any color stages since the known color
315 // output is already baked into the blendConstant.
316 uint8_t alpha = GrColorUnpackA(fBlendConstant);
317 *overrideColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
318 optFlags = GrXferProcessor::kOverrideColor_OptFlag;
319 } else {
320 optFlags = this->internalGetOptimizations(colorPOI,
321 coveragePOI,
joshualitt9b989322014-12-15 14:16:27 -0800322 doesStencilWrite);
egdaniel54160f32014-12-15 12:38:53 -0800323 }
egdaniel71e236c2015-01-20 06:34:51 -0800324 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
egdanielc2304142014-12-11 13:15:13 -0800325 return optFlags;
326}
327
egdaniel41d4f092015-02-09 07:51:00 -0800328void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
329 const GrDrawTargetCaps& caps,
330 bool hasSolidCoverage) {
egdaniel3ad65702015-02-17 11:15:47 -0800331 if (this->willReadDstColor()) {
332 fPrimaryOutputType = kCustom_PrimaryOutputType;
333 return;
334 }
335
joshualitt9b989322014-12-15 14:16:27 -0800336 if (optFlags & kIgnoreColor_OptFlag) {
337 if (optFlags & kIgnoreCoverage_OptFlag) {
338 fPrimaryOutputType = kNone_PrimaryOutputType;
339 return;
340 } else {
341 fPrimaryOutputType = kCoverage_PrimaryOutputType;
342 return;
343 }
344 } else if (optFlags & kIgnoreCoverage_OptFlag) {
345 fPrimaryOutputType = kColor_PrimaryOutputType;
346 return;
347 }
348
egdanielc2304142014-12-11 13:15:13 -0800349 // If we do have coverage determine whether it matters. Dual source blending is expensive so
350 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
351 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
352 // solid coverage.
353 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
354 if (caps.dualSourceBlendingSupport()) {
355 if (kZero_GrBlendCoeff == fDstBlend) {
356 // write the coverage value to second color
357 fSecondaryOutputType = kCoverage_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800358 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800359 } else if (kSA_GrBlendCoeff == fDstBlend) {
360 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
361 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800362 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800363 } else if (kSC_GrBlendCoeff == fDstBlend) {
364 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
365 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800366 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800367 }
egdanielc2304142014-12-11 13:15:13 -0800368 }
369 }
370}
371
372GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800373PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
374 const GrProcOptInfo& coveragePOI,
375 bool doesStencilWrite) {
egdaniel3ad65702015-02-17 11:15:47 -0800376 if (this->willReadDstColor()) {
377 return GrXferProcessor::kNone_Opt;
378 }
egdaniel87509242014-12-17 13:37:13 -0800379
egdaniel3ad65702015-02-17 11:15:47 -0800380 bool srcAIsOne = colorPOI.isOpaque();
381 bool hasCoverage = !coveragePOI.isSolidWhite();
egdaniel95131432014-12-09 11:15:43 -0800382
383 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
384 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
385 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
386 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
387
egdaniel95131432014-12-09 11:15:43 -0800388 // When coeffs are (0,1) there is no reason to draw at all, unless
389 // stenciling is enabled. Having color writes disabled is effectively
390 // (0,1).
391 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
392 if (doesStencilWrite) {
joshualitt9b989322014-12-15 14:16:27 -0800393 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800394 GrXferProcessor::kSetCoverageDrawing_OptFlag;
395 } else {
396 fDstBlend = kOne_GrBlendCoeff;
397 return GrXferProcessor::kSkipDraw_OptFlag;
398 }
399 }
400
401 // if we don't have coverage we can check whether the dst
402 // has to read at all. If not, we'll disable blending.
403 if (!hasCoverage) {
404 if (dstCoeffIsZero) {
405 if (kOne_GrBlendCoeff == fSrcBlend) {
406 // if there is no coverage and coeffs are (1,0) then we
407 // won't need to read the dst at all, it gets replaced by src
408 fDstBlend = kZero_GrBlendCoeff;
409 return GrXferProcessor::kNone_Opt;
410 } else if (kZero_GrBlendCoeff == fSrcBlend) {
411 // if the op is "clear" then we don't need to emit a color
412 // or blend, just write transparent black into the dst.
413 fSrcBlend = kOne_GrBlendCoeff;
414 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800415 return GrXferProcessor::kIgnoreColor_OptFlag |
416 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800417 }
418 }
egdaniel87509242014-12-17 13:37:13 -0800419 } else {
egdaniel95131432014-12-09 11:15:43 -0800420 // check whether coverage can be safely rolled into alpha
421 // of if we can skip color computation and just emit coverage
egdaniel87509242014-12-17 13:37:13 -0800422 if (can_tweak_alpha_for_coverage(fDstBlend)) {
egdanielf7c2d552015-02-13 12:11:00 -0800423 if (colorPOI.allStagesMultiplyInput()) {
424 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
425 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
426 } else {
427 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
428
429 }
egdaniel95131432014-12-09 11:15:43 -0800430 }
431 if (dstCoeffIsZero) {
432 if (kZero_GrBlendCoeff == fSrcBlend) {
433 // the source color is not included in the blend
434 // the dst coeff is effectively zero so blend works out to:
435 // (c)(0)D + (1-c)D = (1-c)D.
436 fDstBlend = kISA_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800437 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800438 GrXferProcessor::kSetCoverageDrawing_OptFlag;
439 } else if (srcAIsOne) {
440 // the dst coeff is effectively zero so blend works out to:
441 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
442 // If Sa is 1 then we can replace Sa with c
443 // and set dst coeff to 1-Sa.
444 fDstBlend = kISA_GrBlendCoeff;
egdanielf7c2d552015-02-13 12:11:00 -0800445 if (colorPOI.allStagesMultiplyInput()) {
446 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
447 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
448 } else {
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
450
451 }
egdaniel95131432014-12-09 11:15:43 -0800452 }
453 } else if (dstCoeffIsOne) {
454 // the dst coeff is effectively one so blend works out to:
455 // cS + (c)(1)D + (1-c)D = cS + D.
456 fDstBlend = kOne_GrBlendCoeff;
egdanielf7c2d552015-02-13 12:11:00 -0800457 if (colorPOI.allStagesMultiplyInput()) {
458 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
459 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
460 } else {
461 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
462
463 }
egdaniel95131432014-12-09 11:15:43 -0800464 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
465 }
466 }
467
468 return GrXferProcessor::kNone_Opt;
469}
egdanielc2304142014-12-11 13:15:13 -0800470
egdaniel41d4f092015-02-09 07:51:00 -0800471bool PorterDuffXferProcessor::hasSecondaryOutput() const {
egdanielc2304142014-12-11 13:15:13 -0800472 return kNone_SecondaryOutputType != fSecondaryOutputType;
473}
474
egdaniel378092f2014-12-03 10:40:13 -0800475///////////////////////////////////////////////////////////////////////////////
476
egdaniel915187b2014-12-05 12:58:28 -0800477GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800478 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800479 this->initClassID<GrPorterDuffXPFactory>();
480}
481
egdanielc016fb82014-12-03 11:41:54 -0800482GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
483 switch (mode) {
484 case SkXfermode::kClear_Mode: {
485 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
486 return SkRef(&gClearPDXPF);
487 break;
488 }
489 case SkXfermode::kSrc_Mode: {
490 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
491 return SkRef(&gSrcPDXPF);
492 break;
493 }
494 case SkXfermode::kDst_Mode: {
495 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
496 return SkRef(&gDstPDXPF);
497 break;
498 }
499 case SkXfermode::kSrcOver_Mode: {
500 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
501 return SkRef(&gSrcOverPDXPF);
502 break;
503 }
504 case SkXfermode::kDstOver_Mode: {
505 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
506 return SkRef(&gDstOverPDXPF);
507 break;
508 }
509 case SkXfermode::kSrcIn_Mode: {
510 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
511 return SkRef(&gSrcInPDXPF);
512 break;
513 }
514 case SkXfermode::kDstIn_Mode: {
515 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
516 return SkRef(&gDstInPDXPF);
517 break;
518 }
519 case SkXfermode::kSrcOut_Mode: {
520 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
521 return SkRef(&gSrcOutPDXPF);
522 break;
523 }
524 case SkXfermode::kDstOut_Mode: {
525 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
526 return SkRef(&gDstOutPDXPF);
527 break;
528 }
529 case SkXfermode::kSrcATop_Mode: {
530 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
531 return SkRef(&gSrcATopPDXPF);
532 break;
533 }
534 case SkXfermode::kDstATop_Mode: {
535 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
536 return SkRef(&gDstATopPDXPF);
537 break;
538 }
539 case SkXfermode::kXor_Mode: {
540 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
541 return SkRef(&gXorPDXPF);
542 break;
543 }
544 case SkXfermode::kPlus_Mode: {
545 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
546 return SkRef(&gPlusPDXPF);
547 break;
548 }
549 case SkXfermode::kModulate_Mode: {
550 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
551 return SkRef(&gModulatePDXPF);
552 break;
553 }
554 case SkXfermode::kScreen_Mode: {
555 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
556 return SkRef(&gScreenPDXPF);
557 break;
558 }
559 default:
560 return NULL;
561 }
562}
563
bsalomon50785a32015-02-06 07:02:37 -0800564GrXferProcessor*
egdaniel3ad65702015-02-17 11:15:47 -0800565GrPorterDuffXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
566 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800567 const GrProcOptInfo& covPOI,
568 const GrDeviceCoordTexture* dstCopy) const {
egdaniel95131432014-12-09 11:15:43 -0800569 if (!covPOI.isFourChannelOutput()) {
egdaniel41d4f092015-02-09 07:51:00 -0800570 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
egdaniel3ad65702015-02-17 11:15:47 -0800571 this->willReadDstColor(caps, colorPOI, covPOI));
egdaniel95131432014-12-09 11:15:43 -0800572 } else {
573 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
574 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
575 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
egdaniel41d4f092015-02-09 07:51:00 -0800576 return PorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
577 blendConstant, dstCopy,
egdaniel3ad65702015-02-17 11:15:47 -0800578 this->willReadDstColor(caps, colorPOI, covPOI));
egdaniel95131432014-12-09 11:15:43 -0800579 } else {
580 return NULL;
581 }
582 }
egdaniel378092f2014-12-03 10:40:13 -0800583}
584
585bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
586 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800587 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800588 kRGBA_GrColorComponentFlags == knownColorFlags) {
589 return true;
590 }
591 return false;
592}
593
egdaniel87509242014-12-17 13:37:13 -0800594bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const {
595 return can_tweak_alpha_for_coverage(fDstCoeff);
egdaniel95131432014-12-09 11:15:43 -0800596}
597
egdaniel9e4ecdc2014-12-18 12:44:55 -0800598void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
599 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800600 GrXPFactory::InvariantOutput* output) const {
egdaniel95131432014-12-09 11:15:43 -0800601 if (!coveragePOI.isSolidWhite()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800602 output->fWillBlendWithDst = true;
603 output->fBlendedColorFlags = 0;
604 return;
egdaniel95131432014-12-09 11:15:43 -0800605 }
606
egdaniel95131432014-12-09 11:15:43 -0800607 GrBlendCoeff srcCoeff = fSrcCoeff;
608 GrBlendCoeff dstCoeff = fDstCoeff;
609
610 // TODO: figure out to merge this simplify with other current optimization code paths and
611 // eventually remove from GrBlend
612 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
613 0, 0, 0);
614
egdaniel9e4ecdc2014-12-18 12:44:55 -0800615 if (GrBlendCoeffRefsDst(srcCoeff)) {
616 output->fWillBlendWithDst = true;
617 output->fBlendedColorFlags = 0;
618 return;
egdaniel95131432014-12-09 11:15:43 -0800619 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800620
621 if (kZero_GrBlendCoeff != dstCoeff) {
622 bool srcAIsOne = colorPOI.isOpaque();
623 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
624 output->fWillBlendWithDst = true;
625 }
626 output->fBlendedColorFlags = 0;
627 return;
628 }
629
630 switch (srcCoeff) {
631 case kZero_GrBlendCoeff:
632 output->fBlendedColor = 0;
633 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
634 break;
635
636 case kOne_GrBlendCoeff:
637 output->fBlendedColor = colorPOI.color();
638 output->fBlendedColorFlags = colorPOI.validFlags();
639 break;
640
641 // The src coeff should never refer to the src and if it refers to dst then opaque
642 // should have been false.
643 case kSC_GrBlendCoeff:
644 case kISC_GrBlendCoeff:
645 case kDC_GrBlendCoeff:
646 case kIDC_GrBlendCoeff:
647 case kSA_GrBlendCoeff:
648 case kISA_GrBlendCoeff:
649 case kDA_GrBlendCoeff:
650 case kIDA_GrBlendCoeff:
651 default:
652 SkFAIL("srcCoeff should not refer to src or dst.");
653 break;
654
655 // TODO: update this once GrPaint actually has a const color.
656 case kConstC_GrBlendCoeff:
657 case kIConstC_GrBlendCoeff:
658 case kConstA_GrBlendCoeff:
659 case kIConstA_GrBlendCoeff:
660 output->fBlendedColorFlags = 0;
661 break;
662 }
663
egdaniel9e4ecdc2014-12-18 12:44:55 -0800664 output->fWillBlendWithDst = false;
egdaniel95131432014-12-09 11:15:43 -0800665}
666
egdaniel3ad65702015-02-17 11:15:47 -0800667bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps,
668 const GrProcOptInfo& colorPOI,
egdaniele36914c2015-02-13 09:00:33 -0800669 const GrProcOptInfo& coveragePOI) const {
egdaniel3ad65702015-02-17 11:15:47 -0800670 // We can always blend correctly if we have dual source blending.
671 if (caps.dualSourceBlendingSupport()) {
672 return false;
673 }
674
675 if (this->canTweakAlphaForCoverage()) {
676 return false;
677 }
678
679 bool srcAIsOne = colorPOI.isOpaque();
680
681 if (kZero_GrBlendCoeff == fDstCoeff) {
682 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
683 return false;
684 }
685 }
686
687 // Reduces to: coeffS * (Cov*S) + D
688 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
689 return false;
690 }
691
692 // We can always blend correctly if we have solid coverage.
693 if (coveragePOI.isSolidWhite()) {
694 return false;
695 }
696
697 return true;
bsalomon50785a32015-02-06 07:02:37 -0800698}
699
egdanielc2304142014-12-11 13:15:13 -0800700GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
701
702GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
703 GrContext*,
704 const GrDrawTargetCaps&,
705 GrTexture*[]) {
egdanielb197b8f2015-02-17 07:34:43 -0800706 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
707 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800708}
egdaniel95131432014-12-09 11:15:43 -0800709