blob: a7f390a5dc5844fafaf25e23ddeee35807fcebce [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"
bsalomonae4738f2015-09-15 15:33:27 -070016#include "gl/GrGLSLBlend.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"
egdaniel018fb622015-10-28 07:26:40 -070020#include "glsl/GrGLSLProgramDataManager.h"
egdaniel378092f2014-12-03 10:40:13 -080021
cdalton6fd158e2015-05-27 15:08:33 -070022/**
23 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
24 */
25struct BlendFormula {
26public:
27 /**
28 * Values the shader can write to primary and secondary outputs. These must all be modulated by
29 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080030 */
cdalton6fd158e2015-05-27 15:08:33 -070031 enum OutputType {
32 kNone_OutputType, //<! 0
33 kCoverage_OutputType, //<! inputCoverage
34 kModulate_OutputType, //<! inputColor * inputCoverage
egdaniel723b0502015-09-15 09:31:40 -070035 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
cdalton6fd158e2015-05-27 15:08:33 -070036 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
37 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
38
39 kLast_OutputType = kISCModulate_OutputType
40 };
41
42 enum Properties {
43 kModifiesDst_Property = 1,
44 kUsesDstColor_Property = 1 << 1,
45 kUsesInputColor_Property = 1 << 2,
46 kCanTweakAlphaForCoverage_Property = 1 << 3,
47
48 kLast_Property = kCanTweakAlphaForCoverage_Property
49 };
50
51 BlendFormula& operator =(const BlendFormula& other) {
52 fData = other.fData;
53 return *this;
54 }
55
56 bool operator ==(const BlendFormula& other) const {
57 return fData == other.fData;
58 }
59
60 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
61 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
62 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
63 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
64 bool canTweakAlphaForCoverage() const {
65 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
66 }
67
68 /**
69 * Deduce the properties of a compile-time constant BlendFormula.
70 */
71 template<OutputType PrimaryOut, OutputType SecondaryOut,
72 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
bungeman761cf612015-08-28 07:09:20 -070073 struct get_properties : skstd::integral_constant<Properties, static_cast<Properties>(
cdalton6fd158e2015-05-27 15:08:33 -070074
75 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
76 kModifiesDst_Property : 0) |
77
78 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
79 kUsesDstColor_Property : 0) |
80
81 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
82 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
83 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
84
85 (kModulate_OutputType == PrimaryOut &&
86 kNone_OutputType == SecondaryOut &&
87 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
88 kCanTweakAlphaForCoverage_Property : 0))> {
89
90 // The provided formula should already be optimized.
91 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
92 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
93 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
94 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
95 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
96 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
97 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
98 };
99
100 union {
101 struct {
102 // We allot the enums one more bit than they require because MSVC seems to sign-extend
103 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
104 OutputType fPrimaryOutputType : 4;
105 OutputType fSecondaryOutputType : 4;
106 GrBlendEquation fBlendEquation : 6;
107 GrBlendCoeff fSrcCoeff : 6;
108 GrBlendCoeff fDstCoeff : 6;
109 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
110 };
111 uint32_t fData;
112 };
113
114 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
115 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
116 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
117 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
118};
119
120GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
121
122GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
123
124/**
125 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
126 */
127#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
128 {{{PRIMARY_OUT, \
129 SECONDARY_OUT, \
130 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
131 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
132 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
133
134/**
135 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
136 * Porter Duff formula.
137 */
138#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
139 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
140 BlendFormula::kNone_OutputType, \
141 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
142
143/**
egdaniel723b0502015-09-15 09:31:40 -0700144 * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
145 * LCD dst-out.
146 */
147#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
148 INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
149 BlendFormula::kNone_OutputType, \
150 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
151
152/**
cdalton6fd158e2015-05-27 15:08:33 -0700153 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
154 * the primary output type to none.
155 */
156#define DST_CLEAR_FORMULA \
157 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
158 BlendFormula::kNone_OutputType, \
159 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
160
161/**
162 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
163 * so we can set the primary output type to none.
164 */
165#define NO_DST_WRITE_FORMULA \
166 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
167 BlendFormula::kNone_OutputType, \
168 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
169
170/**
171 * When there is coverage, the equation with f=coverage is:
172 *
173 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
174 *
175 * This can be rewritten as:
176 *
177 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
178 *
179 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
180 * HW dst coeff with IS2C.
181 *
182 * Xfer modes: dst-atop (Sa!=1)
183 */
184#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
185 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
186 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
187 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
188
189/**
190 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
191 *
192 * D' = f * D * dstCoeff + (1-f) * D
193 *
194 * This can be rewritten as:
195 *
196 * D' = D - D * [f * (1 - dstCoeff)]
197 *
198 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
199 * subtract HW blend equation with coeffs of (DC, One).
200 *
201 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
202 */
203#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
204 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
205 BlendFormula::kNone_OutputType, \
206 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
207
208/**
209 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
210 *
211 * D' = f * S * srcCoeff + (1-f) * D
212 *
213 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
214 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
215 *
216 * Xfer modes (Sa!=1): src, src-in, src-out
217 */
218#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
219 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
220 BlendFormula::kCoverage_OutputType, \
221 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
222
223/**
224 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
225 * with and without an opaque input color. Optimization properties are deduced at compile time so we
226 * can make runtime decisions quickly. RGB coverage is not supported.
227 */
228static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
229
230 /*>> No coverage, input color unknown <<*/ {{
231
232 /* clear */ DST_CLEAR_FORMULA,
233 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
234 /* dst */ NO_DST_WRITE_FORMULA,
235 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
236 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
237 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
238 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
239 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
240 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
241 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
242 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
243 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
244 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
245 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
246 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
247
248 }, /*>> Has coverage, input color unknown <<*/ {
249
250 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
251 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
252 /* dst */ NO_DST_WRITE_FORMULA,
253 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
254 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
255 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
256 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
257 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
258 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
259 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
260 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
261 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
262 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
263 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
264 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
265
266 }}, /*>> No coverage, input color opaque <<*/ {{
267
268 /* clear */ DST_CLEAR_FORMULA,
269 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
270 /* dst */ NO_DST_WRITE_FORMULA,
271 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
272 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
273 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
274 /* dst-in */ NO_DST_WRITE_FORMULA,
275 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
276 /* dst-out */ DST_CLEAR_FORMULA,
277 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
278 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
279 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
280 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
281 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
282 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
283
284 }, /*>> Has coverage, input color opaque <<*/ {
285
286 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
287 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
288 /* dst */ NO_DST_WRITE_FORMULA,
289 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
290 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
291 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
292 /* dst-in */ NO_DST_WRITE_FORMULA,
293 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
294 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
295 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
296 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
297 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
298 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
299 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
300 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
301}}};
302
egdaniel723b0502015-09-15 09:31:40 -0700303static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
304 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
305 /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
306 /* dst */ NO_DST_WRITE_FORMULA,
307 /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
308 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
309 /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
310 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
311 /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
312 /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
313 /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
314 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
315 /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
316 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
317 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
318 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
319};
320
cdalton86ae0a92015-06-08 15:11:04 -0700321static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
322 const GrProcOptInfo& coveragePOI,
323 bool hasMixedSamples,
324 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700325 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
326 SkASSERT(!coveragePOI.isFourChannelOutput());
327
cdalton86ae0a92015-06-08 15:11:04 -0700328 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
329 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800330}
331
egdaniel723b0502015-09-15 09:31:40 -0700332static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
333 SkXfermode::Mode xfermode) {
334 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
335 SkASSERT(coveragePOI.isFourChannelOutput());
336
337 return gLCDBlendTable[xfermode];
338}
339
cdalton6fd158e2015-05-27 15:08:33 -0700340///////////////////////////////////////////////////////////////////////////////
341
egdaniel41d4f092015-02-09 07:51:00 -0800342class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800343public:
cdalton86ae0a92015-06-08 15:11:04 -0700344 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
345 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800346 }
egdaniel378092f2014-12-03 10:40:13 -0800347
mtklein36352bf2015-03-25 18:17:31 -0700348 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800349
mtklein36352bf2015-03-25 18:17:31 -0700350 GrGLXferProcessor* createGLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800351
cdalton6fd158e2015-05-27 15:08:33 -0700352 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700353
354private:
egdanielc19cdc22015-05-10 08:45:18 -0700355 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
356 const GrProcOptInfo& coveragePOI,
357 bool doesStencilWrite,
358 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700359 const GrCaps& caps) override;
egdanielc19cdc22015-05-10 08:45:18 -0700360
jvanverthcfc18862015-04-28 08:48:20 -0700361 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700362
cdaltonedbb31f2015-06-08 12:14:44 -0700363 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
364
cdaltonf4f2b442015-04-23 09:40:23 -0700365 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700366 blendInfo->fEquation = fBlendFormula.fBlendEquation;
367 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
368 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
369 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800370 }
371
mtklein36352bf2015-03-25 18:17:31 -0700372 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800373 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700374 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800375 }
376
cdalton6fd158e2015-05-27 15:08:33 -0700377 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800378
379 typedef GrXferProcessor INHERITED;
380};
381
382///////////////////////////////////////////////////////////////////////////////
383
cdalton6fd158e2015-05-27 15:08:33 -0700384static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
385 BlendFormula::OutputType outputType, const char* output,
386 const char* inColor, const char* inCoverage) {
387 switch (outputType) {
388 case BlendFormula::kNone_OutputType:
389 fsBuilder->codeAppendf("%s = vec4(0.0);", output);
390 break;
391 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700392 // We can have a coverage formula while not reading coverage if there are mixed samples.
cdalton6fd158e2015-05-27 15:08:33 -0700393 fsBuilder->codeAppendf("%s = %s;",
394 output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
395 break;
396 case BlendFormula::kModulate_OutputType:
397 if (xp.readsCoverage()) {
398 fsBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
399 } else {
400 fsBuilder->codeAppendf("%s = %s;", output, inColor);
401 }
402 break;
egdaniel723b0502015-09-15 09:31:40 -0700403 case BlendFormula::kSAModulate_OutputType:
404 if (xp.readsCoverage()) {
405 fsBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
406 } else {
407 fsBuilder->codeAppendf("%s = %s;", output, inColor);
408 }
409 break;
cdalton6fd158e2015-05-27 15:08:33 -0700410 case BlendFormula::kISAModulate_OutputType:
411 if (xp.readsCoverage()) {
412 fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
413 } else {
414 fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
415 }
416 break;
417 case BlendFormula::kISCModulate_OutputType:
418 if (xp.readsCoverage()) {
419 fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
420 } else {
421 fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
422 }
423 break;
424 default:
425 SkFAIL("Unsupported output type.");
426 break;
egdaniel3ad65702015-02-17 11:15:47 -0800427 }
428}
429
egdaniel41d4f092015-02-09 07:51:00 -0800430class GLPorterDuffXferProcessor : public GrGLXferProcessor {
431public:
cdalton6fd158e2015-05-27 15:08:33 -0700432 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800433 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700434 b->add32(SkToInt(xp.readsCoverage()) |
435 (xp.getBlendFormula().fPrimaryOutputType << 1) |
436 (xp.getBlendFormula().fSecondaryOutputType << 4));
437 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800438 };
439
440private:
cdaltonedbb31f2015-06-08 12:14:44 -0700441 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800442 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel29bee0f2015-04-29 11:54:42 -0700443 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
bungemanc33db932015-05-22 17:55:26 -0700444
cdalton6fd158e2015-05-27 15:08:33 -0700445 BlendFormula blendFormula = xp.getBlendFormula();
446 if (blendFormula.hasSecondaryOutput()) {
447 append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
448 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800449 }
cdalton6fd158e2015-05-27 15:08:33 -0700450 append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
451 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800452 }
453
egdaniel018fb622015-10-28 07:26:40 -0700454 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800455
egdaniel378092f2014-12-03 10:40:13 -0800456 typedef GrGLXferProcessor INHERITED;
457};
458
459///////////////////////////////////////////////////////////////////////////////
460
cdalton6fd158e2015-05-27 15:08:33 -0700461void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
egdaniel41d4f092015-02-09 07:51:00 -0800462 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700463 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800464}
465
egdaniel41d4f092015-02-09 07:51:00 -0800466GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700467 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800468}
469
egdaniel95131432014-12-09 11:15:43 -0800470GrXferProcessor::OptFlags
egdanielc19cdc22015-05-10 08:45:18 -0700471PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
472 const GrProcOptInfo& coveragePOI,
473 bool doesStencilWrite,
474 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700475 const GrCaps& caps) {
bsalomon7765a472015-07-08 11:26:37 -0700476 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700477 if (!fBlendFormula.modifiesDst()) {
478 if (!doesStencilWrite) {
479 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
480 }
481 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
482 GrXferProcessor::kIgnoreCoverage_OptFlag |
483 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
484 } else {
485 if (!fBlendFormula.usesInputColor()) {
486 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
487 }
488 if (coveragePOI.isSolidWhite()) {
489 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
490 }
egdaniel723b0502015-09-15 09:31:40 -0700491 if (colorPOI.allStagesMultiplyInput() &&
492 fBlendFormula.canTweakAlphaForCoverage() &&
493 !coveragePOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700494 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
495 }
496 }
bungemanc33db932015-05-22 17:55:26 -0700497 return optFlags;
498}
499
cdalton6fd158e2015-05-27 15:08:33 -0700500///////////////////////////////////////////////////////////////////////////////
501
502class ShaderPDXferProcessor : public GrXferProcessor {
503public:
cdalton86ae0a92015-06-08 15:11:04 -0700504 ShaderPDXferProcessor(const DstTexture* dstTexture,
505 bool hasMixedSamples,
506 SkXfermode::Mode xfermode)
507 : INHERITED(dstTexture, true, hasMixedSamples)
508 , fXfermode(xfermode) {
509 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700510 }
511
cdalton6fd158e2015-05-27 15:08:33 -0700512 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700513
514 GrGLXferProcessor* createGLInstance() const override;
515
516 SkXfermode::Mode getXfermode() const { return fXfermode; }
517
518private:
cdalton6fd158e2015-05-27 15:08:33 -0700519 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
520 bool, GrColor*, const GrCaps&) override {
bsalomon7765a472015-07-08 11:26:37 -0700521 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700522 }
523
524 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
525
526 bool onIsEqual(const GrXferProcessor& xpBase) const override {
527 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
528 return fXfermode == xp.fXfermode;
529 }
530
531 const SkXfermode::Mode fXfermode;
532
533 typedef GrXferProcessor INHERITED;
534};
535
536///////////////////////////////////////////////////////////////////////////////
537
cdalton6fd158e2015-05-27 15:08:33 -0700538class GLShaderPDXferProcessor : public GrGLXferProcessor {
539public:
540 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
541 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
542 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800543 }
egdaniel87509242014-12-17 13:37:13 -0800544
cdalton6fd158e2015-05-27 15:08:33 -0700545private:
cdaltonedbb31f2015-06-08 12:14:44 -0700546 void emitBlendCodeForDstRead(GrGLXPBuilder* pb, const char* srcColor, const char* dstColor,
547 const char* outColor, const GrXferProcessor& proc) override {
548 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
549 GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
egdaniel95131432014-12-09 11:15:43 -0800550
bsalomonae4738f2015-09-15 15:33:27 -0700551 GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdaniel95131432014-12-09 11:15:43 -0800552 }
553
egdaniel018fb622015-10-28 07:26:40 -0700554 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700555
cdalton6fd158e2015-05-27 15:08:33 -0700556 typedef GrGLXferProcessor INHERITED;
557};
bungemanc33db932015-05-22 17:55:26 -0700558
cdalton6fd158e2015-05-27 15:08:33 -0700559///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700560
cdalton6fd158e2015-05-27 15:08:33 -0700561void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
562 GrProcessorKeyBuilder* b) const {
563 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700564}
565
cdalton6fd158e2015-05-27 15:08:33 -0700566GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700567 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800568}
569
egdaniel378092f2014-12-03 10:40:13 -0800570///////////////////////////////////////////////////////////////////////////////
571
egdaniel0d5fd112015-05-12 06:11:35 -0700572class PDLCDXferProcessor : public GrXferProcessor {
573public:
cdalton6fd158e2015-05-27 15:08:33 -0700574 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700575
576 ~PDLCDXferProcessor() override;
577
578 const char* name() const override { return "Porter Duff LCD"; }
579
580 GrGLXferProcessor* createGLInstance() const override;
581
egdaniel0d5fd112015-05-12 06:11:35 -0700582private:
583 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
584
585 GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
586 const GrProcOptInfo& coveragePOI,
587 bool doesStencilWrite,
588 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700589 const GrCaps& caps) override;
egdaniel0d5fd112015-05-12 06:11:35 -0700590
591 void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
592
593 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
594 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
595 blendInfo->fDstBlend = kISC_GrBlendCoeff;
596 blendInfo->fBlendConstant = fBlendConstant;
597 }
598
599 bool onIsEqual(const GrXferProcessor& xpBase) const override {
600 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
601 if (fBlendConstant != xp.fBlendConstant ||
602 fAlpha != xp.fAlpha) {
603 return false;
604 }
605 return true;
606 }
607
608 GrColor fBlendConstant;
609 uint8_t fAlpha;
610
611 typedef GrXferProcessor INHERITED;
612};
613
614///////////////////////////////////////////////////////////////////////////////
615
616class GLPDLCDXferProcessor : public GrGLXferProcessor {
617public:
618 GLPDLCDXferProcessor(const GrProcessor&) {}
619
620 virtual ~GLPDLCDXferProcessor() {}
621
622 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
623 GrProcessorKeyBuilder* b) {}
624
625private:
cdaltonedbb31f2015-06-08 12:14:44 -0700626 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel0d5fd112015-05-12 06:11:35 -0700627 GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel0d5fd112015-05-12 06:11:35 -0700628 fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
629 args.fInputCoverage);
630 }
631
egdaniel018fb622015-10-28 07:26:40 -0700632 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {};
egdaniel0d5fd112015-05-12 06:11:35 -0700633
634 typedef GrGLXferProcessor INHERITED;
635};
636
637///////////////////////////////////////////////////////////////////////////////
638
639PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
640 : fBlendConstant(blendConstant)
641 , fAlpha(alpha) {
642 this->initClassID<PDLCDXferProcessor>();
643}
644
cdalton6fd158e2015-05-27 15:08:33 -0700645GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700646 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700647 if (SkXfermode::kSrcOver_Mode != xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700648 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700649 }
650
651 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700652 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700653 }
654
bsalomonae4738f2015-09-15 15:33:27 -0700655 GrColor blendConstant = GrUnpremulColor(colorPOI.color());
egdaniel0d5fd112015-05-12 06:11:35 -0700656 uint8_t alpha = GrColorUnpackA(blendConstant);
657 blendConstant |= (0xff << GrColor_SHIFT_A);
658
halcanary385fe4d2015-08-26 13:07:48 -0700659 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700660}
661
662PDLCDXferProcessor::~PDLCDXferProcessor() {
663}
664
665void PDLCDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
666 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700667 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700668}
669
670GrGLXferProcessor* PDLCDXferProcessor::createGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700671 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700672}
673
674GrXferProcessor::OptFlags
675PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
676 const GrProcOptInfo& coveragePOI,
677 bool doesStencilWrite,
678 GrColor* overrideColor,
bsalomon4b91f762015-05-19 09:29:46 -0700679 const GrCaps& caps) {
egdaniel0d5fd112015-05-12 06:11:35 -0700680 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
681 // value of the blend the constant. We should already have valid blend coeff's if we are at
682 // a point where we have RGB coverage. We don't need any color stages since the known color
683 // output is already baked into the blendConstant.
684 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
685 return GrXferProcessor::kOverrideColor_OptFlag;
686}
687
688///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700689
690GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
691 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700692 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdaniel915187b2014-12-05 12:58:28 -0800693 this->initClassID<GrPorterDuffXPFactory>();
694}
695
cdalton6fd158e2015-05-27 15:08:33 -0700696GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
697 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
698 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
699 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
700 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
701 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
702 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
703 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
704 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
705 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
706 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
707 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
708 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
709 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
710 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
711 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
712
713 static GrPorterDuffXPFactory* gFactories[] = {
714 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
715 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
716 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
717 };
718 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
719
720 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700721 return nullptr;
egdanielc016fb82014-12-03 11:41:54 -0800722 }
cdalton6fd158e2015-05-27 15:08:33 -0700723 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800724}
725
bsalomon50785a32015-02-06 07:02:37 -0800726GrXferProcessor*
bsalomon4b91f762015-05-19 09:29:46 -0700727GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800728 const GrProcOptInfo& colorPOI,
bsalomon50785a32015-02-06 07:02:37 -0800729 const GrProcOptInfo& covPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700730 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700731 const DstTexture* dstTexture) const {
egdaniel723b0502015-09-15 09:31:40 -0700732 BlendFormula blendFormula;
egdaniel0d5fd112015-05-12 06:11:35 -0700733 if (covPOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700734 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniele73f1f62015-09-22 10:10:55 -0700735 kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
736 !caps.shaderCaps()->dualSourceBlendingSupport() &&
737 !caps.shaderCaps()->dstReadInShaderSupport()) {
738 // If we don't have dual source blending or in shader dst reads, we fall back to this
739 // trick for rendering SrcOver LCD text instead of doing a dst copy.
egdaniel723b0502015-09-15 09:31:40 -0700740 SkASSERT(!dstTexture || !dstTexture->texture());
741 return PDLCDXferProcessor::Create(fXfermode, colorPOI);
742 }
743 blendFormula = get_lcd_blend_formula(covPOI, fXfermode);
744 } else {
745 blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
egdaniel95131432014-12-09 11:15:43 -0800746 }
cdalton6fd158e2015-05-27 15:08:33 -0700747
cdalton6fd158e2015-05-27 15:08:33 -0700748 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700749 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700750 }
751
752 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700753 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800754}
755
cdalton1fa45722015-06-02 10:43:39 -0700756void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
757 InvariantBlendedColor* blendedColor) const {
758 // Find the blended color info based on the formula that does not have coverage.
759 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
760 if (colorFormula.usesDstColor()) {
761 blendedColor->fWillBlendWithDst = true;
762 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800763 return;
egdaniel95131432014-12-09 11:15:43 -0800764 }
765
cdalton1fa45722015-06-02 10:43:39 -0700766 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700767
cdalton1fa45722015-06-02 10:43:39 -0700768 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700769
cdalton1fa45722015-06-02 10:43:39 -0700770 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800771 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700772 blendedColor->fKnownColor = 0;
773 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700774 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800775
776 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700777 blendedColor->fKnownColor = colorPOI.color();
778 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700779 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800780
cdalton1fa45722015-06-02 10:43:39 -0700781 default:
782 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
783 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800784 }
egdaniel95131432014-12-09 11:15:43 -0800785}
786
bsalomon4b91f762015-05-19 09:29:46 -0700787bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
egdaniel3ad65702015-02-17 11:15:47 -0800788 const GrProcOptInfo& colorPOI,
cdalton86ae0a92015-06-08 15:11:04 -0700789 const GrProcOptInfo& covPOI,
790 bool hasMixedSamples) const {
791 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
792 return false;
bungemanc33db932015-05-22 17:55:26 -0700793 }
egdaniel723b0502015-09-15 09:31:40 -0700794
795 // When we have four channel coverage we always need to read the dst in order to correctly
796 // blend. The one exception is when we are using srcover mode and we know the input color into
797 // the XP.
cdalton86ae0a92015-06-08 15:11:04 -0700798 if (covPOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700799 if (SkXfermode::kSrcOver_Mode == fXfermode &&
egdaniele73f1f62015-09-22 10:10:55 -0700800 kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
801 !caps.shaderCaps()->dstReadInShaderSupport()) {
egdaniel723b0502015-09-15 09:31:40 -0700802 return false;
803 }
804 return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput();
cdalton86ae0a92015-06-08 15:11:04 -0700805 }
cdalton6fd158e2015-05-27 15:08:33 -0700806 // We fallback on the shader XP when the blend formula would use dual source blending but we
807 // don't have support for it.
cdalton86ae0a92015-06-08 15:11:04 -0700808 return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800809}
810
egdanielc2304142014-12-11 13:15:13 -0800811GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
812
bsalomonc21b09e2015-08-28 18:46:56 -0700813const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700814 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
egdanielb197b8f2015-02-17 07:34:43 -0800815 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800816}
egdaniel95131432014-12-09 11:15:43 -0800817
cdalton6fd158e2015-05-27 15:08:33 -0700818void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
819 int* outPrimary,
820 int* outSecondary) {
821 if (!!strcmp(xp->name(), "Porter Duff")) {
822 *outPrimary = *outSecondary = -1;
823 return;
824 }
825 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
826 *outPrimary = blendFormula.fPrimaryOutputType;
827 *outSecondary = blendFormula.fSecondaryOutputType;
828}