blob: 6fc3c93e00d1e725485aef94a129f20699104300 [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
cdalton86ae0a92015-06-08 15:11:04 -0700291static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
292 const GrProcOptInfo& coveragePOI,
293 bool hasMixedSamples,
294 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700295 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
296 SkASSERT(!coveragePOI.isFourChannelOutput());
297
cdalton86ae0a92015-06-08 15:11:04 -0700298 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
299 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800300}
301
cdalton6fd158e2015-05-27 15:08:33 -0700302///////////////////////////////////////////////////////////////////////////////
303
egdaniel41d4f092015-02-09 07:51:00 -0800304class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800305public:
cdalton86ae0a92015-06-08 15:11:04 -0700306 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
307 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800308 }
egdaniel378092f2014-12-03 10:40:13 -0800309
mtklein36352bf2015-03-25 18:17:31 -0700310 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800311
mtklein36352bf2015-03-25 18:17:31 -0700312 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800313
cdalton6fd158e2015-05-27 15:08:33 -0700314 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700315
316private:
egdanielc19cdc22015-05-10 08:45:18 -0700317 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
318 const GrProcOptInfo& coveragePOI,
319 bool doesStencilWrite,
320 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700321 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700322
jvanverthcfc18862015-04-28 08:48:20 -0700323 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700324
cdaltonedbb31f2015-06-08 12:14:44 -0700325 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
326
cdaltonf4f2b442015-04-23 09:40:23 -0700327 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700328 blendInfo->fEquation = fBlendFormula.fBlendEquation;
329 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
330 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
331 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800332 }
333
mtklein36352bf2015-03-25 18:17:31 -0700334 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800335 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700336 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800337 }
338
cdalton6fd158e2015-05-27 15:08:33 -0700339 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800340
341 typedef GrXferProcessor INHERITED;
342};
343
344///////////////////////////////////////////////////////////////////////////////
345
cdalton6fd158e2015-05-27 15:08:33 -0700346static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
347 BlendFormula::OutputType outputType, const char* output,
348 const char* inColor, const char* inCoverage) {
349 switch (outputType) {
350 case BlendFormula::kNone_OutputType:
351 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
352 break;
353 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700354 // We can have a coverage formula while not reading coverage if there are mixed samples.
cdalton6fd158e2015-05-27 15:08:33 -0700355 fsBuilder->codeAppendf("%s = %s;",
356 output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
357 break;
358 case BlendFormula::kModulate_OutputType:
359 if (xp.readsCoverage()) {
360 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
361 } else {
362 fsBuilder->codeAppendf("%s = %s;", output, inColor);
363 }
364 break;
365 case BlendFormula::kISAModulate_OutputType:
366 if (xp.readsCoverage()) {
367 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
368 } else {
369 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
370 }
371 break;
372 case BlendFormula::kISCModulate_OutputType:
373 if (xp.readsCoverage()) {
374 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
375 } else {
376 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
377 }
378 break;
379 default:
380 SkFAIL("Unsupported output type.");
381 break;
egdaniel3ad65702015-02-17 11:15:47 -0800382 }
383}
384
egdaniel41d4f092015-02-09 07:51:00 -0800385class GLPorterDuffXferProcessor : public GrGLXferProcessor {
386public:
cdalton6fd158e2015-05-27 15:08:33 -0700387 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800388 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700389 b->add32(SkToInt(xp.readsCoverage()) |
390 (xp.getBlendFormula().fPrimaryOutputType << 1) |
391 (xp.getBlendFormula().fSecondaryOutputType << 4));
392 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800393 };
394
395private:
cdaltonedbb31f2015-06-08 12:14:44 -0700396 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800397 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel29bee0f2015-04-29 11:54:42 -0700398 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
bungemanc33db932015-05-22 17:55:26 -0700399
cdalton6fd158e2015-05-27 15:08:33 -0700400 BlendFormula blendFormula = xp.getBlendFormula();
401 if (blendFormula.hasSecondaryOutput()) {
402 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
403 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800404 }
cdalton6fd158e2015-05-27 15:08:33 -0700405 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
406 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800407 }
408
cdalton6fd158e2015-05-27 15:08:33 -0700409 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800410
egdaniel378092f2014-12-03 10:40:13 -0800411 typedef GrGLXferProcessor INHERITED;
412};
413
414///////////////////////////////////////////////////////////////////////////////
415
cdalton6fd158e2015-05-27 15:08:33 -0700416void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
egdaniel41d4f092015-02-09 07:51:00 -0800417 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700418 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800419}
420
egdaniel41d4f092015-02-09 07:51:00 -0800421GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
cdalton6fd158e2015-05-27 15:08:33 -0700422 return SkNEW(GLPorterDuffXferProcessor);
egdaniel378092f2014-12-03 10:40:13 -0800423}
424
egdaniel95131432014-12-09 11:15:43 -0800425GrXferProcessor::OptFlags
egdanielc19cdc22015-05-10 08:45:18 -0700426PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
427 const GrProcOptInfo& coveragePOI,
428 bool doesStencilWrite,
429 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700430 const GrCaps& caps) {
bsalomon7765a472015-07-08 11:26:37 -0700431 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700432 if (!fBlendFormula.modifiesDst()) {
433 if (!doesStencilWrite) {
434 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
435 }
436 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
437 GrXferProcessor::kIgnoreCoverage_OptFlag |
438 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
439 } else {
440 if (!fBlendFormula.usesInputColor()) {
441 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
442 }
443 if (coveragePOI.isSolidWhite()) {
444 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
445 }
446 if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
447 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
448 }
449 }
bungemanc33db932015-05-22 17:55:26 -0700450 return optFlags;
451}
452
cdalton6fd158e2015-05-27 15:08:33 -0700453///////////////////////////////////////////////////////////////////////////////
454
455class ShaderPDXferProcessor : public GrXferProcessor {
456public:
cdalton86ae0a92015-06-08 15:11:04 -0700457 ShaderPDXferProcessor(const DstTexture* dstTexture,
458 bool hasMixedSamples,
459 SkXfermode::Mode xfermode)
460 : INHERITED(dstTexture, true, hasMixedSamples)
461 , fXfermode(xfermode) {
462 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700463 }
464
cdalton6fd158e2015-05-27 15:08:33 -0700465 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700466
467 GrGLXferProcessor* createGLInstance() const override;
468
469 SkXfermode::Mode getXfermode() const { return fXfermode; }
470
471private:
cdalton6fd158e2015-05-27 15:08:33 -0700472 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
473 bool, GrColor*, const GrCaps&) override {
bsalomon7765a472015-07-08 11:26:37 -0700474 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700475 }
476
477 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
478
479 bool onIsEqual(const GrXferProcessor& xpBase) const override {
480 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
481 return fXfermode == xp.fXfermode;
482 }
483
484 const SkXfermode::Mode fXfermode;
485
486 typedef GrXferProcessor INHERITED;
487};
488
489///////////////////////////////////////////////////////////////////////////////
490
491static bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
492 const char* colorName, const char* srcColorName,
493 const char* dstColorName, bool hasPrevious) {
494 if (SkXfermode::kZero_Coeff == coeff) {
495 return hasPrevious;
496 } else {
497 if (hasPrevious) {
498 fsBuilder->codeAppend(" + ");
bungemanc33db932015-05-22 17:55:26 -0700499 }
cdalton6fd158e2015-05-27 15:08:33 -0700500 fsBuilder->codeAppendf("%s", colorName);
501 switch (coeff) {
502 case SkXfermode::kOne_Coeff:
503 break;
504 case SkXfermode::kSC_Coeff:
505 fsBuilder->codeAppendf(" * %s", srcColorName);
506 break;
507 case SkXfermode::kISC_Coeff:
508 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
509 break;
510 case SkXfermode::kDC_Coeff:
511 fsBuilder->codeAppendf(" * %s", dstColorName);
512 break;
513 case SkXfermode::kIDC_Coeff:
514 fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
515 break;
516 case SkXfermode::kSA_Coeff:
517 fsBuilder->codeAppendf(" * %s.a", srcColorName);
518 break;
519 case SkXfermode::kISA_Coeff:
520 fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
521 break;
522 case SkXfermode::kDA_Coeff:
523 fsBuilder->codeAppendf(" * %s.a", dstColorName);
524 break;
525 case SkXfermode::kIDA_Coeff:
526 fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
527 break;
528 default:
529 SkFAIL("Unsupported Blend Coeff");
530 }
531 return true;
bungemanc33db932015-05-22 17:55:26 -0700532 }
533}
534
cdalton6fd158e2015-05-27 15:08:33 -0700535class GLShaderPDXferProcessor : public GrGLXferProcessor {
536public:
537 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
538 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
539 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800540 }
egdaniel87509242014-12-17 13:37:13 -0800541
cdalton6fd158e2015-05-27 15:08:33 -0700542private:
cdaltonedbb31f2015-06-08 12:14:44 -0700543 void emitBlendCodeForDstRead(GrGLXPBuilder* pb, const char* srcColor, const char* dstColor,
544 const char* outColor, const GrXferProcessor& proc) override {
545 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
546 GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800547
cdalton6fd158e2015-05-27 15:08:33 -0700548 SkXfermode::Coeff srcCoeff, dstCoeff;
549 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
bungemanc33db932015-05-22 17:55:26 -0700550
cdaltonedbb31f2015-06-08 12:14:44 -0700551 fsBuilder->codeAppendf("%s =", outColor);
cdalton6fd158e2015-05-27 15:08:33 -0700552 // append src blend
cdaltonedbb31f2015-06-08 12:14:44 -0700553 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
554 false);
cdalton6fd158e2015-05-27 15:08:33 -0700555 // append dst blend
cdaltonedbb31f2015-06-08 12:14:44 -0700556 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor,
557 didAppend));
cdalton6fd158e2015-05-27 15:08:33 -0700558 fsBuilder->codeAppend(";");
egdaniel95131432014-12-09 11:15:43 -0800559 }
560
cdalton6fd158e2015-05-27 15:08:33 -0700561 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700562
cdalton6fd158e2015-05-27 15:08:33 -0700563 typedef GrGLXferProcessor INHERITED;
564};
bungemanc33db932015-05-22 17:55:26 -0700565
cdalton6fd158e2015-05-27 15:08:33 -0700566///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700567
cdalton6fd158e2015-05-27 15:08:33 -0700568void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
569 GrProcessorKeyBuilder* b) const {
570 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700571}
572
cdalton6fd158e2015-05-27 15:08:33 -0700573GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
574 return SkNEW(GLShaderPDXferProcessor);
egdanielc2304142014-12-11 13:15:13 -0800575}
576
egdaniel378092f2014-12-03 10:40:13 -0800577///////////////////////////////////////////////////////////////////////////////
578
egdaniel0d5fd112015-05-12 06:11:35 -0700579class PDLCDXferProcessor : public GrXferProcessor {
580public:
cdalton6fd158e2015-05-27 15:08:33 -0700581 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700582
583 ~PDLCDXferProcessor() override;
584
585 const char* name() const override { return "Porter Duff LCD"; }
586
587 GrGLXferProcessor* createGLInstance() const override;
588
egdaniel0d5fd112015-05-12 06:11:35 -0700589private:
590 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
591
592 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
593 const GrProcOptInfo& coveragePOI,
594 bool doesStencilWrite,
595 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700596 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700597
598 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
599
600 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
601 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
602 blendInfo->fDstBlend = kISC_GrBlendCoeff;
603 blendInfo->fBlendConstant = fBlendConstant;
604 }
605
606 bool onIsEqual(const GrXferProcessor& xpBase) const override {
607 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
608 if (fBlendConstant != xp.fBlendConstant ||
609 fAlpha != xp.fAlpha) {
610 return false;
611 }
612 return true;
613 }
614
615 GrColor fBlendConstant;
616 uint8_t fAlpha;
617
618 typedef GrXferProcessor INHERITED;
619};
620
621///////////////////////////////////////////////////////////////////////////////
622
623class GLPDLCDXferProcessor : public GrGLXferProcessor {
624public:
625 GLPDLCDXferProcessor(const GrProcessor&) {}
626
627 virtual ~GLPDLCDXferProcessor() {}
628
629 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
630 GrProcessorKeyBuilder* b) {}
631
632private:
cdaltonedbb31f2015-06-08 12:14:44 -0700633 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel0d5fd112015-05-12 06:11:35 -0700634 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
635
636 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
637 args.fInputCoverage);
638 }
639
640 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
641
642 typedef GrGLXferProcessor INHERITED;
643};
644
645///////////////////////////////////////////////////////////////////////////////
646
647PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
648 : fBlendConstant(blendConstant)
649 , fAlpha(alpha) {
650 this->initClassID<PDLCDXferProcessor>();
651}
652
cdalton6fd158e2015-05-27 15:08:33 -0700653GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700654 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700655 if (SkXfermode::kSrcOver_Mode != xfermode) {
egdaniel0d5fd112015-05-12 06:11:35 -0700656 return NULL;
657 }
658
659 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
660 return NULL;
661 }
662
663 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
664 uint8_t alpha = GrColorUnpackA(blendConstant);
665 blendConstant |= (0xff << GrColor_SHIFT_A);
666
667 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha));
668}
669
670PDLCDXferProcessor::~PDLCDXferProcessor() {
671}
672
673void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
674 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700675 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700676}
677
678GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
679 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
680}
681
682GrXferProcessor::OptFlags
683PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
684 const GrProcOptInfo& coveragePOI,
685 bool doesStencilWrite,
686 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700687 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700688 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
689 // value of the blend the constant. We should already have valid blend coeff's if we are at
690 // a point where we have RGB coverage. We don't need any color stages since the known color
691 // output is already baked into the blendConstant.
692 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
693 return GrXferProcessor::kOverrideColor_OptFlag;
694}
695
696///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700697
698GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
699 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700700 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdaniel915187b2014-12-05 12:58:28 -0800701 this->initClassID<GrPorterDuffXPFactory>();
702}
703
cdalton6fd158e2015-05-27 15:08:33 -0700704GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
705 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
706 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
707 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
708 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
709 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
710 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
711 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
712 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
713 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
714 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
715 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
716 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
717 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
718 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
719 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
720
721 static GrPorterDuffXPFactory* gFactories[] = {
722 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
723 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
724 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
725 };
726 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
727
728 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
729 return NULL;
egdanielc016fb82014-12-03 11:41:54 -0800730 }
cdalton6fd158e2015-05-27 15:08:33 -0700731 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800732}
733
bsalomon50785a32015-02-06 07:02:37 -0800734GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700735GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800736 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800737 const GrProcOptInfo& covPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700738 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700739 const DstTexture* dstTexture) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700740 if (covPOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700741 SkASSERT(!dstTexture || !dstTexture->texture());
742 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
egdaniel95131432014-12-09 11:15:43 -0800743 }
cdalton6fd158e2015-05-27 15:08:33 -0700744
cdalton86ae0a92015-06-08 15:11:04 -0700745 BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700746 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
cdalton86ae0a92015-06-08 15:11:04 -0700747 return SkNEW_ARGS(ShaderPDXferProcessor, (dstTexture, hasMixedSamples, fXfermode));
cdalton6fd158e2015-05-27 15:08:33 -0700748 }
749
750 SkASSERT(!dstTexture || !dstTexture->texture());
cdalton86ae0a92015-06-08 15:11:04 -0700751 return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
egdaniel378092f2014-12-03 10:40:13 -0800752}
753
754bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
755 uint32_t knownColorFlags) const {
cdalton6fd158e2015-05-27 15:08:33 -0700756 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniel378092f2014-12-03 10:40:13 -0800757 kRGBA_GrColorComponentFlags == knownColorFlags) {
758 return true;
759 }
760 return false;
761}
762
cdalton1fa45722015-06-02 10:43:39 -0700763void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
764 InvariantBlendedColor* blendedColor) const {
765 // Find the blended color info based on the formula that does not have coverage.
766 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
767 if (colorFormula.usesDstColor()) {
768 blendedColor->fWillBlendWithDst = true;
769 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800770 return;
egdaniel95131432014-12-09 11:15:43 -0800771 }
772
cdalton1fa45722015-06-02 10:43:39 -0700773 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700774
cdalton1fa45722015-06-02 10:43:39 -0700775 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700776
cdalton1fa45722015-06-02 10:43:39 -0700777 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800778 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700779 blendedColor->fKnownColor = 0;
780 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700781 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800782
783 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700784 blendedColor->fKnownColor = colorPOI.color();
785 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700786 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800787
cdalton1fa45722015-06-02 10:43:39 -0700788 default:
789 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
790 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800791 }
egdaniel95131432014-12-09 11:15:43 -0800792}
793
bsalomon4b91f762015-05-19 09:29:46 -0700794bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800795 const GrProcOptInfo& colorPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700796 const GrProcOptInfo& covPOI,
797 bool hasMixedSamples) const {
798 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
799 return false;
bungemanc33db932015-05-22 17:55:26 -0700800 }
cdalton86ae0a92015-06-08 15:11:04 -0700801 if (covPOI.isFourChannelOutput()) {
802 return false; // The LCD XP will abort rather than doing a dst read.
803 }
cdalton6fd158e2015-05-27 15:08:33 -0700804 // We fallback on the shader XP when the blend formula would use dual source blending but we
805 // don't have support for it.
cdalton86ae0a92015-06-08 15:11:04 -0700806 return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).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