blob: 43cdc400ccdf8af0296c45d9da80772817fbf43f [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"
bsalomoneb1cb5c2015-05-22 08:01:09 -070011#include "GrCaps.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,
bsalomon4b91f762015-05-19 09:29:46 -070098 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -070099
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
bsalomon4b91f762015-05-19 09:29:46 -0700129 void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrCaps& caps,
egdaniel41d4f092015-02-09 07:51:00 -0800130 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,
bsalomon4b91f762015-05-19 09:29:46 -0700308 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700309 GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI,
310 coveragePOI,
311 doesStencilWrite);
egdaniel71e236c2015-01-20 06:34:51 -0800312 this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
egdanielc2304142014-12-11 13:15:13 -0800313 return optFlags;
314}
315
egdaniel41d4f092015-02-09 07:51:00 -0800316void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
bsalomon4b91f762015-05-19 09:29:46 -0700317 const GrCaps& caps,
egdaniel41d4f092015-02-09 07:51:00 -0800318 bool hasSolidCoverage) {
egdaniel3ad65702015-02-17 11:15:47 -0800319 if (this->willReadDstColor()) {
320 fPrimaryOutputType = kCustom_PrimaryOutputType;
321 return;
322 }
323
joshualitt9b989322014-12-15 14:16:27 -0800324 if (optFlags & kIgnoreColor_OptFlag) {
325 if (optFlags & kIgnoreCoverage_OptFlag) {
326 fPrimaryOutputType = kNone_PrimaryOutputType;
327 return;
328 } else {
329 fPrimaryOutputType = kCoverage_PrimaryOutputType;
330 return;
331 }
332 } else if (optFlags & kIgnoreCoverage_OptFlag) {
333 fPrimaryOutputType = kColor_PrimaryOutputType;
334 return;
335 }
336
egdanielc2304142014-12-11 13:15:13 -0800337 // If we do have coverage determine whether it matters. Dual source blending is expensive so
338 // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
339 // blending if we have any effective coverage stages OR the geometry processor doesn't emits
340 // solid coverage.
341 if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
jvanverthe9c0fc62015-04-29 11:18:05 -0700342 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
egdanielc2304142014-12-11 13:15:13 -0800343 if (kZero_GrBlendCoeff == fDstBlend) {
344 // write the coverage value to second color
345 fSecondaryOutputType = kCoverage_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800346 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800347 } else if (kSA_GrBlendCoeff == fDstBlend) {
348 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
349 fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800350 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800351 } else if (kSC_GrBlendCoeff == fDstBlend) {
352 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
353 fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
egdanielb197b8f2015-02-17 07:34:43 -0800354 fDstBlend = kIS2C_GrBlendCoeff;
egdanielc2304142014-12-11 13:15:13 -0800355 }
egdanielc2304142014-12-11 13:15:13 -0800356 }
357 }
358}
359
360GrXferProcessor::OptFlags
egdaniel41d4f092015-02-09 07:51:00 -0800361PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
362 const GrProcOptInfo& coveragePOI,
363 bool doesStencilWrite) {
egdaniel3ad65702015-02-17 11:15:47 -0800364 if (this->willReadDstColor()) {
365 return GrXferProcessor::kNone_Opt;
366 }
egdaniel87509242014-12-17 13:37:13 -0800367
egdaniel3ad65702015-02-17 11:15:47 -0800368 bool srcAIsOne = colorPOI.isOpaque();
369 bool hasCoverage = !coveragePOI.isSolidWhite();
egdaniel95131432014-12-09 11:15:43 -0800370
371 bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
372 (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
374 (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
375
egdaniel95131432014-12-09 11:15:43 -0800376 // When coeffs are (0,1) there is no reason to draw at all, unless
377 // stenciling is enabled. Having color writes disabled is effectively
378 // (0,1).
379 if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
380 if (doesStencilWrite) {
joshualitt9b989322014-12-15 14:16:27 -0800381 return GrXferProcessor::kIgnoreColor_OptFlag |
egdaniel95131432014-12-09 11:15:43 -0800382 GrXferProcessor::kSetCoverageDrawing_OptFlag;
383 } else {
384 fDstBlend = kOne_GrBlendCoeff;
385 return GrXferProcessor::kSkipDraw_OptFlag;
386 }
387 }
388
389 // if we don't have coverage we can check whether the dst
390 // has to read at all. If not, we'll disable blending.
391 if (!hasCoverage) {
392 if (dstCoeffIsZero) {
393 if (kOne_GrBlendCoeff == fSrcBlend) {
394 // if there is no coverage and coeffs are (1,0) then we
395 // won't need to read the dst at all, it gets replaced by src
396 fDstBlend = kZero_GrBlendCoeff;
egdaniel7dfc27c2015-05-08 12:48:35 -0700397 return GrXferProcessor::kNone_Opt |
398 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800399 } else if (kZero_GrBlendCoeff == fSrcBlend) {
400 // if the op is "clear" then we don't need to emit a color
401 // or blend, just write transparent black into the dst.
402 fSrcBlend = kOne_GrBlendCoeff;
403 fDstBlend = kZero_GrBlendCoeff;
joshualitt9b989322014-12-15 14:16:27 -0800404 return GrXferProcessor::kIgnoreColor_OptFlag |
405 GrXferProcessor::kIgnoreCoverage_OptFlag;
egdaniel95131432014-12-09 11:15:43 -0800406 }
407 }
egdaniel7dfc27c2015-05-08 12:48:35 -0700408 return GrXferProcessor::kIgnoreCoverage_OptFlag;
409 }
egdanielf7c2d552015-02-13 12:11:00 -0800410
egdaniel7dfc27c2015-05-08 12:48:35 -0700411 // check whether coverage can be safely rolled into alpha
412 // of if we can skip color computation and just emit coverage
413 if (can_tweak_alpha_for_coverage(fDstBlend)) {
414 if (colorPOI.allStagesMultiplyInput()) {
415 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
416 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
417 } else {
egdaniel95131432014-12-09 11:15:43 -0800418 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
egdaniel7dfc27c2015-05-08 12:48:35 -0700419
egdaniel95131432014-12-09 11:15:43 -0800420 }
421 }
egdaniel7dfc27c2015-05-08 12:48:35 -0700422 if (dstCoeffIsZero) {
423 if (kZero_GrBlendCoeff == fSrcBlend) {
424 // the source color is not included in the blend
425 // the dst coeff is effectively zero so blend works out to:
426 // (c)(0)D + (1-c)D = (1-c)D.
427 fDstBlend = kISA_GrBlendCoeff;
428 return GrXferProcessor::kIgnoreColor_OptFlag |
429 GrXferProcessor::kSetCoverageDrawing_OptFlag;
430 } else if (srcAIsOne) {
431 // the dst coeff is effectively zero so blend works out to:
432 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
433 // If Sa is 1 then we can replace Sa with c
434 // and set dst coeff to 1-Sa.
435 fDstBlend = kISA_GrBlendCoeff;
436 if (colorPOI.allStagesMultiplyInput()) {
437 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
439 } else {
440 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
441
442 }
443 }
444 } else if (dstCoeffIsOne) {
445 // the dst coeff is effectively one so blend works out to:
446 // cS + (c)(1)D + (1-c)D = cS + D.
447 fDstBlend = kOne_GrBlendCoeff;
448 if (colorPOI.allStagesMultiplyInput()) {
449 return GrXferProcessor::kSetCoverageDrawing_OptFlag |
450 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
451 } else {
452 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
453
454 }
455 return GrXferProcessor::kSetCoverageDrawing_OptFlag;
456 }
egdaniel95131432014-12-09 11:15:43 -0800457
458 return GrXferProcessor::kNone_Opt;
459}
egdanielc2304142014-12-11 13:15:13 -0800460
egdaniel41d4f092015-02-09 07:51:00 -0800461bool PorterDuffXferProcessor::hasSecondaryOutput() const {
egdanielc2304142014-12-11 13:15:13 -0800462 return kNone_SecondaryOutputType != fSecondaryOutputType;
463}
464
egdaniel378092f2014-12-03 10:40:13 -0800465///////////////////////////////////////////////////////////////////////////////
466
egdaniel0d5fd112015-05-12 06:11:35 -0700467class PDLCDXferProcessor : public GrXferProcessor {
468public:
469 static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
470 const GrProcOptInfo& colorPOI);
471
472 ~PDLCDXferProcessor() override;
473
474 const char* name() const override { return "Porter Duff LCD"; }
475
476 GrGLXferProcessor* createGLInstance() const override;
477
478 bool hasSecondaryOutput() const override { return false; }
479
480private:
481 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
482
483 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
484 const GrProcOptInfo& coveragePOI,
485 bool doesStencilWrite,
486 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700487 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700488
489 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
490
491 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
492 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
493 blendInfo->fDstBlend = kISC_GrBlendCoeff;
494 blendInfo->fBlendConstant = fBlendConstant;
495 }
496
497 bool onIsEqual(const GrXferProcessor& xpBase) const override {
498 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
499 if (fBlendConstant != xp.fBlendConstant ||
500 fAlpha != xp.fAlpha) {
501 return false;
502 }
503 return true;
504 }
505
506 GrColor fBlendConstant;
507 uint8_t fAlpha;
508
509 typedef GrXferProcessor INHERITED;
510};
511
512///////////////////////////////////////////////////////////////////////////////
513
514class GLPDLCDXferProcessor : public GrGLXferProcessor {
515public:
516 GLPDLCDXferProcessor(const GrProcessor&) {}
517
518 virtual ~GLPDLCDXferProcessor() {}
519
520 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
521 GrProcessorKeyBuilder* b) {}
522
523private:
524 void onEmitCode(const EmitArgs& args) override {
525 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
526
527 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
528 args.fInputCoverage);
529 }
530
531 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
532
533 typedef GrGLXferProcessor INHERITED;
534};
535
536///////////////////////////////////////////////////////////////////////////////
537
538PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
539 : fBlendConstant(blendConstant)
540 , fAlpha(alpha) {
541 this->initClassID<PDLCDXferProcessor>();
542}
543
544GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
545 const GrProcOptInfo& colorPOI) {
546 if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) {
547 return NULL;
548 }
549
550 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
551 return NULL;
552 }
553
554 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
555 uint8_t alpha = GrColorUnpackA(blendConstant);
556 blendConstant |= (0xff << GrColor_SHIFT_A);
557
558 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha));
559}
560
561PDLCDXferProcessor::~PDLCDXferProcessor() {
562}
563
564void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
565 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700566 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700567}
568
569GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
570 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
571}
572
573GrXferProcessor::OptFlags
574PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
575 const GrProcOptInfo& coveragePOI,
576 bool doesStencilWrite,
577 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700578 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700579 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
580 // value of the blend the constant. We should already have valid blend coeff's if we are at
581 // a point where we have RGB coverage. We don't need any color stages since the known color
582 // output is already baked into the blendConstant.
583 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
584 return GrXferProcessor::kOverrideColor_OptFlag;
585}
586
587///////////////////////////////////////////////////////////////////////////////
egdaniel915187b2014-12-05 12:58:28 -0800588GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
egdaniel95131432014-12-09 11:15:43 -0800589 : fSrcCoeff(src), fDstCoeff(dst) {
egdaniel915187b2014-12-05 12:58:28 -0800590 this->initClassID<GrPorterDuffXPFactory>();
591}
592
egdanielc016fb82014-12-03 11:41:54 -0800593GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
594 switch (mode) {
595 case SkXfermode::kClear_Mode: {
596 static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
597 return SkRef(&gClearPDXPF);
598 break;
599 }
600 case SkXfermode::kSrc_Mode: {
601 static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
602 return SkRef(&gSrcPDXPF);
603 break;
604 }
605 case SkXfermode::kDst_Mode: {
606 static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
607 return SkRef(&gDstPDXPF);
608 break;
609 }
610 case SkXfermode::kSrcOver_Mode: {
611 static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
612 return SkRef(&gSrcOverPDXPF);
613 break;
614 }
615 case SkXfermode::kDstOver_Mode: {
616 static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
617 return SkRef(&gDstOverPDXPF);
618 break;
619 }
620 case SkXfermode::kSrcIn_Mode: {
621 static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
622 return SkRef(&gSrcInPDXPF);
623 break;
624 }
625 case SkXfermode::kDstIn_Mode: {
626 static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
627 return SkRef(&gDstInPDXPF);
628 break;
629 }
630 case SkXfermode::kSrcOut_Mode: {
631 static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
632 return SkRef(&gSrcOutPDXPF);
633 break;
634 }
635 case SkXfermode::kDstOut_Mode: {
636 static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
637 return SkRef(&gDstOutPDXPF);
638 break;
639 }
640 case SkXfermode::kSrcATop_Mode: {
641 static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
642 return SkRef(&gSrcATopPDXPF);
643 break;
644 }
645 case SkXfermode::kDstATop_Mode: {
646 static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
647 return SkRef(&gDstATopPDXPF);
648 break;
649 }
650 case SkXfermode::kXor_Mode: {
651 static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
652 return SkRef(&gXorPDXPF);
653 break;
654 }
655 case SkXfermode::kPlus_Mode: {
656 static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
657 return SkRef(&gPlusPDXPF);
658 break;
659 }
660 case SkXfermode::kModulate_Mode: {
661 static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
662 return SkRef(&gModulatePDXPF);
663 break;
664 }
665 case SkXfermode::kScreen_Mode: {
666 static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
667 return SkRef(&gScreenPDXPF);
668 break;
669 }
670 default:
671 return NULL;
672 }
673}
674
bsalomon50785a32015-02-06 07:02:37 -0800675GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700676GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800677 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800678 const GrProcOptInfo& covPOI,
679 const GrDeviceCoordTexture* dstCopy) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700680 if (covPOI.isFourChannelOutput()) {
681 return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI);
682 } else {
egdaniel41d4f092015-02-09 07:51:00 -0800683 return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstCopy,
egdaniel3ad65702015-02-17 11:15:47 -0800684 this->willReadDstColor(caps, colorPOI, covPOI));
egdaniel95131432014-12-09 11:15:43 -0800685 }
egdaniel378092f2014-12-03 10:40:13 -0800686}
687
688bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
689 uint32_t knownColorFlags) const {
egdaniel95131432014-12-09 11:15:43 -0800690 if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
egdaniel378092f2014-12-03 10:40:13 -0800691 kRGBA_GrColorComponentFlags == knownColorFlags) {
692 return true;
693 }
694 return false;
695}
696
egdaniel9e4ecdc2014-12-18 12:44:55 -0800697void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
698 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800699 GrXPFactory::InvariantOutput* output) const {
egdaniel95131432014-12-09 11:15:43 -0800700 if (!coveragePOI.isSolidWhite()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800701 output->fWillBlendWithDst = true;
702 output->fBlendedColorFlags = 0;
703 return;
egdaniel95131432014-12-09 11:15:43 -0800704 }
705
egdaniel95131432014-12-09 11:15:43 -0800706 GrBlendCoeff srcCoeff = fSrcCoeff;
707 GrBlendCoeff dstCoeff = fDstCoeff;
708
709 // TODO: figure out to merge this simplify with other current optimization code paths and
710 // eventually remove from GrBlend
711 GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
712 0, 0, 0);
713
egdaniel9e4ecdc2014-12-18 12:44:55 -0800714 if (GrBlendCoeffRefsDst(srcCoeff)) {
715 output->fWillBlendWithDst = true;
716 output->fBlendedColorFlags = 0;
717 return;
egdaniel95131432014-12-09 11:15:43 -0800718 }
egdaniel9e4ecdc2014-12-18 12:44:55 -0800719
720 if (kZero_GrBlendCoeff != dstCoeff) {
721 bool srcAIsOne = colorPOI.isOpaque();
722 if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
723 output->fWillBlendWithDst = true;
724 }
725 output->fBlendedColorFlags = 0;
726 return;
727 }
728
729 switch (srcCoeff) {
730 case kZero_GrBlendCoeff:
731 output->fBlendedColor = 0;
732 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
733 break;
734
735 case kOne_GrBlendCoeff:
736 output->fBlendedColor = colorPOI.color();
737 output->fBlendedColorFlags = colorPOI.validFlags();
738 break;
739
740 // The src coeff should never refer to the src and if it refers to dst then opaque
741 // should have been false.
742 case kSC_GrBlendCoeff:
743 case kISC_GrBlendCoeff:
744 case kDC_GrBlendCoeff:
745 case kIDC_GrBlendCoeff:
746 case kSA_GrBlendCoeff:
747 case kISA_GrBlendCoeff:
748 case kDA_GrBlendCoeff:
749 case kIDA_GrBlendCoeff:
750 default:
751 SkFAIL("srcCoeff should not refer to src or dst.");
752 break;
753
754 // TODO: update this once GrPaint actually has a const color.
755 case kConstC_GrBlendCoeff:
756 case kIConstC_GrBlendCoeff:
757 case kConstA_GrBlendCoeff:
758 case kIConstA_GrBlendCoeff:
759 output->fBlendedColorFlags = 0;
760 break;
761 }
762
egdaniel9e4ecdc2014-12-18 12:44:55 -0800763 output->fWillBlendWithDst = false;
egdaniel95131432014-12-09 11:15:43 -0800764}
765
bsalomon4b91f762015-05-19 09:29:46 -0700766bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800767 const GrProcOptInfo& colorPOI,
egdaniele36914c2015-02-13 09:00:33 -0800768 const GrProcOptInfo& coveragePOI) const {
egdaniel3ad65702015-02-17 11:15:47 -0800769 // We can always blend correctly if we have dual source blending.
jvanverthe9c0fc62015-04-29 11:18:05 -0700770 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
egdaniel3ad65702015-02-17 11:15:47 -0800771 return false;
772 }
773
egdaniel99bc9fd2015-05-04 12:58:16 -0700774 if (can_tweak_alpha_for_coverage(fDstCoeff)) {
egdaniel3ad65702015-02-17 11:15:47 -0800775 return false;
776 }
777
778 bool srcAIsOne = colorPOI.isOpaque();
779
780 if (kZero_GrBlendCoeff == fDstCoeff) {
781 if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
782 return false;
783 }
784 }
785
786 // Reduces to: coeffS * (Cov*S) + D
787 if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
788 return false;
789 }
790
791 // We can always blend correctly if we have solid coverage.
792 if (coveragePOI.isSolidWhite()) {
793 return false;
794 }
795
796 return true;
bsalomon50785a32015-02-06 07:02:37 -0800797}
798
egdanielc2304142014-12-11 13:15:13 -0800799GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
800
801GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
802 GrContext*,
bsalomon4b91f762015-05-19 09:29:46 -0700803 const GrCaps&,
egdanielc2304142014-12-11 13:15:13 -0800804 GrTexture*[]) {
egdanielb197b8f2015-02-17 07:34:43 -0800805 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
806 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800807}
egdaniel95131432014-12-09 11:15:43 -0800808