blob: 4c50e47ab9ae1d3845fb603a4f8d42c639a7cbff [file] [log] [blame]
egdaniel378092f2014-12-03 10:40:13 -08001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
egdanielced90102014-12-05 12:40:52 -08008#include "effects/GrPorterDuffXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -08009
egdaniel95131432014-12-09 11:15:43 -080010#include "GrBlend.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070011#include "GrCaps.h"
egdaniel378092f2014-12-03 10:40:13 -080012#include "GrProcessor.h"
egdaniel87509242014-12-17 13:37:13 -080013#include "GrProcOptInfo.h"
egdaniel378092f2014-12-03 10:40:13 -080014#include "GrTypes.h"
15#include "GrXferProcessor.h"
wangyixcef14bf2015-07-24 13:48:26 -070016#include "gl/GrGLBlend.h"
egdanielc2304142014-12-11 13:15:13 -080017#include "gl/GrGLXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080018#include "gl/builders/GrGLFragmentShaderBuilder.h"
19#include "gl/builders/GrGLProgramBuilder.h"
20
cdalton6fd158e2015-05-27 15:08:33 -070021/**
22 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
23 */
24struct BlendFormula {
25public:
26 /**
27 * Values the shader can write to primary and secondary outputs. These must all be modulated by
28 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080029 */
cdalton6fd158e2015-05-27 15:08:33 -070030 enum OutputType {
31 kNone_OutputType, //<! 0
32 kCoverage_OutputType, //<! inputCoverage
33 kModulate_OutputType, //<! inputColor * inputCoverage
egdaniel723b0502015-09-15 09:31:40 -070034 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
cdalton6fd158e2015-05-27 15:08:33 -070035 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
36 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
37
38 kLast_OutputType = kISCModulate_OutputType
39 };
40
41 enum Properties {
42 kModifiesDst_Property = 1,
43 kUsesDstColor_Property = 1 << 1,
44 kUsesInputColor_Property = 1 << 2,
45 kCanTweakAlphaForCoverage_Property = 1 << 3,
46
47 kLast_Property = kCanTweakAlphaForCoverage_Property
48 };
49
50 BlendFormula& operator =(const BlendFormula& other) {
51 fData = other.fData;
52 return *this;
53 }
54
55 bool operator ==(const BlendFormula& other) const {
56 return fData == other.fData;
57 }
58
59 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
60 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
61 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
62 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
63 bool canTweakAlphaForCoverage() const {
64 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
65 }
66
67 /**
68 * Deduce the properties of a compile-time constant BlendFormula.
69 */
70 template<OutputType PrimaryOut, OutputType SecondaryOut,
71 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
bungeman761cf612015-08-28 07:09:20 -070072 struct get_properties : skstd::integral_constant<Properties, static_cast<Properties>(
cdalton6fd158e2015-05-27 15:08:33 -070073
74 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
75 kModifiesDst_Property : 0) |
76
77 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
78 kUsesDstColor_Property : 0) |
79
80 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
81 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
82 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
83
84 (kModulate_OutputType == PrimaryOut &&
85 kNone_OutputType == SecondaryOut &&
86 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
87 kCanTweakAlphaForCoverage_Property : 0))> {
88
89 // The provided formula should already be optimized.
90 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
91 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
92 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
93 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
94 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
95 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
96 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
97 };
98
99 union {
100 struct {
101 // We allot the enums one more bit than they require because MSVC seems to sign-extend
102 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
103 OutputType fPrimaryOutputType : 4;
104 OutputType fSecondaryOutputType : 4;
105 GrBlendEquation fBlendEquation : 6;
106 GrBlendCoeff fSrcCoeff : 6;
107 GrBlendCoeff fDstCoeff : 6;
108 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
109 };
110 uint32_t fData;
111 };
112
113 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
114 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
115 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
116 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
117};
118
119GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
120
121GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
122
123/**
124 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
125 */
126#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
127 {{{PRIMARY_OUT, \
128 SECONDARY_OUT, \
129 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
130 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
131 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
132
133/**
134 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
135 * Porter Duff formula.
136 */
137#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
138 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
139 BlendFormula::kNone_OutputType, \
140 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
141
142/**
egdaniel723b0502015-09-15 09:31:40 -0700143 * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
144 * LCD dst-out.
145 */
146#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
147 INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
148 BlendFormula::kNone_OutputType, \
149 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
150
151/**
cdalton6fd158e2015-05-27 15:08:33 -0700152 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
153 * the primary output type to none.
154 */
155#define DST_CLEAR_FORMULA \
156 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
157 BlendFormula::kNone_OutputType, \
158 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
159
160/**
161 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
162 * so we can set the primary output type to none.
163 */
164#define NO_DST_WRITE_FORMULA \
165 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
166 BlendFormula::kNone_OutputType, \
167 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
168
169/**
170 * When there is coverage, the equation with f=coverage is:
171 *
172 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
173 *
174 * This can be rewritten as:
175 *
176 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
177 *
178 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
179 * HW dst coeff with IS2C.
180 *
181 * Xfer modes: dst-atop (Sa!=1)
182 */
183#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
184 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
185 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
186 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
187
188/**
189 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
190 *
191 * D' = f * D * dstCoeff + (1-f) * D
192 *
193 * This can be rewritten as:
194 *
195 * D' = D - D * [f * (1 - dstCoeff)]
196 *
197 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
198 * subtract HW blend equation with coeffs of (DC, One).
199 *
200 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
201 */
202#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
203 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
204 BlendFormula::kNone_OutputType, \
205 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
206
207/**
208 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
209 *
210 * D' = f * S * srcCoeff + (1-f) * D
211 *
212 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
213 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
214 *
215 * Xfer modes (Sa!=1): src, src-in, src-out
216 */
217#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
218 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
219 BlendFormula::kCoverage_OutputType, \
220 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
221
222/**
223 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
224 * with and without an opaque input color. Optimization properties are deduced at compile time so we
225 * can make runtime decisions quickly. RGB coverage is not supported.
226 */
227static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
228
229 /*>> No coverage, input color unknown <<*/ {{
230
231 /* clear */ DST_CLEAR_FORMULA,
232 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
233 /* dst */ NO_DST_WRITE_FORMULA,
234 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
235 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
236 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
237 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
238 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
239 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
240 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
241 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
242 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
243 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
244 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
245 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
246
247 }, /*>> Has coverage, input color unknown <<*/ {
248
249 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
250 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
251 /* dst */ NO_DST_WRITE_FORMULA,
252 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
253 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
254 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
255 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
256 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
257 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
258 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
259 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
260 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
261 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
262 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
263 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
264
265 }}, /*>> No coverage, input color opaque <<*/ {{
266
267 /* clear */ DST_CLEAR_FORMULA,
268 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
269 /* dst */ NO_DST_WRITE_FORMULA,
270 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
271 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
272 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
273 /* dst-in */ NO_DST_WRITE_FORMULA,
274 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
275 /* dst-out */ DST_CLEAR_FORMULA,
276 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
277 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
278 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
279 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
280 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
281 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
282
283 }, /*>> Has coverage, input color opaque <<*/ {
284
285 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
286 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
287 /* dst */ NO_DST_WRITE_FORMULA,
288 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
289 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
290 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
291 /* dst-in */ NO_DST_WRITE_FORMULA,
292 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
293 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
294 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
295 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
296 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
297 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
298 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
299 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
300}}};
301
egdaniel723b0502015-09-15 09:31:40 -0700302static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
303 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
304 /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
305 /* dst */ NO_DST_WRITE_FORMULA,
306 /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
307 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
308 /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
309 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
310 /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
311 /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
312 /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
313 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
314 /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
315 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
316 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
317 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
318};
319
cdalton86ae0a92015-06-08 15:11:04 -0700320static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
321 const GrProcOptInfo& coveragePOI,
322 bool hasMixedSamples,
323 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700324 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
325 SkASSERT(!coveragePOI.isFourChannelOutput());
326
cdalton86ae0a92015-06-08 15:11:04 -0700327 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
328 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800329}
330
egdaniel723b0502015-09-15 09:31:40 -0700331static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
332 SkXfermode::Mode xfermode) {
333 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
334 SkASSERT(coveragePOI.isFourChannelOutput());
335
336 return gLCDBlendTable[xfermode];
337}
338
cdalton6fd158e2015-05-27 15:08:33 -0700339///////////////////////////////////////////////////////////////////////////////
340
egdaniel41d4f092015-02-09 07:51:00 -0800341class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800342public:
cdalton86ae0a92015-06-08 15:11:04 -0700343 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
344 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800345 }
egdaniel378092f2014-12-03 10:40:13 -0800346
mtklein36352bf2015-03-25 18:17:31 -0700347 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800348
mtklein36352bf2015-03-25 18:17:31 -0700349 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800350
cdalton6fd158e2015-05-27 15:08:33 -0700351 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700352
353private:
egdanielc19cdc22015-05-10 08:45:18 -0700354 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
355 const GrProcOptInfo& coveragePOI,
356 bool doesStencilWrite,
357 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700358 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700359
jvanverthcfc18862015-04-28 08:48:20 -0700360 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700361
cdaltonedbb31f2015-06-08 12:14:44 -0700362 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
363
cdaltonf4f2b442015-04-23 09:40:23 -0700364 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700365 blendInfo->fEquation = fBlendFormula.fBlendEquation;
366 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
367 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
368 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800369 }
370
mtklein36352bf2015-03-25 18:17:31 -0700371 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800372 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700373 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800374 }
375
cdalton6fd158e2015-05-27 15:08:33 -0700376 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800377
378 typedef GrXferProcessor INHERITED;
379};
380
381///////////////////////////////////////////////////////////////////////////////
382
cdalton6fd158e2015-05-27 15:08:33 -0700383static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
384 BlendFormula::OutputType outputType, const char* output,
385 const char* inColor, const char* inCoverage) {
386 switch (outputType) {
387 case BlendFormula::kNone_OutputType:
388 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
389 break;
390 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700391 // We can have a coverage formula while not reading coverage if there are mixed samples.
cdalton6fd158e2015-05-27 15:08:33 -0700392 fsBuilder->codeAppendf("%s = %s;",
393 output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
394 break;
395 case BlendFormula::kModulate_OutputType:
396 if (xp.readsCoverage()) {
397 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
398 } else {
399 fsBuilder->codeAppendf("%s = %s;", output, inColor);
400 }
401 break;
egdaniel723b0502015-09-15 09:31:40 -0700402 case BlendFormula::kSAModulate_OutputType:
403 if (xp.readsCoverage()) {
404 fsBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
405 } else {
406 fsBuilder->codeAppendf("%s = %s;", output, inColor);
407 }
408 break;
cdalton6fd158e2015-05-27 15:08:33 -0700409 case BlendFormula::kISAModulate_OutputType:
410 if (xp.readsCoverage()) {
411 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
412 } else {
413 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
414 }
415 break;
416 case BlendFormula::kISCModulate_OutputType:
417 if (xp.readsCoverage()) {
418 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
419 } else {
420 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
421 }
422 break;
423 default:
424 SkFAIL("Unsupported output type.");
425 break;
egdaniel3ad65702015-02-17 11:15:47 -0800426 }
427}
428
egdaniel41d4f092015-02-09 07:51:00 -0800429class GLPorterDuffXferProcessor : public GrGLXferProcessor {
430public:
cdalton6fd158e2015-05-27 15:08:33 -0700431 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800432 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700433 b->add32(SkToInt(xp.readsCoverage()) |
434 (xp.getBlendFormula().fPrimaryOutputType << 1) |
435 (xp.getBlendFormula().fSecondaryOutputType << 4));
436 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800437 };
438
439private:
cdaltonedbb31f2015-06-08 12:14:44 -0700440 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800441 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel29bee0f2015-04-29 11:54:42 -0700442 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
bungemanc33db932015-05-22 17:55:26 -0700443
cdalton6fd158e2015-05-27 15:08:33 -0700444 BlendFormula blendFormula = xp.getBlendFormula();
445 if (blendFormula.hasSecondaryOutput()) {
446 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
447 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800448 }
cdalton6fd158e2015-05-27 15:08:33 -0700449 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
450 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800451 }
452
cdalton6fd158e2015-05-27 15:08:33 -0700453 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800454
egdaniel378092f2014-12-03 10:40:13 -0800455 typedef GrGLXferProcessor INHERITED;
456};
457
458///////////////////////////////////////////////////////////////////////////////
459
cdalton6fd158e2015-05-27 15:08:33 -0700460void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
egdaniel41d4f092015-02-09 07:51:00 -0800461 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700462 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800463}
464
egdaniel41d4f092015-02-09 07:51:00 -0800465GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700466 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800467}
468
egdaniel95131432014-12-09 11:15:43 -0800469GrXferProcessor::OptFlags
egdanielc19cdc22015-05-10 08:45:18 -0700470PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
471 const GrProcOptInfo& coveragePOI,
472 bool doesStencilWrite,
473 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700474 const GrCaps& caps) {
bsalomon7765a472015-07-08 11:26:37 -0700475 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700476 if (!fBlendFormula.modifiesDst()) {
477 if (!doesStencilWrite) {
478 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
479 }
480 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
481 GrXferProcessor::kIgnoreCoverage_OptFlag |
482 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
483 } else {
484 if (!fBlendFormula.usesInputColor()) {
485 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
486 }
487 if (coveragePOI.isSolidWhite()) {
488 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
489 }
egdaniel723b0502015-09-15 09:31:40 -0700490 if (colorPOI.allStagesMultiplyInput() &&
491 fBlendFormula.canTweakAlphaForCoverage() &&
492 !coveragePOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700493 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
494 }
495 }
bungemanc33db932015-05-22 17:55:26 -0700496 return optFlags;
497}
498
cdalton6fd158e2015-05-27 15:08:33 -0700499///////////////////////////////////////////////////////////////////////////////
500
501class ShaderPDXferProcessor : public GrXferProcessor {
502public:
cdalton86ae0a92015-06-08 15:11:04 -0700503 ShaderPDXferProcessor(const DstTexture* dstTexture,
504 bool hasMixedSamples,
505 SkXfermode::Mode xfermode)
506 : INHERITED(dstTexture, true, hasMixedSamples)
507 , fXfermode(xfermode) {
508 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700509 }
510
cdalton6fd158e2015-05-27 15:08:33 -0700511 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700512
513 GrGLXferProcessor* createGLInstance() const override;
514
515 SkXfermode::Mode getXfermode() const { return fXfermode; }
516
517private:
cdalton6fd158e2015-05-27 15:08:33 -0700518 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
519 bool, GrColor*, const GrCaps&) override {
bsalomon7765a472015-07-08 11:26:37 -0700520 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700521 }
522
523 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
524
525 bool onIsEqual(const GrXferProcessor& xpBase) const override {
526 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
527 return fXfermode == xp.fXfermode;
528 }
529
530 const SkXfermode::Mode fXfermode;
531
532 typedef GrXferProcessor INHERITED;
533};
534
535///////////////////////////////////////////////////////////////////////////////
536
cdalton6fd158e2015-05-27 15:08:33 -0700537class GLShaderPDXferProcessor : public GrGLXferProcessor {
538public:
539 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
540 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
541 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800542 }
egdaniel87509242014-12-17 13:37:13 -0800543
cdalton6fd158e2015-05-27 15:08:33 -0700544private:
cdaltonedbb31f2015-06-08 12:14:44 -0700545 void emitBlendCodeForDstRead(GrGLXPBuilder* pb, const char* srcColor, const char* dstColor,
546 const char* outColor, const GrXferProcessor& proc) override {
547 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
548 GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800549
wangyixcef14bf2015-07-24 13:48:26 -0700550 GrGLBlend::AppendPorterDuffBlend(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdaniel95131432014-12-09 11:15:43 -0800551 }
552
cdalton6fd158e2015-05-27 15:08:33 -0700553 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700554
cdalton6fd158e2015-05-27 15:08:33 -0700555 typedef GrGLXferProcessor INHERITED;
556};
bungemanc33db932015-05-22 17:55:26 -0700557
cdalton6fd158e2015-05-27 15:08:33 -0700558///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700559
cdalton6fd158e2015-05-27 15:08:33 -0700560void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
561 GrProcessorKeyBuilder* b) const {
562 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700563}
564
cdalton6fd158e2015-05-27 15:08:33 -0700565GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700566 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800567}
568
egdaniel378092f2014-12-03 10:40:13 -0800569///////////////////////////////////////////////////////////////////////////////
570
egdaniel0d5fd112015-05-12 06:11:35 -0700571class PDLCDXferProcessor : public GrXferProcessor {
572public:
cdalton6fd158e2015-05-27 15:08:33 -0700573 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700574
575 ~PDLCDXferProcessor() override;
576
577 const char* name() const override { return "Porter Duff LCD"; }
578
579 GrGLXferProcessor* createGLInstance() const override;
580
egdaniel0d5fd112015-05-12 06:11:35 -0700581private:
582 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
583
584 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
585 const GrProcOptInfo& coveragePOI,
586 bool doesStencilWrite,
587 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700588 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700589
590 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
591
592 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
593 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
594 blendInfo->fDstBlend = kISC_GrBlendCoeff;
595 blendInfo->fBlendConstant = fBlendConstant;
596 }
597
598 bool onIsEqual(const GrXferProcessor& xpBase) const override {
599 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
600 if (fBlendConstant != xp.fBlendConstant ||
601 fAlpha != xp.fAlpha) {
602 return false;
603 }
604 return true;
605 }
606
607 GrColor fBlendConstant;
608 uint8_t fAlpha;
609
610 typedef GrXferProcessor INHERITED;
611};
612
613///////////////////////////////////////////////////////////////////////////////
614
615class GLPDLCDXferProcessor : public GrGLXferProcessor {
616public:
617 GLPDLCDXferProcessor(const GrProcessor&) {}
618
619 virtual ~GLPDLCDXferProcessor() {}
620
621 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
622 GrProcessorKeyBuilder* b) {}
623
624private:
cdaltonedbb31f2015-06-08 12:14:44 -0700625 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel0d5fd112015-05-12 06:11:35 -0700626 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel0d5fd112015-05-12 06:11:35 -0700627 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
628 args.fInputCoverage);
629 }
630
631 void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
632
633 typedef GrGLXferProcessor INHERITED;
634};
635
636///////////////////////////////////////////////////////////////////////////////
637
638PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
639 : fBlendConstant(blendConstant)
640 , fAlpha(alpha) {
641 this->initClassID<PDLCDXferProcessor>();
642}
643
cdalton6fd158e2015-05-27 15:08:33 -0700644GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700645 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700646 if (SkXfermode::kSrcOver_Mode != xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700647 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700648 }
649
650 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700651 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700652 }
653
654 GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
655 uint8_t alpha = GrColorUnpackA(blendConstant);
656 blendConstant |= (0xff << GrColor_SHIFT_A);
657
halcanary385fe4d2015-08-26 13:07:48 -0700658 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700659}
660
661PDLCDXferProcessor::~PDLCDXferProcessor() {
662}
663
664void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
665 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700666 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700667}
668
669GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700670 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700671}
672
673GrXferProcessor::OptFlags
674PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
675 const GrProcOptInfo& coveragePOI,
676 bool doesStencilWrite,
677 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700678 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700679 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
680 // value of the blend the constant. We should already have valid blend coeff's if we are at
681 // a point where we have RGB coverage. We don't need any color stages since the known color
682 // output is already baked into the blendConstant.
683 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
684 return GrXferProcessor::kOverrideColor_OptFlag;
685}
686
687///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700688
689GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
690 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700691 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdaniel915187b2014-12-05 12:58:28 -0800692 this->initClassID<GrPorterDuffXPFactory>();
693}
694
cdalton6fd158e2015-05-27 15:08:33 -0700695GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
696 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
697 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
698 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
699 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
700 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
701 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
702 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
703 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
704 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
705 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
706 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
707 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
708 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
709 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
710 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
711
712 static GrPorterDuffXPFactory* gFactories[] = {
713 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
714 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
715 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
716 };
717 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
718
719 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700720 return nullptr;
egdanielc016fb82014-12-03 11:41:54 -0800721 }
cdalton6fd158e2015-05-27 15:08:33 -0700722 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800723}
724
bsalomon50785a32015-02-06 07:02:37 -0800725GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700726GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800727 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800728 const GrProcOptInfo& covPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700729 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700730 const DstTexture* dstTexture) const {
egdaniel723b0502015-09-15 09:31:40 -0700731 BlendFormula blendFormula;
egdaniel0d5fd112015-05-12 06:11:35 -0700732 if (covPOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700733 if (SkXfermode::kSrcOver_Mode == fXfermode &&
734 kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
735 SkASSERT(!dstTexture || !dstTexture->texture());
736 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
737 }
738 blendFormula = get_lcd_blend_formula(covPOI, fXfermode);
739 } else {
740 blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
egdaniel95131432014-12-09 11:15:43 -0800741 }
cdalton6fd158e2015-05-27 15:08:33 -0700742
cdalton6fd158e2015-05-27 15:08:33 -0700743 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700744 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700745 }
746
747 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700748 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800749}
750
cdalton1fa45722015-06-02 10:43:39 -0700751void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
752 InvariantBlendedColor* blendedColor) const {
753 // Find the blended color info based on the formula that does not have coverage.
754 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
755 if (colorFormula.usesDstColor()) {
756 blendedColor->fWillBlendWithDst = true;
757 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800758 return;
egdaniel95131432014-12-09 11:15:43 -0800759 }
760
cdalton1fa45722015-06-02 10:43:39 -0700761 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700762
cdalton1fa45722015-06-02 10:43:39 -0700763 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700764
cdalton1fa45722015-06-02 10:43:39 -0700765 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800766 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700767 blendedColor->fKnownColor = 0;
768 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700769 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800770
771 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700772 blendedColor->fKnownColor = colorPOI.color();
773 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700774 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800775
cdalton1fa45722015-06-02 10:43:39 -0700776 default:
777 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
778 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800779 }
egdaniel95131432014-12-09 11:15:43 -0800780}
781
bsalomon4b91f762015-05-19 09:29:46 -0700782bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800783 const GrProcOptInfo& colorPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700784 const GrProcOptInfo& covPOI,
785 bool hasMixedSamples) const {
786 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
787 return false;
bungemanc33db932015-05-22 17:55:26 -0700788 }
egdaniel723b0502015-09-15 09:31:40 -0700789
790 // When we have four channel coverage we always need to read the dst in order to correctly
791 // blend. The one exception is when we are using srcover mode and we know the input color into
792 // the XP.
cdalton86ae0a92015-06-08 15:11:04 -0700793 if (covPOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700794 if (SkXfermode::kSrcOver_Mode == fXfermode &&
795 kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
796 return false;
797 }
798 return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput();
cdalton86ae0a92015-06-08 15:11:04 -0700799 }
cdalton6fd158e2015-05-27 15:08:33 -0700800 // We fallback on the shader XP when the blend formula would use dual source blending but we
801 // don't have support for it.
cdalton86ae0a92015-06-08 15:11:04 -0700802 return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800803}
804
egdanielc2304142014-12-11 13:15:13 -0800805GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
806
bsalomonc21b09e2015-08-28 18:46:56 -0700807const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700808 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
egdanielb197b8f2015-02-17 07:34:43 -0800809 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800810}
egdaniel95131432014-12-09 11:15:43 -0800811
cdalton6fd158e2015-05-27 15:08:33 -0700812void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
813 int* outPrimary,
814 int* outSecondary) {
815 if (!!strcmp(xp->name(), "Porter Duff")) {
816 *outPrimary = *outSecondary = -1;
817 return;
818 }
819 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
820 *outPrimary = blendFormula.fPrimaryOutputType;
821 *outSecondary = blendFormula.fSecondaryOutputType;
822}