blob: ecaa87f941cb80f840d74f7f45ca589fcc4cfc21 [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
cdalton6fd158e2015-05-27 15:08:33 -070020/**
21 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
22 */
23struct BlendFormula {
24public:
25 /**
26 * Values the shader can write to primary and secondary outputs. These must all be modulated by
27 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080028 */
cdalton6fd158e2015-05-27 15:08:33 -070029 enum OutputType {
30 kNone_OutputType, //<! 0
31 kCoverage_OutputType, //<! inputCoverage
32 kModulate_OutputType, //<! inputColor * inputCoverage
33 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
34 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
35
36 kLast_OutputType = kISCModulate_OutputType
37 };
38
39 enum Properties {
40 kModifiesDst_Property = 1,
41 kUsesDstColor_Property = 1 << 1,
42 kUsesInputColor_Property = 1 << 2,
43 kCanTweakAlphaForCoverage_Property = 1 << 3,
44
45 kLast_Property = kCanTweakAlphaForCoverage_Property
46 };
47
48 BlendFormula& operator =(const BlendFormula& other) {
49 fData = other.fData;
50 return *this;
51 }
52
53 bool operator ==(const BlendFormula& other) const {
54 return fData == other.fData;
55 }
56
57 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
58 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
59 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
60 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
61 bool canTweakAlphaForCoverage() const {
62 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
63 }
64
65 /**
66 * Deduce the properties of a compile-time constant BlendFormula.
67 */
68 template<OutputType PrimaryOut, OutputType SecondaryOut,
69 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
70 struct get_properties : SkTIntegralConstant<Properties, static_cast<Properties>(
71
72 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
73 kModifiesDst_Property : 0) |
74
75 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
76 kUsesDstColor_Property : 0) |
77
78 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
79 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
80 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
81
82 (kModulate_OutputType == PrimaryOut &&
83 kNone_OutputType == SecondaryOut &&
84 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
85 kCanTweakAlphaForCoverage_Property : 0))> {
86
87 // The provided formula should already be optimized.
88 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
89 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
90 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
91 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
92 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
93 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
94 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
95 };
96
97 union {
98 struct {
99 // We allot the enums one more bit than they require because MSVC seems to sign-extend
100 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
101 OutputType fPrimaryOutputType : 4;
102 OutputType fSecondaryOutputType : 4;
103 GrBlendEquation fBlendEquation : 6;
104 GrBlendCoeff fSrcCoeff : 6;
105 GrBlendCoeff fDstCoeff : 6;
106 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
107 };
108 uint32_t fData;
109 };
110
111 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
112 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
113 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
114 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
115};
116
117GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
118
119GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
120
121/**
122 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
123 */
124#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
125 {{{PRIMARY_OUT, \
126 SECONDARY_OUT, \
127 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
128 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
129 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
130
131/**
132 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
133 * Porter Duff formula.
134 */
135#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
136 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
137 BlendFormula::kNone_OutputType, \
138 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
139
140/**
141 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
142 * the primary output type to none.
143 */
144#define DST_CLEAR_FORMULA \
145 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
146 BlendFormula::kNone_OutputType, \
147 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
148
149/**
150 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
151 * so we can set the primary output type to none.
152 */
153#define NO_DST_WRITE_FORMULA \
154 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
155 BlendFormula::kNone_OutputType, \
156 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
157
158/**
159 * When there is coverage, the equation with f=coverage is:
160 *
161 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
162 *
163 * This can be rewritten as:
164 *
165 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
166 *
167 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
168 * HW dst coeff with IS2C.
169 *
170 * Xfer modes: dst-atop (Sa!=1)
171 */
172#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
173 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
174 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
175 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
176
177/**
178 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
179 *
180 * D' = f * D * dstCoeff + (1-f) * D
181 *
182 * This can be rewritten as:
183 *
184 * D' = D - D * [f * (1 - dstCoeff)]
185 *
186 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
187 * subtract HW blend equation with coeffs of (DC, One).
188 *
189 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
190 */
191#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
192 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
193 BlendFormula::kNone_OutputType, \
194 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
195
196/**
197 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
198 *
199 * D' = f * S * srcCoeff + (1-f) * D
200 *
201 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
202 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
203 *
204 * Xfer modes (Sa!=1): src, src-in, src-out
205 */
206#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
207 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
208 BlendFormula::kCoverage_OutputType, \
209 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
210
211/**
212 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
213 * with and without an opaque input color. Optimization properties are deduced at compile time so we
214 * can make runtime decisions quickly. RGB coverage is not supported.
215 */
216static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
217
218 /*>> No coverage, input color unknown <<*/ {{
219
220 /* clear */ DST_CLEAR_FORMULA,
221 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
222 /* dst */ NO_DST_WRITE_FORMULA,
223 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
224 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
225 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
226 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
227 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
228 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
229 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
230 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
231 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
232 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
233 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
234 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
235
236 }, /*>> Has coverage, input color unknown <<*/ {
237
238 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
239 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
240 /* dst */ NO_DST_WRITE_FORMULA,
241 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
242 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
243 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
244 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
245 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
246 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
247 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
248 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
249 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
250 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
251 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
252 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
253
254 }}, /*>> No coverage, input color opaque <<*/ {{
255
256 /* clear */ DST_CLEAR_FORMULA,
257 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
258 /* dst */ NO_DST_WRITE_FORMULA,
259 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
260 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
261 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
262 /* dst-in */ NO_DST_WRITE_FORMULA,
263 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
264 /* dst-out */ DST_CLEAR_FORMULA,
265 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
266 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
267 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
268 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
269 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
270 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
271
272 }, /*>> Has coverage, input color opaque <<*/ {
273
274 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
275 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
276 /* dst */ NO_DST_WRITE_FORMULA,
277 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
278 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
279 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
280 /* dst-in */ NO_DST_WRITE_FORMULA,
281 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
282 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
283 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
284 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
285 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
286 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
287 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
288 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
289}}};
290
291static BlendFormula get_blend_formula(SkXfermode::Mode xfermode,
292 const GrProcOptInfo& colorPOI,
293 const GrProcOptInfo& coveragePOI) {
294 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
295 SkASSERT(!coveragePOI.isFourChannelOutput());
296
297 return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800298}
299
cdalton6fd158e2015-05-27 15:08:33 -0700300///////////////////////////////////////////////////////////////////////////////
301
egdaniel41d4f092015-02-09 07:51:00 -0800302class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800303public:
cdalton6fd158e2015-05-27 15:08:33 -0700304 static GrXferProcessor* Create(BlendFormula blendFormula) {
305 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
egdaniel41d4f092015-02-09 07:51:00 -0800306 }
egdaniel378092f2014-12-03 10:40:13 -0800307
mtklein36352bf2015-03-25 18:17:31 -0700308 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800309
mtklein36352bf2015-03-25 18:17:31 -0700310 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800311
cdalton6fd158e2015-05-27 15:08:33 -0700312 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700313
314private:
cdalton6fd158e2015-05-27 15:08:33 -0700315 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
316 this->initClassID<PorterDuffXferProcessor>();
317 }
cdaltonf4f2b442015-04-23 09:40:23 -0700318
egdanielc19cdc22015-05-10 08:45:18 -0700319 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
320 const GrProcOptInfo& coveragePOI,
321 bool doesStencilWrite,
322 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700323 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700324
jvanverthcfc18862015-04-28 08:48:20 -0700325 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700326
cdaltonedbb31f2015-06-08 12:14:44 -0700327 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
328
cdaltonf4f2b442015-04-23 09:40:23 -0700329 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700330 blendInfo->fEquation = fBlendFormula.fBlendEquation;
331 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
332 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
333 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800334 }
335
mtklein36352bf2015-03-25 18:17:31 -0700336 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800337 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700338 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800339 }
340
cdalton6fd158e2015-05-27 15:08:33 -0700341 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800342
343 typedef GrXferProcessor INHERITED;
344};
345
346///////////////////////////////////////////////////////////////////////////////
347
cdalton6fd158e2015-05-27 15:08:33 -0700348static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
349 BlendFormula::OutputType outputType, const char* output,
350 const char* inColor, const char* inCoverage) {
351 switch (outputType) {
352 case BlendFormula::kNone_OutputType:
353 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
354 break;
355 case BlendFormula::kCoverage_OutputType:
356 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 {
cdalton6fd158e2015-05-27 15:08:33 -0700423 return SkNEW(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) {
cdalton6fd158e2015-05-27 15:08:33 -0700432 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
433 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:
458 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
459 return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
bungemanc33db932015-05-22 17:55:26 -0700460 }
461
cdalton6fd158e2015-05-27 15:08:33 -0700462 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700463
464 GrGLXferProcessor* createGLInstance() const override;
465
466 SkXfermode::Mode getXfermode() const { return fXfermode; }
467
468private:
469 ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTexture)
470 : INHERITED(dstTexture, true)
471 , fXfermode(xfermode) {
472 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700473 }
474
cdalton6fd158e2015-05-27 15:08:33 -0700475 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
476 bool, GrColor*, const GrCaps&) override {
477 return kNone_Opt;
478 }
479
480 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
481
482 bool onIsEqual(const GrXferProcessor& xpBase) const override {
483 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
484 return fXfermode == xp.fXfermode;
485 }
486
487 const SkXfermode::Mode fXfermode;
488
489 typedef GrXferProcessor INHERITED;
490};
491
492///////////////////////////////////////////////////////////////////////////////
493
494static bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
495 const char* colorName, const char* srcColorName,
496 const char* dstColorName, bool hasPrevious) {
497 if (SkXfermode::kZero_Coeff == coeff) {
498 return hasPrevious;
499 } else {
500 if (hasPrevious) {
501 fsBuilder->codeAppend(" + ");
bungemanc33db932015-05-22 17:55:26 -0700502 }
cdalton6fd158e2015-05-27 15:08:33 -0700503 fsBuilder->codeAppendf("%s", colorName);
504 switch (coeff) {
505 case SkXfermode::kOne_Coeff:
506 break;
507 case SkXfermode::kSC_Coeff:
508 fsBuilder->codeAppendf(" * %s", srcColorName);
509 break;
510 case SkXfermode::kISC_Coeff:
511 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
512 break;
513 case SkXfermode::kDC_Coeff:
514 fsBuilder->codeAppendf(" * %s", dstColorName);
515 break;
516 case SkXfermode::kIDC_Coeff:
517 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
518 break;
519 case SkXfermode::kSA_Coeff:
520 fsBuilder->codeAppendf(" * %s.a", srcColorName);
521 break;
522 case SkXfermode::kISA_Coeff:
523 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
524 break;
525 case SkXfermode::kDA_Coeff:
526 fsBuilder->codeAppendf(" * %s.a", dstColorName);
527 break;
528 case SkXfermode::kIDA_Coeff:
529 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
530 break;
531 default:
532 SkFAIL("Unsupported Blend Coeff");
533 }
534 return true;
bungemanc33db932015-05-22 17:55:26 -0700535 }
536}
537
cdalton6fd158e2015-05-27 15:08:33 -0700538class GLShaderPDXferProcessor : public GrGLXferProcessor {
539public:
540 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
541 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
542 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800543 }
egdaniel87509242014-12-17 13:37:13 -0800544
cdalton6fd158e2015-05-27 15:08:33 -0700545private:
cdaltonedbb31f2015-06-08 12:14:44 -0700546 void emitBlendCodeForDstRead(GrGLXPBuilder* pb, const char* srcColor, const char* dstColor,
547 const char* outColor, const GrXferProcessor& proc) override {
548 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
549 GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800550
cdalton6fd158e2015-05-27 15:08:33 -0700551 SkXfermode::Coeff srcCoeff, dstCoeff;
552 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
bungemanc33db932015-05-22 17:55:26 -0700553
cdaltonedbb31f2015-06-08 12:14:44 -0700554 fsBuilder->codeAppendf("%s =", outColor);
cdalton6fd158e2015-05-27 15:08:33 -0700555 // append src blend
cdaltonedbb31f2015-06-08 12:14:44 -0700556 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
557 false);
cdalton6fd158e2015-05-27 15:08:33 -0700558 // append dst blend
cdaltonedbb31f2015-06-08 12:14:44 -0700559 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor,
560 didAppend));
cdalton6fd158e2015-05-27 15:08:33 -0700561 fsBuilder->codeAppend(";");
egdaniel95131432014-12-09 11:15:43 -0800562 }
563
cdalton6fd158e2015-05-27 15:08:33 -0700564 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700565
cdalton6fd158e2015-05-27 15:08:33 -0700566 typedef GrGLXferProcessor INHERITED;
567};
bungemanc33db932015-05-22 17:55:26 -0700568
cdalton6fd158e2015-05-27 15:08:33 -0700569///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700570
cdalton6fd158e2015-05-27 15:08:33 -0700571void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
572 GrProcessorKeyBuilder* b) const {
573 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700574}
575
cdalton6fd158e2015-05-27 15:08:33 -0700576GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
577 return SkNEW(GLShaderPDXferProcessor);
egdanielc2304142014-12-11 13:15:13 -0800578}
579
egdaniel378092f2014-12-03 10:40:13 -0800580///////////////////////////////////////////////////////////////////////////////
581
egdaniel0d5fd112015-05-12 06:11:35 -0700582class PDLCDXferProcessor : public GrXferProcessor {
583public:
cdalton6fd158e2015-05-27 15:08:33 -0700584 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700585
586 ~PDLCDXferProcessor() override;
587
588 const char* name() const override { return "Porter Duff LCD"; }
589
590 GrGLXferProcessor* createGLInstance() const override;
591
egdaniel0d5fd112015-05-12 06:11:35 -0700592private:
593 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
594
595 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
596 const GrProcOptInfo& coveragePOI,
597 bool doesStencilWrite,
598 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700599 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700600
601 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
602
603 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
604 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
605 blendInfo->fDstBlend = kISC_GrBlendCoeff;
606 blendInfo->fBlendConstant = fBlendConstant;
607 }
608
609 bool onIsEqual(const GrXferProcessor& xpBase) const override {
610 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
611 if (fBlendConstant != xp.fBlendConstant ||
612 fAlpha != xp.fAlpha) {
613 return false;
614 }
615 return true;
616 }
617
618 GrColor fBlendConstant;
619 uint8_t fAlpha;
620
621 typedef GrXferProcessor INHERITED;
622};
623
624///////////////////////////////////////////////////////////////////////////////
625
626class GLPDLCDXferProcessor : public GrGLXferProcessor {
627public:
628 GLPDLCDXferProcessor(const GrProcessor&) {}
629
630 virtual ~GLPDLCDXferProcessor() {}
631
632 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
633 GrProcessorKeyBuilder* b) {}
634
635private:
cdaltonedbb31f2015-06-08 12:14:44 -0700636 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel0d5fd112015-05-12 06:11:35 -0700637 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
638
639 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
640 args.fInputCoverage);
641 }
642
643 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
644
645 typedef GrGLXferProcessor INHERITED;
646};
647
648///////////////////////////////////////////////////////////////////////////////
649
650PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
651 : fBlendConstant(blendConstant)
652 , fAlpha(alpha) {
653 this->initClassID<PDLCDXferProcessor>();
654}
655
cdalton6fd158e2015-05-27 15:08:33 -0700656GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700657 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700658 if (SkXfermode::kSrcOver_Mode != xfermode) {
egdaniel0d5fd112015-05-12 06:11:35 -0700659 return NULL;
660 }
661
662 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
663 return NULL;
664 }
665
666 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
667 uint8_t alpha = GrColorUnpackA(blendConstant);
668 blendConstant |= (0xff << GrColor_SHIFT_A);
669
670 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha));
671}
672
673PDLCDXferProcessor::~PDLCDXferProcessor() {
674}
675
676void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
677 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700678 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700679}
680
681GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
682 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
683}
684
685GrXferProcessor::OptFlags
686PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
687 const GrProcOptInfo& coveragePOI,
688 bool doesStencilWrite,
689 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700690 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700691 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
692 // value of the blend the constant. We should already have valid blend coeff's if we are at
693 // a point where we have RGB coverage. We don't need any color stages since the known color
694 // output is already baked into the blendConstant.
695 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
696 return GrXferProcessor::kOverrideColor_OptFlag;
697}
698
699///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700700
701GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
702 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700703 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdaniel915187b2014-12-05 12:58:28 -0800704 this->initClassID<GrPorterDuffXPFactory>();
705}
706
cdalton6fd158e2015-05-27 15:08:33 -0700707GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
708 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
709 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
710 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
711 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
712 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
713 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
714 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
715 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
716 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
717 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
718 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
719 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
720 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
721 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
722 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
723
724 static GrPorterDuffXPFactory* gFactories[] = {
725 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
726 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
727 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
728 };
729 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
730
731 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
732 return NULL;
egdanielc016fb82014-12-03 11:41:54 -0800733 }
cdalton6fd158e2015-05-27 15:08:33 -0700734 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800735}
736
bsalomon50785a32015-02-06 07:02:37 -0800737GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700738GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800739 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800740 const GrProcOptInfo& covPOI,
bsalomon6a44c6a2015-05-26 09:49:05 -0700741 const DstTexture* dstTexture) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700742 if (covPOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700743 SkASSERT(!dstTexture || !dstTexture->texture());
744 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
egdaniel95131432014-12-09 11:15:43 -0800745 }
cdalton6fd158e2015-05-27 15:08:33 -0700746
747 BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
748 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
749 return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
750 }
751
752 SkASSERT(!dstTexture || !dstTexture->texture());
753 return PorterDuffXferProcessor::Create(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800754}
755
756bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
757 uint32_t knownColorFlags) const {
cdalton6fd158e2015-05-27 15:08:33 -0700758 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniel378092f2014-12-03 10:40:13 -0800759 kRGBA_GrColorComponentFlags == knownColorFlags) {
760 return true;
761 }
762 return false;
763}
764
cdalton1fa45722015-06-02 10:43:39 -0700765void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
766 InvariantBlendedColor* blendedColor) const {
767 // Find the blended color info based on the formula that does not have coverage.
768 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
769 if (colorFormula.usesDstColor()) {
770 blendedColor->fWillBlendWithDst = true;
771 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800772 return;
egdaniel95131432014-12-09 11:15:43 -0800773 }
774
cdalton1fa45722015-06-02 10:43:39 -0700775 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700776
cdalton1fa45722015-06-02 10:43:39 -0700777 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700778
cdalton1fa45722015-06-02 10:43:39 -0700779 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800780 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700781 blendedColor->fKnownColor = 0;
782 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700783 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800784
785 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700786 blendedColor->fKnownColor = colorPOI.color();
787 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700788 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800789
cdalton1fa45722015-06-02 10:43:39 -0700790 default:
791 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
792 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800793 }
egdaniel95131432014-12-09 11:15:43 -0800794}
795
bsalomon4b91f762015-05-19 09:29:46 -0700796bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800797 const GrProcOptInfo& colorPOI,
egdaniele36914c2015-02-13 09:00:33 -0800798 const GrProcOptInfo& coveragePOI) const {
cdalton6fd158e2015-05-27 15:08:33 -0700799 if (coveragePOI.isFourChannelOutput()) {
800 return false; // The LCD XP never does a dst read.
bungemanc33db932015-05-22 17:55:26 -0700801 }
802
cdalton6fd158e2015-05-27 15:08:33 -0700803 // We fallback on the shader XP when the blend formula would use dual source blending but we
804 // don't have support for it.
805 return !caps.shaderCaps()->dualSourceBlendingSupport() &&
806 get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800807}
808
egdanielc2304142014-12-11 13:15:13 -0800809GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
810
811GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
812 GrContext*,
bsalomon4b91f762015-05-19 09:29:46 -0700813 const GrCaps&,
egdanielc2304142014-12-11 13:15:13 -0800814 GrTexture*[]) {
egdanielb197b8f2015-02-17 07:34:43 -0800815 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
816 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800817}
egdaniel95131432014-12-09 11:15:43 -0800818
cdalton6fd158e2015-05-27 15:08:33 -0700819void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
820 int* outPrimary,
821 int* outSecondary) {
822 if (!!strcmp(xp->name(), "Porter Duff")) {
823 *outPrimary = *outSecondary = -1;
824 return;
825 }
826 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
827 *outPrimary = blendFormula.fPrimaryOutputType;
828 *outSecondary = blendFormula.fSecondaryOutputType;
829}
830