blob: 543a515e909e9ed59d2a64231bfe795ed1df20ce [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
cdaltonf4f2b442015-04-23 09:40:23 -070087 GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
88 GrBlendCoeff getDstBlend() const { return fDstBlend; }
89
90private:
91 PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
92 const GrDeviceCoordTexture* dstCopy, bool willReadDstColor);
93
egdanielc19cdc22015-05-10 08:45:18 -070094 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
95 const GrProcOptInfo& coveragePOI,
96 bool doesStencilWrite,
97 GrColor* overrideColor,
98 const GrDrawTargetCaps& caps) override;
99
jvanverthcfc18862015-04-28 08:48:20 -0700100 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700101
102 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
egdaniel3ad65702015-02-17 11:15:47 -0800103 if (!this->willReadDstColor()) {
104 blendInfo->fSrcBlend = fSrcBlend;
105 blendInfo->fDstBlend = fDstBlend;
106 } else {
107 blendInfo->fSrcBlend = kOne_GrBlendCoeff;
108 blendInfo->fDstBlend = kZero_GrBlendCoeff;
109 }
egdaniel41d4f092015-02-09 07:51:00 -0800110 blendInfo->fBlendConstant = fBlendConstant;
111 }
112
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
egdaniel29bee0f2015-04-29 11:54:42 -0700143bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff,
egdaniel3ad65702015-02-17 11:15:47 -0800144 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
jvanverthcfc18862015-04-28 08:48:20 -0700193 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
bsalomon50785a32015-02-06 07:02:37 -0800194 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>();
egdaniel29bee0f2015-04-29 11:54:42 -0700207 GrGLXPFragmentBuilder* 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
jvanverthcfc18862015-04-28 08:48:20 -0700294void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
egdaniel41d4f092015-02-09 07:51:00 -0800295 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
egdanielc19cdc22015-05-10 08:45:18 -0700304PorterDuffXferProcessor::onGetOptimizations(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) {
jvanverthe9c0fc62015-04-29 11:18:05 -0700354 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
egdanielc2304142014-12-11 13:15:13 -0800355 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;
egdaniel7dfc27c2015-05-08 12:48:35 -0700409 return GrXferProcessor::kNone_Opt |
410 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800411 } else if (kZero_GrBlendCoeff == fSrcBlend) {
412 // if the op is "clear" then we don't need to emit a color
413 // or blend, just write transparent black into the dst.
414 fSrcBlend = kOne_GrBlendCoeff;
415 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800416 return GrXferProcessor::kIgnoreColor_OptFlag |
417 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800418 }
419 }
egdaniel7dfc27c2015-05-08 12:48:35 -0700420 return GrXferProcessor::kIgnoreCoverage_OptFlag;
421 }
egdanielf7c2d552015-02-13 12:11:00 -0800422
egdaniel7dfc27c2015-05-08 12:48:35 -0700423 // check whether coverage can be safely rolled into alpha
424 // of if we can skip color computation and just emit coverage
425 if (can_tweak_alpha_for_coverage(fDstBlend)) {
426 if (colorPOI.allStagesMultiplyInput()) {
427 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
428 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
429 } else {
egdaniel95131432014-12-09 11:15:43 -0800430 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
egdaniel7dfc27c2015-05-08 12:48:35 -0700431
egdaniel95131432014-12-09 11:15:43 -0800432 }
433 }
egdaniel7dfc27c2015-05-08 12:48:35 -0700434 if (dstCoeffIsZero) {
435 if (kZero_GrBlendCoeff == fSrcBlend) {
436 // the source color is not included in the blend
437 // the dst coeff is effectively zero so blend works out to:
438 // (c)(0)D + (1-c)D = (1-c)D.
439 fDstBlend = kISA_GrBlendCoeff;
440 return GrXferProcessor::kIgnoreColor_OptFlag |
441 GrXferProcessor::kSetCoverageDrawing_OptFlag;
442 } else if (srcAIsOne) {
443 // the dst coeff is effectively zero so blend works out to:
444 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
445 // If Sa is 1 then we can replace Sa with c
446 // and set dst coeff to 1-Sa.
447 fDstBlend = kISA_GrBlendCoeff;
448 if (colorPOI.allStagesMultiplyInput()) {
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
451 } else {
452 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
453
454 }
455 }
456 } else if (dstCoeffIsOne) {
457 // the dst coeff is effectively one so blend works out to:
458 // cS + (c)(1)D + (1-c)D = cS + D.
459 fDstBlend = kOne_GrBlendCoeff;
460 if (colorPOI.allStagesMultiplyInput()) {
461 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
462 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
463 } else {
464 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
465
466 }
467 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
468 }
egdaniel95131432014-12-09 11:15:43 -0800469
470 return GrXferProcessor::kNone_Opt;
471}
egdanielc2304142014-12-11 13:15:13 -0800472
egdaniel41d4f092015-02-09 07:51:00 -0800473bool PorterDuffXferProcessor::hasSecondaryOutput() const {
egdanielc2304142014-12-11 13:15:13 -0800474 return kNone_SecondaryOutputType != fSecondaryOutputType;
475}
476
egdaniel378092f2014-12-03 10:40:13 -0800477///////////////////////////////////////////////////////////////////////////////
478
egdaniel915187b2014-12-05 12:58:28 -0800479GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800480 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800481 this->initClassID<GrPorterDuffXPFactory>();
482}
483
egdanielc016fb82014-12-03 11:41:54 -0800484GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
485 switch (mode) {
486 case SkXfermode::kClear_Mode: {
487 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
488 return SkRef(&gClearPDXPF);
489 break;
490 }
491 case SkXfermode::kSrc_Mode: {
492 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
493 return SkRef(&gSrcPDXPF);
494 break;
495 }
496 case SkXfermode::kDst_Mode: {
497 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
498 return SkRef(&gDstPDXPF);
499 break;
500 }
501 case SkXfermode::kSrcOver_Mode: {
502 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
503 return SkRef(&gSrcOverPDXPF);
504 break;
505 }
506 case SkXfermode::kDstOver_Mode: {
507 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
508 return SkRef(&gDstOverPDXPF);
509 break;
510 }
511 case SkXfermode::kSrcIn_Mode: {
512 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
513 return SkRef(&gSrcInPDXPF);
514 break;
515 }
516 case SkXfermode::kDstIn_Mode: {
517 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
518 return SkRef(&gDstInPDXPF);
519 break;
520 }
521 case SkXfermode::kSrcOut_Mode: {
522 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
523 return SkRef(&gSrcOutPDXPF);
524 break;
525 }
526 case SkXfermode::kDstOut_Mode: {
527 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
528 return SkRef(&gDstOutPDXPF);
529 break;
530 }
531 case SkXfermode::kSrcATop_Mode: {
532 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
533 return SkRef(&gSrcATopPDXPF);
534 break;
535 }
536 case SkXfermode::kDstATop_Mode: {
537 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
538 return SkRef(&gDstATopPDXPF);
539 break;
540 }
541 case SkXfermode::kXor_Mode: {
542 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
543 return SkRef(&gXorPDXPF);
544 break;
545 }
546 case SkXfermode::kPlus_Mode: {
547 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
548 return SkRef(&gPlusPDXPF);
549 break;
550 }
551 case SkXfermode::kModulate_Mode: {
552 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
553 return SkRef(&gModulatePDXPF);
554 break;
555 }
556 case SkXfermode::kScreen_Mode: {
557 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
558 return SkRef(&gScreenPDXPF);
559 break;
560 }
561 default:
562 return NULL;
563 }
564}
565
bsalomon50785a32015-02-06 07:02:37 -0800566GrXferProcessor*
egdaniel3ad65702015-02-17 11:15:47 -0800567GrPorterDuffXPFactory::onCreateXferProcessor(const GrDrawTargetCaps& caps,
568 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800569 const GrProcOptInfo& covPOI,
570 const GrDeviceCoordTexture* dstCopy) const {
egdaniel95131432014-12-09 11:15:43 -0800571 if (!covPOI.isFourChannelOutput()) {
egdaniel41d4f092015-02-09 07:51:00 -0800572 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
egdaniel3ad65702015-02-17 11:15:47 -0800573 this->willReadDstColor(caps, colorPOI, covPOI));
egdaniel95131432014-12-09 11:15:43 -0800574 } else {
575 if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
576 SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
577 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
egdaniel41d4f092015-02-09 07:51:00 -0800578 return PorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
579 blendConstant, dstCopy,
egdaniel3ad65702015-02-17 11:15:47 -0800580 this->willReadDstColor(caps, colorPOI, covPOI));
egdaniel95131432014-12-09 11:15:43 -0800581 } else {
582 return NULL;
583 }
584 }
egdaniel378092f2014-12-03 10:40:13 -0800585}
586
587bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
588 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800589 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800590 kRGBA_GrColorComponentFlags == knownColorFlags) {
591 return true;
592 }
593 return false;
594}
595
egdaniel9e4ecdc2014-12-18 12:44:55 -0800596void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
597 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800598 GrXPFactory::InvariantOutput* output) const {
egdaniel95131432014-12-09 11:15:43 -0800599 if (!coveragePOI.isSolidWhite()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800600 output->fWillBlendWithDst = true;
601 output->fBlendedColorFlags = 0;
602 return;
egdaniel95131432014-12-09 11:15:43 -0800603 }
604
egdaniel95131432014-12-09 11:15:43 -0800605 GrBlendCoeff srcCoeff = fSrcCoeff;
606 GrBlendCoeff dstCoeff = fDstCoeff;
607
608 // TODO: figure out to merge this simplify with other current optimization code paths and
609 // eventually remove from GrBlend
610 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
611 0, 0, 0);
612
egdaniel9e4ecdc2014-12-18 12:44:55 -0800613 if (GrBlendCoeffRefsDst(srcCoeff)) {
614 output->fWillBlendWithDst = true;
615 output->fBlendedColorFlags = 0;
616 return;
egdaniel95131432014-12-09 11:15:43 -0800617 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800618
619 if (kZero_GrBlendCoeff != dstCoeff) {
620 bool srcAIsOne = colorPOI.isOpaque();
621 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
622 output->fWillBlendWithDst = true;
623 }
624 output->fBlendedColorFlags = 0;
625 return;
626 }
627
628 switch (srcCoeff) {
629 case kZero_GrBlendCoeff:
630 output->fBlendedColor = 0;
631 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
632 break;
633
634 case kOne_GrBlendCoeff:
635 output->fBlendedColor = colorPOI.color();
636 output->fBlendedColorFlags = colorPOI.validFlags();
637 break;
638
639 // The src coeff should never refer to the src and if it refers to dst then opaque
640 // should have been false.
641 case kSC_GrBlendCoeff:
642 case kISC_GrBlendCoeff:
643 case kDC_GrBlendCoeff:
644 case kIDC_GrBlendCoeff:
645 case kSA_GrBlendCoeff:
646 case kISA_GrBlendCoeff:
647 case kDA_GrBlendCoeff:
648 case kIDA_GrBlendCoeff:
649 default:
650 SkFAIL("srcCoeff should not refer to src or dst.");
651 break;
652
653 // TODO: update this once GrPaint actually has a const color.
654 case kConstC_GrBlendCoeff:
655 case kIConstC_GrBlendCoeff:
656 case kConstA_GrBlendCoeff:
657 case kIConstA_GrBlendCoeff:
658 output->fBlendedColorFlags = 0;
659 break;
660 }
661
egdaniel9e4ecdc2014-12-18 12:44:55 -0800662 output->fWillBlendWithDst = false;
egdaniel95131432014-12-09 11:15:43 -0800663}
664
egdaniel3ad65702015-02-17 11:15:47 -0800665bool GrPorterDuffXPFactory::willReadDstColor(const GrDrawTargetCaps& caps,
666 const GrProcOptInfo& colorPOI,
egdaniele36914c2015-02-13 09:00:33 -0800667 const GrProcOptInfo& coveragePOI) const {
egdaniel3ad65702015-02-17 11:15:47 -0800668 // We can always blend correctly if we have dual source blending.
jvanverthe9c0fc62015-04-29 11:18:05 -0700669 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
egdaniel3ad65702015-02-17 11:15:47 -0800670 return false;
671 }
672
egdaniel99bc9fd2015-05-04 12:58:16 -0700673 if (can_tweak_alpha_for_coverage(fDstCoeff)) {
egdaniel3ad65702015-02-17 11:15:47 -0800674 return false;
675 }
676
677 bool srcAIsOne = colorPOI.isOpaque();
678
679 if (kZero_GrBlendCoeff == fDstCoeff) {
680 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
681 return false;
682 }
683 }
684
685 // Reduces to: coeffS * (Cov*S) + D
686 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
687 return false;
688 }
689
690 // We can always blend correctly if we have solid coverage.
691 if (coveragePOI.isSolidWhite()) {
692 return false;
693 }
694
695 return true;
bsalomon50785a32015-02-06 07:02:37 -0800696}
697
egdanielc2304142014-12-11 13:15:13 -0800698GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
699
700GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
701 GrContext*,
702 const GrDrawTargetCaps&,
703 GrTexture*[]) {
egdanielb197b8f2015-02-17 07:34:43 -0800704 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
705 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800706}
egdaniel95131432014-12-09 11:15:43 -0800707