blob: 812cfeaaa4472e4bef2a4a170e7bdd4a22b19265 [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"; }
cdalton6fd158e2015-05-27 15:08:33 -0700309 bool hasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
egdaniel41d4f092015-02-09 07:51:00 -0800310
mtklein36352bf2015-03-25 18:17:31 -0700311 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800312
cdalton6fd158e2015-05-27 15:08:33 -0700313 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700314
315private:
cdalton6fd158e2015-05-27 15:08:33 -0700316 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
317 this->initClassID<PorterDuffXferProcessor>();
318 }
cdaltonf4f2b442015-04-23 09:40:23 -0700319
egdanielc19cdc22015-05-10 08:45:18 -0700320 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
321 const GrProcOptInfo& coveragePOI,
322 bool doesStencilWrite,
323 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700324 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700325
jvanverthcfc18862015-04-28 08:48:20 -0700326 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700327
328 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:
355 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:
mtklein36352bf2015-03-25 18:17:31 -0700396 void onEmitCode(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) {
cdalton6fd158e2015-05-27 15:08:33 -0700431 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
432 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:
457 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
458 return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
bungemanc33db932015-05-22 17:55:26 -0700459 }
460
cdalton6fd158e2015-05-27 15:08:33 -0700461 const char* name() const override { return "Porter Duff Shader"; }
462 bool hasSecondaryOutput() const override { return false; }
463
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:
546 void onEmitCode(const EmitArgs& args) override {
547 const ShaderPDXferProcessor& xp = args.fXP.cast<ShaderPDXferProcessor>();
548 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800549
cdalton6fd158e2015-05-27 15:08:33 -0700550 SkXfermode::Coeff srcCoeff, dstCoeff;
551 SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
bungemanc33db932015-05-22 17:55:26 -0700552
cdalton6fd158e2015-05-27 15:08:33 -0700553 const char* dstColor = fsBuilder->dstColor();
554
555 fsBuilder->codeAppend("vec4 colorBlend =");
556 // append src blend
557 bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
558 args.fInputColor, args.fInputColor,
559 dstColor, false);
560 // append dst blend
561 SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
562 dstColor, args.fInputColor,
563 dstColor, didAppend));
564 fsBuilder->codeAppend(";");
565
566 fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
567 args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage,
568 dstColor);
egdaniel95131432014-12-09 11:15:43 -0800569 }
570
cdalton6fd158e2015-05-27 15:08:33 -0700571 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700572
cdalton6fd158e2015-05-27 15:08:33 -0700573 typedef GrGLXferProcessor INHERITED;
574};
bungemanc33db932015-05-22 17:55:26 -0700575
cdalton6fd158e2015-05-27 15:08:33 -0700576///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700577
cdalton6fd158e2015-05-27 15:08:33 -0700578void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
579 GrProcessorKeyBuilder* b) const {
580 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700581}
582
cdalton6fd158e2015-05-27 15:08:33 -0700583GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
584 return SkNEW(GLShaderPDXferProcessor);
egdanielc2304142014-12-11 13:15:13 -0800585}
586
egdaniel378092f2014-12-03 10:40:13 -0800587///////////////////////////////////////////////////////////////////////////////
588
egdaniel0d5fd112015-05-12 06:11:35 -0700589class PDLCDXferProcessor : public GrXferProcessor {
590public:
cdalton6fd158e2015-05-27 15:08:33 -0700591 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700592
593 ~PDLCDXferProcessor() override;
594
595 const char* name() const override { return "Porter Duff LCD"; }
596
597 GrGLXferProcessor* createGLInstance() const override;
598
599 bool hasSecondaryOutput() const override { return false; }
600
601private:
602 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
603
604 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
605 const GrProcOptInfo& coveragePOI,
606 bool doesStencilWrite,
607 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700608 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700609
610 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
611
612 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
613 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
614 blendInfo->fDstBlend = kISC_GrBlendCoeff;
615 blendInfo->fBlendConstant = fBlendConstant;
616 }
617
618 bool onIsEqual(const GrXferProcessor& xpBase) const override {
619 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
620 if (fBlendConstant != xp.fBlendConstant ||
621 fAlpha != xp.fAlpha) {
622 return false;
623 }
624 return true;
625 }
626
627 GrColor fBlendConstant;
628 uint8_t fAlpha;
629
630 typedef GrXferProcessor INHERITED;
631};
632
633///////////////////////////////////////////////////////////////////////////////
634
635class GLPDLCDXferProcessor : public GrGLXferProcessor {
636public:
637 GLPDLCDXferProcessor(const GrProcessor&) {}
638
639 virtual ~GLPDLCDXferProcessor() {}
640
641 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
642 GrProcessorKeyBuilder* b) {}
643
644private:
645 void onEmitCode(const EmitArgs& args) override {
646 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
647
648 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
649 args.fInputCoverage);
650 }
651
652 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
653
654 typedef GrGLXferProcessor INHERITED;
655};
656
657///////////////////////////////////////////////////////////////////////////////
658
659PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
660 : fBlendConstant(blendConstant)
661 , fAlpha(alpha) {
662 this->initClassID<PDLCDXferProcessor>();
663}
664
cdalton6fd158e2015-05-27 15:08:33 -0700665GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700666 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700667 if (SkXfermode::kSrcOver_Mode != xfermode) {
egdaniel0d5fd112015-05-12 06:11:35 -0700668 return NULL;
669 }
670
671 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
672 return NULL;
673 }
674
675 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
676 uint8_t alpha = GrColorUnpackA(blendConstant);
677 blendConstant |= (0xff << GrColor_SHIFT_A);
678
679 return SkNEW_ARGS(PDLCDXferProcessor, (blendConstant, alpha));
680}
681
682PDLCDXferProcessor::~PDLCDXferProcessor() {
683}
684
685void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
686 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700687 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700688}
689
690GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
691 return SkNEW_ARGS(GLPDLCDXferProcessor, (*this));
692}
693
694GrXferProcessor::OptFlags
695PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
696 const GrProcOptInfo& coveragePOI,
697 bool doesStencilWrite,
698 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700699 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700700 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
701 // value of the blend the constant. We should already have valid blend coeff's if we are at
702 // a point where we have RGB coverage. We don't need any color stages since the known color
703 // output is already baked into the blendConstant.
704 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
705 return GrXferProcessor::kOverrideColor_OptFlag;
706}
707
708///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700709
710GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
711 : fXfermode(xfermode) {
egdaniel915187b2014-12-05 12:58:28 -0800712 this->initClassID<GrPorterDuffXPFactory>();
713}
714
cdalton6fd158e2015-05-27 15:08:33 -0700715GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
716 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
717 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
718 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
719 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
720 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
721 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
722 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
723 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
724 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
725 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
726 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
727 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
728 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
729 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
730 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
731
732 static GrPorterDuffXPFactory* gFactories[] = {
733 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
734 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
735 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
736 };
737 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
738
739 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
740 return NULL;
egdanielc016fb82014-12-03 11:41:54 -0800741 }
cdalton6fd158e2015-05-27 15:08:33 -0700742 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800743}
744
bsalomon50785a32015-02-06 07:02:37 -0800745GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700746GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800747 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800748 const GrProcOptInfo& covPOI,
bsalomon6a44c6a2015-05-26 09:49:05 -0700749 const DstTexture* dstTexture) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700750 if (covPOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700751 SkASSERT(!dstTexture || !dstTexture->texture());
752 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
egdaniel95131432014-12-09 11:15:43 -0800753 }
cdalton6fd158e2015-05-27 15:08:33 -0700754
755 BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
756 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
757 return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
758 }
759
760 SkASSERT(!dstTexture || !dstTexture->texture());
761 return PorterDuffXferProcessor::Create(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800762}
763
764bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
765 uint32_t knownColorFlags) const {
cdalton6fd158e2015-05-27 15:08:33 -0700766 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniel378092f2014-12-03 10:40:13 -0800767 kRGBA_GrColorComponentFlags == knownColorFlags) {
768 return true;
769 }
770 return false;
771}
772
egdaniel9e4ecdc2014-12-18 12:44:55 -0800773void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
774 const GrProcOptInfo& coveragePOI,
egdaniel9e4ecdc2014-12-18 12:44:55 -0800775 GrXPFactory::InvariantOutput* output) const {
cdalton6fd158e2015-05-27 15:08:33 -0700776 output->fWillBlendWithDst = true;
777 output->fBlendedColorFlags = kNone_GrColorComponentFlags;
778
779 // The blend table doesn't support LCD coverage, but these formulas never have invariant output.
780 if (coveragePOI.isFourChannelOutput()) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800781 return;
egdaniel95131432014-12-09 11:15:43 -0800782 }
783
cdalton6fd158e2015-05-27 15:08:33 -0700784 const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, coveragePOI);
785 if (blendFormula.usesDstColor()) {
bungemanc33db932015-05-22 17:55:26 -0700786 return;
787 }
788
cdalton6fd158e2015-05-27 15:08:33 -0700789 SkASSERT(coveragePOI.isSolidWhite());
790 SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700791
cdalton6fd158e2015-05-27 15:08:33 -0700792 output->fWillBlendWithDst = false;
793
794 switch (blendFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800795 case kZero_GrBlendCoeff:
796 output->fBlendedColor = 0;
797 output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700798 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800799
800 case kOne_GrBlendCoeff:
801 output->fBlendedColor = colorPOI.color();
802 output->fBlendedColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700803 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800804
cdalton6fd158e2015-05-27 15:08:33 -0700805 default: return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800806 }
egdaniel95131432014-12-09 11:15:43 -0800807}
808
bsalomon4b91f762015-05-19 09:29:46 -0700809bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800810 const GrProcOptInfo& colorPOI,
egdaniele36914c2015-02-13 09:00:33 -0800811 const GrProcOptInfo& coveragePOI) const {
cdalton6fd158e2015-05-27 15:08:33 -0700812 if (coveragePOI.isFourChannelOutput()) {
813 return false; // The LCD XP never does a dst read.
bungemanc33db932015-05-22 17:55:26 -0700814 }
815
cdalton6fd158e2015-05-27 15:08:33 -0700816 // We fallback on the shader XP when the blend formula would use dual source blending but we
817 // don't have support for it.
818 return !caps.shaderCaps()->dualSourceBlendingSupport() &&
819 get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800820}
821
egdanielc2304142014-12-11 13:15:13 -0800822GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
823
824GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
825 GrContext*,
bsalomon4b91f762015-05-19 09:29:46 -0700826 const GrCaps&,
egdanielc2304142014-12-11 13:15:13 -0800827 GrTexture*[]) {
egdanielb197b8f2015-02-17 07:34:43 -0800828 SkXfermode::Mode mode = SkXfermode::Mode(random->nextULessThan(SkXfermode::kLastCoeffMode));
829 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800830}
egdaniel95131432014-12-09 11:15:43 -0800831
cdalton6fd158e2015-05-27 15:08:33 -0700832void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
833 int* outPrimary,
834 int* outSecondary) {
835 if (!!strcmp(xp->name(), "Porter Duff")) {
836 *outPrimary = *outSecondary = -1;
837 return;
838 }
839 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
840 *outPrimary = blendFormula.fPrimaryOutputType;
841 *outSecondary = blendFormula.fSecondaryOutputType;
842}
843