blob: ff857f4e0df62b72f4275c0b65526765da194ab4 [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"
wangyixcef14bf2015-07-24 13:48:26 -070016#include "gl/GrGLBlend.h"
egdanielc2304142014-12-11 13:15:13 -080017#include "gl/GrGLXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080018#include "gl/builders/GrGLFragmentShaderBuilder.h"
19#include "gl/builders/GrGLProgramBuilder.h"
20
cdalton6fd158e2015-05-27 15:08:33 -070021/**
22 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
23 */
24struct BlendFormula {
25public:
26 /**
27 * Values the shader can write to primary and secondary outputs. These must all be modulated by
28 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080029 */
cdalton6fd158e2015-05-27 15:08:33 -070030 enum OutputType {
31 kNone_OutputType, //<! 0
32 kCoverage_OutputType, //<! inputCoverage
33 kModulate_OutputType, //<! inputColor * inputCoverage
34 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
35 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
36
37 kLast_OutputType = kISCModulate_OutputType
38 };
39
40 enum Properties {
41 kModifiesDst_Property = 1,
42 kUsesDstColor_Property = 1 << 1,
43 kUsesInputColor_Property = 1 << 2,
44 kCanTweakAlphaForCoverage_Property = 1 << 3,
45
46 kLast_Property = kCanTweakAlphaForCoverage_Property
47 };
48
49 BlendFormula& operator =(const BlendFormula& other) {
50 fData = other.fData;
51 return *this;
52 }
53
54 bool operator ==(const BlendFormula& other) const {
55 return fData == other.fData;
56 }
57
58 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
59 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
60 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
61 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
62 bool canTweakAlphaForCoverage() const {
63 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
64 }
65
66 /**
67 * Deduce the properties of a compile-time constant BlendFormula.
68 */
69 template<OutputType PrimaryOut, OutputType SecondaryOut,
70 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
71 struct get_properties : SkTIntegralConstant<Properties, static_cast<Properties>(
72
73 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
74 kModifiesDst_Property : 0) |
75
76 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
77 kUsesDstColor_Property : 0) |
78
79 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
80 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
81 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
82
83 (kModulate_OutputType == PrimaryOut &&
84 kNone_OutputType == SecondaryOut &&
85 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
86 kCanTweakAlphaForCoverage_Property : 0))> {
87
88 // The provided formula should already be optimized.
89 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
90 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
91 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
92 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
93 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
94 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
95 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
96 };
97
98 union {
99 struct {
100 // We allot the enums one more bit than they require because MSVC seems to sign-extend
101 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
102 OutputType fPrimaryOutputType : 4;
103 OutputType fSecondaryOutputType : 4;
104 GrBlendEquation fBlendEquation : 6;
105 GrBlendCoeff fSrcCoeff : 6;
106 GrBlendCoeff fDstCoeff : 6;
107 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
108 };
109 uint32_t fData;
110 };
111
112 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
113 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
114 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
115 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
116};
117
118GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
119
120GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
121
122/**
123 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
124 */
125#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
126 {{{PRIMARY_OUT, \
127 SECONDARY_OUT, \
128 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
129 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
130 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
131
132/**
133 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
134 * Porter Duff formula.
135 */
136#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
137 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
138 BlendFormula::kNone_OutputType, \
139 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
140
141/**
142 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
143 * the primary output type to none.
144 */
145#define DST_CLEAR_FORMULA \
146 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
147 BlendFormula::kNone_OutputType, \
148 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
149
150/**
151 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
152 * so we can set the primary output type to none.
153 */
154#define NO_DST_WRITE_FORMULA \
155 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
156 BlendFormula::kNone_OutputType, \
157 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
158
159/**
160 * When there is coverage, the equation with f=coverage is:
161 *
162 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
163 *
164 * This can be rewritten as:
165 *
166 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
167 *
168 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
169 * HW dst coeff with IS2C.
170 *
171 * Xfer modes: dst-atop (Sa!=1)
172 */
173#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
174 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
175 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
176 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
177
178/**
179 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
180 *
181 * D' = f * D * dstCoeff + (1-f) * D
182 *
183 * This can be rewritten as:
184 *
185 * D' = D - D * [f * (1 - dstCoeff)]
186 *
187 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
188 * subtract HW blend equation with coeffs of (DC, One).
189 *
190 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
191 */
192#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
193 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
194 BlendFormula::kNone_OutputType, \
195 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
196
197/**
198 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
199 *
200 * D' = f * S * srcCoeff + (1-f) * D
201 *
202 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
203 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
204 *
205 * Xfer modes (Sa!=1): src, src-in, src-out
206 */
207#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
208 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
209 BlendFormula::kCoverage_OutputType, \
210 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
211
212/**
213 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
214 * with and without an opaque input color. Optimization properties are deduced at compile time so we
215 * can make runtime decisions quickly. RGB coverage is not supported.
216 */
217static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
218
219 /*>> No coverage, input color unknown <<*/ {{
220
221 /* clear */ DST_CLEAR_FORMULA,
222 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
223 /* dst */ NO_DST_WRITE_FORMULA,
224 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
225 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
226 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
227 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
228 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
229 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
230 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
231 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
232 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
233 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
234 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
235 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
236
237 }, /*>> Has coverage, input color unknown <<*/ {
238
239 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
240 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
241 /* dst */ NO_DST_WRITE_FORMULA,
242 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
243 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
244 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
245 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
246 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
247 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
248 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
249 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
250 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
251 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
252 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
253 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
254
255 }}, /*>> No coverage, input color opaque <<*/ {{
256
257 /* clear */ DST_CLEAR_FORMULA,
258 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
259 /* dst */ NO_DST_WRITE_FORMULA,
260 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
261 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
262 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
263 /* dst-in */ NO_DST_WRITE_FORMULA,
264 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
265 /* dst-out */ DST_CLEAR_FORMULA,
266 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
267 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
268 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
269 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
270 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
271 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
272
273 }, /*>> Has coverage, input color opaque <<*/ {
274
275 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
276 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
277 /* dst */ NO_DST_WRITE_FORMULA,
278 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
279 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
280 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
281 /* dst-in */ NO_DST_WRITE_FORMULA,
282 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
283 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
284 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
285 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
286 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
287 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
288 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
289 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
290}}};
291
cdalton86ae0a92015-06-08 15:11:04 -0700292static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
293 const GrProcOptInfo& coveragePOI,
294 bool hasMixedSamples,
295 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700296 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
297 SkASSERT(!coveragePOI.isFourChannelOutput());
298
cdalton86ae0a92015-06-08 15:11:04 -0700299 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
300 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800301}
302
cdalton6fd158e2015-05-27 15:08:33 -0700303///////////////////////////////////////////////////////////////////////////////
304
egdaniel41d4f092015-02-09 07:51:00 -0800305class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800306public:
cdalton86ae0a92015-06-08 15:11:04 -0700307 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
308 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800309 }
egdaniel378092f2014-12-03 10:40:13 -0800310
mtklein36352bf2015-03-25 18:17:31 -0700311 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800312
mtklein36352bf2015-03-25 18:17:31 -0700313 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800314
cdalton6fd158e2015-05-27 15:08:33 -0700315 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700316
317private:
egdanielc19cdc22015-05-10 08:45:18 -0700318 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
319 const GrProcOptInfo& coveragePOI,
320 bool doesStencilWrite,
321 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700322 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700323
jvanverthcfc18862015-04-28 08:48:20 -0700324 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700325
cdaltonedbb31f2015-06-08 12:14:44 -0700326 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
327
cdaltonf4f2b442015-04-23 09:40:23 -0700328 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700329 blendInfo->fEquation = fBlendFormula.fBlendEquation;
330 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
331 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
332 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800333 }
334
mtklein36352bf2015-03-25 18:17:31 -0700335 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800336 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700337 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800338 }
339
cdalton6fd158e2015-05-27 15:08:33 -0700340 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800341
342 typedef GrXferProcessor INHERITED;
343};
344
345///////////////////////////////////////////////////////////////////////////////
346
cdalton6fd158e2015-05-27 15:08:33 -0700347static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
348 BlendFormula::OutputType outputType, const char* output,
349 const char* inColor, const char* inCoverage) {
350 switch (outputType) {
351 case BlendFormula::kNone_OutputType:
352 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
353 break;
354 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700355 // We can have a coverage formula while not reading coverage if there are mixed samples.
cdalton6fd158e2015-05-27 15:08:33 -0700356 fsBuilder->codeAppendf("%s = %s;",
357 output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
358 break;
359 case BlendFormula::kModulate_OutputType:
360 if (xp.readsCoverage()) {
361 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
362 } else {
363 fsBuilder->codeAppendf("%s = %s;", output, inColor);
364 }
365 break;
366 case BlendFormula::kISAModulate_OutputType:
367 if (xp.readsCoverage()) {
368 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
369 } else {
370 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
371 }
372 break;
373 case BlendFormula::kISCModulate_OutputType:
374 if (xp.readsCoverage()) {
375 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
376 } else {
377 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
378 }
379 break;
380 default:
381 SkFAIL("Unsupported output type.");
382 break;
egdaniel3ad65702015-02-17 11:15:47 -0800383 }
384}
385
egdaniel41d4f092015-02-09 07:51:00 -0800386class GLPorterDuffXferProcessor : public GrGLXferProcessor {
387public:
cdalton6fd158e2015-05-27 15:08:33 -0700388 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800389 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700390 b->add32(SkToInt(xp.readsCoverage()) |
391 (xp.getBlendFormula().fPrimaryOutputType << 1) |
392 (xp.getBlendFormula().fSecondaryOutputType << 4));
393 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800394 };
395
396private:
cdaltonedbb31f2015-06-08 12:14:44 -0700397 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800398 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel29bee0f2015-04-29 11:54:42 -0700399 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
bungemanc33db932015-05-22 17:55:26 -0700400
cdalton6fd158e2015-05-27 15:08:33 -0700401 BlendFormula blendFormula = xp.getBlendFormula();
402 if (blendFormula.hasSecondaryOutput()) {
403 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
404 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800405 }
cdalton6fd158e2015-05-27 15:08:33 -0700406 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
407 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800408 }
409
cdalton6fd158e2015-05-27 15:08:33 -0700410 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800411
egdaniel378092f2014-12-03 10:40:13 -0800412 typedef GrGLXferProcessor INHERITED;
413};
414
415///////////////////////////////////////////////////////////////////////////////
416
cdalton6fd158e2015-05-27 15:08:33 -0700417void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
egdaniel41d4f092015-02-09 07:51:00 -0800418 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700419 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800420}
421
egdaniel41d4f092015-02-09 07:51:00 -0800422GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700423 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800424}
425
egdaniel95131432014-12-09 11:15:43 -0800426GrXferProcessor::OptFlags
egdanielc19cdc22015-05-10 08:45:18 -0700427PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
428 const GrProcOptInfo& coveragePOI,
429 bool doesStencilWrite,
430 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700431 const GrCaps& caps) {
bsalomon7765a472015-07-08 11:26:37 -0700432 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700433 if (!fBlendFormula.modifiesDst()) {
434 if (!doesStencilWrite) {
435 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
436 }
437 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
438 GrXferProcessor::kIgnoreCoverage_OptFlag |
439 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
440 } else {
441 if (!fBlendFormula.usesInputColor()) {
442 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
443 }
444 if (coveragePOI.isSolidWhite()) {
445 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
446 }
447 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
448 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
449 }
450 }
bungemanc33db932015-05-22 17:55:26 -0700451 return optFlags;
452}
453
cdalton6fd158e2015-05-27 15:08:33 -0700454///////////////////////////////////////////////////////////////////////////////
455
456class ShaderPDXferProcessor : public GrXferProcessor {
457public:
cdalton86ae0a92015-06-08 15:11:04 -0700458 ShaderPDXferProcessor(const DstTexture* dstTexture,
459 bool hasMixedSamples,
460 SkXfermode::Mode xfermode)
461 : INHERITED(dstTexture, true, hasMixedSamples)
462 , fXfermode(xfermode) {
463 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700464 }
465
cdalton6fd158e2015-05-27 15:08:33 -0700466 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700467
468 GrGLXferProcessor* createGLInstance() const override;
469
470 SkXfermode::Mode getXfermode() const { return fXfermode; }
471
472private:
cdalton6fd158e2015-05-27 15:08:33 -0700473 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
474 bool, GrColor*, const GrCaps&) override {
bsalomon7765a472015-07-08 11:26:37 -0700475 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700476 }
477
478 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
479
480 bool onIsEqual(const GrXferProcessor& xpBase) const override {
481 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
482 return fXfermode == xp.fXfermode;
483 }
484
485 const SkXfermode::Mode fXfermode;
486
487 typedef GrXferProcessor INHERITED;
488};
489
490///////////////////////////////////////////////////////////////////////////////
491
cdalton6fd158e2015-05-27 15:08:33 -0700492class GLShaderPDXferProcessor : public GrGLXferProcessor {
493public:
494 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
495 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
496 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800497 }
egdaniel87509242014-12-17 13:37:13 -0800498
cdalton6fd158e2015-05-27 15:08:33 -0700499private:
cdaltonedbb31f2015-06-08 12:14:44 -0700500 void emitBlendCodeForDstRead(GrGLXPBuilder* pb, const char* srcColor, const char* dstColor,
501 const char* outColor, const GrXferProcessor& proc) override {
502 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
503 GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800504
wangyixcef14bf2015-07-24 13:48:26 -0700505 GrGLBlend::AppendPorterDuffBlend(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdaniel95131432014-12-09 11:15:43 -0800506 }
507
cdalton6fd158e2015-05-27 15:08:33 -0700508 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700509
cdalton6fd158e2015-05-27 15:08:33 -0700510 typedef GrGLXferProcessor INHERITED;
511};
bungemanc33db932015-05-22 17:55:26 -0700512
cdalton6fd158e2015-05-27 15:08:33 -0700513///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700514
cdalton6fd158e2015-05-27 15:08:33 -0700515void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
516 GrProcessorKeyBuilder* b) const {
517 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700518}
519
cdalton6fd158e2015-05-27 15:08:33 -0700520GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700521 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800522}
523
egdaniel378092f2014-12-03 10:40:13 -0800524///////////////////////////////////////////////////////////////////////////////
525
egdaniel0d5fd112015-05-12 06:11:35 -0700526class PDLCDXferProcessor : public GrXferProcessor {
527public:
cdalton6fd158e2015-05-27 15:08:33 -0700528 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700529
530 ~PDLCDXferProcessor() override;
531
532 const char* name() const override { return "Porter Duff LCD"; }
533
534 GrGLXferProcessor* createGLInstance() const override;
535
egdaniel0d5fd112015-05-12 06:11:35 -0700536private:
537 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
538
539 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
540 const GrProcOptInfo& coveragePOI,
541 bool doesStencilWrite,
542 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700543 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700544
545 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
546
547 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
548 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
549 blendInfo->fDstBlend = kISC_GrBlendCoeff;
550 blendInfo->fBlendConstant = fBlendConstant;
551 }
552
553 bool onIsEqual(const GrXferProcessor& xpBase) const override {
554 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
555 if (fBlendConstant != xp.fBlendConstant ||
556 fAlpha != xp.fAlpha) {
557 return false;
558 }
559 return true;
560 }
561
562 GrColor fBlendConstant;
563 uint8_t fAlpha;
564
565 typedef GrXferProcessor INHERITED;
566};
567
568///////////////////////////////////////////////////////////////////////////////
569
570class GLPDLCDXferProcessor : public GrGLXferProcessor {
571public:
572 GLPDLCDXferProcessor(const GrProcessor&) {}
573
574 virtual ~GLPDLCDXferProcessor() {}
575
576 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
577 GrProcessorKeyBuilder* b) {}
578
579private:
cdaltonedbb31f2015-06-08 12:14:44 -0700580 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel0d5fd112015-05-12 06:11:35 -0700581 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
582
583 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
584 args.fInputCoverage);
585 }
586
587 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
588
589 typedef GrGLXferProcessor INHERITED;
590};
591
592///////////////////////////////////////////////////////////////////////////////
593
594PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
595 : fBlendConstant(blendConstant)
596 , fAlpha(alpha) {
597 this->initClassID<PDLCDXferProcessor>();
598}
599
cdalton6fd158e2015-05-27 15:08:33 -0700600GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700601 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700602 if (SkXfermode::kSrcOver_Mode != xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700603 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700604 }
605
606 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700607 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700608 }
609
610 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
611 uint8_t alpha = GrColorUnpackA(blendConstant);
612 blendConstant |= (0xff << GrColor_SHIFT_A);
613
halcanary385fe4d2015-08-26 13:07:48 -0700614 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700615}
616
617PDLCDXferProcessor::~PDLCDXferProcessor() {
618}
619
620void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
621 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700622 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700623}
624
625GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700626 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700627}
628
629GrXferProcessor::OptFlags
630PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
631 const GrProcOptInfo& coveragePOI,
632 bool doesStencilWrite,
633 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700634 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700635 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
636 // value of the blend the constant. We should already have valid blend coeff's if we are at
637 // a point where we have RGB coverage. We don't need any color stages since the known color
638 // output is already baked into the blendConstant.
639 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
640 return GrXferProcessor::kOverrideColor_OptFlag;
641}
642
643///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700644
645GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
646 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700647 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdaniel915187b2014-12-05 12:58:28 -0800648 this->initClassID<GrPorterDuffXPFactory>();
649}
650
cdalton6fd158e2015-05-27 15:08:33 -0700651GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
652 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
653 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
654 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
655 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
656 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
657 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
658 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
659 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
660 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
661 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
662 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
663 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
664 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
665 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
666 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
667
668 static GrPorterDuffXPFactory* gFactories[] = {
669 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
670 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
671 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
672 };
673 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
674
675 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700676 return nullptr;
egdanielc016fb82014-12-03 11:41:54 -0800677 }
cdalton6fd158e2015-05-27 15:08:33 -0700678 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800679}
680
bsalomon50785a32015-02-06 07:02:37 -0800681GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700682GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800683 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800684 const GrProcOptInfo& covPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700685 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700686 const DstTexture* dstTexture) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700687 if (covPOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700688 SkASSERT(!dstTexture || !dstTexture->texture());
689 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
egdaniel95131432014-12-09 11:15:43 -0800690 }
cdalton6fd158e2015-05-27 15:08:33 -0700691
cdalton86ae0a92015-06-08 15:11:04 -0700692 BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700693 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700694 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700695 }
696
697 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700698 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800699}
700
701bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
702 uint32_t knownColorFlags) const {
cdalton6fd158e2015-05-27 15:08:33 -0700703 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniel378092f2014-12-03 10:40:13 -0800704 kRGBA_GrColorComponentFlags == knownColorFlags) {
705 return true;
706 }
707 return false;
708}
709
cdalton1fa45722015-06-02 10:43:39 -0700710void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
711 InvariantBlendedColor* blendedColor) const {
712 // Find the blended color info based on the formula that does not have coverage.
713 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
714 if (colorFormula.usesDstColor()) {
715 blendedColor->fWillBlendWithDst = true;
716 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800717 return;
egdaniel95131432014-12-09 11:15:43 -0800718 }
719
cdalton1fa45722015-06-02 10:43:39 -0700720 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700721
cdalton1fa45722015-06-02 10:43:39 -0700722 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700723
cdalton1fa45722015-06-02 10:43:39 -0700724 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800725 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700726 blendedColor->fKnownColor = 0;
727 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700728 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800729
730 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700731 blendedColor->fKnownColor = colorPOI.color();
732 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700733 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800734
cdalton1fa45722015-06-02 10:43:39 -0700735 default:
736 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
737 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800738 }
egdaniel95131432014-12-09 11:15:43 -0800739}
740
bsalomon4b91f762015-05-19 09:29:46 -0700741bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800742 const GrProcOptInfo& colorPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700743 const GrProcOptInfo& covPOI,
744 bool hasMixedSamples) const {
745 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
746 return false;
bungemanc33db932015-05-22 17:55:26 -0700747 }
cdalton86ae0a92015-06-08 15:11:04 -0700748 if (covPOI.isFourChannelOutput()) {
749 return false; // The LCD XP will abort rather than doing a dst read.
750 }
cdalton6fd158e2015-05-27 15:08:33 -0700751 // We fallback on the shader XP when the blend formula would use dual source blending but we
752 // don't have support for it.
cdalton86ae0a92015-06-08 15:11:04 -0700753 return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800754}
755
egdanielc2304142014-12-11 13:15:13 -0800756GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
757
joshualitt0067ff52015-07-08 14:26:19 -0700758GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
759 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
egdanielb197b8f2015-02-17 07:34:43 -0800760 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800761}
egdaniel95131432014-12-09 11:15:43 -0800762
cdalton6fd158e2015-05-27 15:08:33 -0700763void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
764 int* outPrimary,
765 int* outSecondary) {
766 if (!!strcmp(xp->name(), "Porter Duff")) {
767 *outPrimary = *outSecondary = -1;
768 return;
769 }
770 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
771 *outPrimary = blendFormula.fPrimaryOutputType;
772 *outSecondary = blendFormula.fSecondaryOutputType;
773}