blob: 11af4b6aa02404f5518f8b32883db8346fbc9174 [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"
ethannicholasde4166a2015-11-30 08:57:38 -080012#include "GrPipeline.h"
egdaniel378092f2014-12-03 10:40:13 -080013#include "GrProcessor.h"
egdaniel87509242014-12-17 13:37:13 -080014#include "GrProcOptInfo.h"
egdaniel378092f2014-12-03 10:40:13 -080015#include "GrTypes.h"
16#include "GrXferProcessor.h"
egdaniel64c47282015-11-13 06:54:19 -080017#include "glsl/GrGLSLBlend.h"
egdaniel2d721d32015-11-11 13:06:05 -080018#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070019#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080020#include "glsl/GrGLSLUniformHandler.h"
egdanielfa4cc8b2015-11-13 08:34:52 -080021#include "glsl/GrGLSLXferProcessor.h"
egdaniel378092f2014-12-03 10:40:13 -080022
cdalton6fd158e2015-05-27 15:08:33 -070023/**
24 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
25 */
26struct BlendFormula {
27public:
28 /**
29 * Values the shader can write to primary and secondary outputs. These must all be modulated by
30 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080031 */
cdalton6fd158e2015-05-27 15:08:33 -070032 enum OutputType {
33 kNone_OutputType, //<! 0
34 kCoverage_OutputType, //<! inputCoverage
35 kModulate_OutputType, //<! inputColor * inputCoverage
egdaniel723b0502015-09-15 09:31:40 -070036 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
cdalton6fd158e2015-05-27 15:08:33 -070037 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
38 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
39
40 kLast_OutputType = kISCModulate_OutputType
41 };
42
43 enum Properties {
44 kModifiesDst_Property = 1,
45 kUsesDstColor_Property = 1 << 1,
46 kUsesInputColor_Property = 1 << 2,
47 kCanTweakAlphaForCoverage_Property = 1 << 3,
48
49 kLast_Property = kCanTweakAlphaForCoverage_Property
50 };
51
52 BlendFormula& operator =(const BlendFormula& other) {
53 fData = other.fData;
54 return *this;
55 }
56
57 bool operator ==(const BlendFormula& other) const {
58 return fData == other.fData;
59 }
60
61 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
62 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
63 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
64 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
65 bool canTweakAlphaForCoverage() const {
66 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
67 }
68
69 /**
70 * Deduce the properties of a compile-time constant BlendFormula.
71 */
72 template<OutputType PrimaryOut, OutputType SecondaryOut,
73 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
bungeman761cf612015-08-28 07:09:20 -070074 struct get_properties : skstd::integral_constant<Properties, static_cast<Properties>(
cdalton6fd158e2015-05-27 15:08:33 -070075
76 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
77 kModifiesDst_Property : 0) |
78
79 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
80 kUsesDstColor_Property : 0) |
81
82 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
83 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
84 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
85
86 (kModulate_OutputType == PrimaryOut &&
87 kNone_OutputType == SecondaryOut &&
88 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
89 kCanTweakAlphaForCoverage_Property : 0))> {
90
91 // The provided formula should already be optimized.
92 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
93 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
94 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
95 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
96 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
97 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
98 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
99 };
100
101 union {
102 struct {
103 // We allot the enums one more bit than they require because MSVC seems to sign-extend
104 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
105 OutputType fPrimaryOutputType : 4;
106 OutputType fSecondaryOutputType : 4;
107 GrBlendEquation fBlendEquation : 6;
108 GrBlendCoeff fSrcCoeff : 6;
109 GrBlendCoeff fDstCoeff : 6;
110 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
111 };
112 uint32_t fData;
113 };
114
115 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
116 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
117 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
118 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
119};
120
121GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
122
123GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
124
125/**
126 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
127 */
128#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
129 {{{PRIMARY_OUT, \
130 SECONDARY_OUT, \
131 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
132 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
133 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
134
135/**
136 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
137 * Porter Duff formula.
138 */
139#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
140 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
141 BlendFormula::kNone_OutputType, \
142 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
143
144/**
egdaniel723b0502015-09-15 09:31:40 -0700145 * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
146 * LCD dst-out.
147 */
148#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
149 INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
150 BlendFormula::kNone_OutputType, \
151 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
152
153/**
cdalton6fd158e2015-05-27 15:08:33 -0700154 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
155 * the primary output type to none.
156 */
157#define DST_CLEAR_FORMULA \
158 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
159 BlendFormula::kNone_OutputType, \
160 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
161
162/**
163 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
164 * so we can set the primary output type to none.
165 */
166#define NO_DST_WRITE_FORMULA \
167 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
168 BlendFormula::kNone_OutputType, \
169 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
170
171/**
172 * When there is coverage, the equation with f=coverage is:
173 *
174 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
175 *
176 * This can be rewritten as:
177 *
178 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
179 *
180 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
181 * HW dst coeff with IS2C.
182 *
183 * Xfer modes: dst-atop (Sa!=1)
184 */
185#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
186 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
187 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
188 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
189
190/**
191 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
192 *
193 * D' = f * D * dstCoeff + (1-f) * D
194 *
195 * This can be rewritten as:
196 *
197 * D' = D - D * [f * (1 - dstCoeff)]
198 *
199 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
200 * subtract HW blend equation with coeffs of (DC, One).
201 *
202 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
203 */
204#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
205 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
206 BlendFormula::kNone_OutputType, \
207 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
208
209/**
210 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
211 *
212 * D' = f * S * srcCoeff + (1-f) * D
213 *
214 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
215 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
216 *
217 * Xfer modes (Sa!=1): src, src-in, src-out
218 */
219#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
220 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
221 BlendFormula::kCoverage_OutputType, \
222 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
223
224/**
225 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
226 * with and without an opaque input color. Optimization properties are deduced at compile time so we
227 * can make runtime decisions quickly. RGB coverage is not supported.
228 */
229static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
230
231 /*>> No coverage, input color unknown <<*/ {{
232
233 /* clear */ DST_CLEAR_FORMULA,
234 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
235 /* dst */ NO_DST_WRITE_FORMULA,
236 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
237 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
238 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
239 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
240 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
241 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
242 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
243 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
244 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
245 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
246 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
247 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
248
249 }, /*>> Has coverage, input color unknown <<*/ {
250
251 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
252 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
253 /* dst */ NO_DST_WRITE_FORMULA,
254 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
255 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
256 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
257 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
258 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
259 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
260 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
261 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
262 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
263 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
264 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
265 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
266
267 }}, /*>> No coverage, input color opaque <<*/ {{
268
269 /* clear */ DST_CLEAR_FORMULA,
270 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
271 /* dst */ NO_DST_WRITE_FORMULA,
272 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
273 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
274 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
275 /* dst-in */ NO_DST_WRITE_FORMULA,
276 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
277 /* dst-out */ DST_CLEAR_FORMULA,
278 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
279 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
280 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
281 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
282 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
283 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
284
285 }, /*>> Has coverage, input color opaque <<*/ {
286
287 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
288 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
289 /* dst */ NO_DST_WRITE_FORMULA,
290 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
291 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
292 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
293 /* dst-in */ NO_DST_WRITE_FORMULA,
294 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
295 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
296 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
297 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
298 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
299 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
300 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
301 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
302}}};
303
egdaniel723b0502015-09-15 09:31:40 -0700304static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
305 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
306 /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
307 /* dst */ NO_DST_WRITE_FORMULA,
308 /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
309 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
310 /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
311 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
312 /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
313 /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
314 /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
315 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
316 /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
317 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
318 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
319 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
320};
321
cdalton86ae0a92015-06-08 15:11:04 -0700322static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
323 const GrProcOptInfo& coveragePOI,
324 bool hasMixedSamples,
325 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700326 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
327 SkASSERT(!coveragePOI.isFourChannelOutput());
328
cdalton86ae0a92015-06-08 15:11:04 -0700329 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
330 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800331}
332
egdaniel723b0502015-09-15 09:31:40 -0700333static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
334 SkXfermode::Mode xfermode) {
335 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
336 SkASSERT(coveragePOI.isFourChannelOutput());
337
338 return gLCDBlendTable[xfermode];
339}
340
cdalton6fd158e2015-05-27 15:08:33 -0700341///////////////////////////////////////////////////////////////////////////////
342
egdaniel41d4f092015-02-09 07:51:00 -0800343class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800344public:
cdalton86ae0a92015-06-08 15:11:04 -0700345 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
346 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800347 }
egdaniel378092f2014-12-03 10:40:13 -0800348
mtklein36352bf2015-03-25 18:17:31 -0700349 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800350
egdaniel57d3b032015-11-13 11:57:27 -0800351 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800352
cdalton6fd158e2015-05-27 15:08:33 -0700353 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700354
355private:
ethannicholasde4166a2015-11-30 08:57:38 -0800356 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdanielc19cdc22015-05-10 08:45:18 -0700357 bool doesStencilWrite,
358 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800359 const GrCaps& caps) const override;
egdanielc19cdc22015-05-10 08:45:18 -0700360
egdaniel57d3b032015-11-13 11:57:27 -0800361 void onGetGLSLProcessorKey(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
egdaniel2d721d32015-11-11 13:06:05 -0800384static void append_color_output(const PorterDuffXferProcessor& xp,
egdaniel4ca2e602015-11-18 08:01:26 -0800385 GrGLSLXPFragmentBuilder* fragBuilder,
cdalton6fd158e2015-05-27 15:08:33 -0700386 BlendFormula::OutputType outputType, const char* output,
387 const char* inColor, const char* inCoverage) {
388 switch (outputType) {
389 case BlendFormula::kNone_OutputType:
egdaniel4ca2e602015-11-18 08:01:26 -0800390 fragBuilder->codeAppendf("%s = vec4(0.0);", output);
cdalton6fd158e2015-05-27 15:08:33 -0700391 break;
392 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700393 // We can have a coverage formula while not reading coverage if there are mixed samples.
egdaniel56cf6dc2015-11-30 10:15:58 -0800394 if (inCoverage) {
395 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
396 } else {
397 fragBuilder->codeAppendf("%s = vec4(1.0);", output);
398 }
cdalton6fd158e2015-05-27 15:08:33 -0700399 break;
400 case BlendFormula::kModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800401 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800402 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700403 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800404 fragBuilder->codeAppendf("%s = %s;", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700405 }
406 break;
egdaniel723b0502015-09-15 09:31:40 -0700407 case BlendFormula::kSAModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800408 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800409 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
egdaniel723b0502015-09-15 09:31:40 -0700410 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800411 fragBuilder->codeAppendf("%s = %s;", output, inColor);
egdaniel723b0502015-09-15 09:31:40 -0700412 }
413 break;
cdalton6fd158e2015-05-27 15:08:33 -0700414 case BlendFormula::kISAModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800415 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800416 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700417 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800418 fragBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700419 }
420 break;
421 case BlendFormula::kISCModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800422 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800423 fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700424 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800425 fragBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700426 }
427 break;
428 default:
429 SkFAIL("Unsupported output type.");
430 break;
egdaniel3ad65702015-02-17 11:15:47 -0800431 }
432}
433
egdanielfa4cc8b2015-11-13 08:34:52 -0800434class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
egdaniel41d4f092015-02-09 07:51:00 -0800435public:
cdalton6fd158e2015-05-27 15:08:33 -0700436 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800437 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
egdaniel56cf6dc2015-11-30 10:15:58 -0800438 b->add32(xp.getBlendFormula().fPrimaryOutputType |
439 (xp.getBlendFormula().fSecondaryOutputType << 3));
cdalton6fd158e2015-05-27 15:08:33 -0700440 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800441 };
442
443private:
cdaltonedbb31f2015-06-08 12:14:44 -0700444 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800445 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel4ca2e602015-11-18 08:01:26 -0800446 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
bungemanc33db932015-05-22 17:55:26 -0700447
cdalton6fd158e2015-05-27 15:08:33 -0700448 BlendFormula blendFormula = xp.getBlendFormula();
449 if (blendFormula.hasSecondaryOutput()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800450 append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700451 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800452 }
egdaniel4ca2e602015-11-18 08:01:26 -0800453 append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700454 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800455 }
456
egdaniel018fb622015-10-28 07:26:40 -0700457 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800458
egdanielfa4cc8b2015-11-13 08:34:52 -0800459 typedef GrGLSLXferProcessor INHERITED;
egdaniel378092f2014-12-03 10:40:13 -0800460};
461
462///////////////////////////////////////////////////////////////////////////////
463
egdaniel57d3b032015-11-13 11:57:27 -0800464void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
465 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700466 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800467}
468
egdaniel57d3b032015-11-13 11:57:27 -0800469GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700470 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800471}
472
egdaniel95131432014-12-09 11:15:43 -0800473GrXferProcessor::OptFlags
ethannicholasde4166a2015-11-30 08:57:38 -0800474PorterDuffXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdanielc19cdc22015-05-10 08:45:18 -0700475 bool doesStencilWrite,
476 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800477 const GrCaps& caps) const {
bsalomon7765a472015-07-08 11:26:37 -0700478 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700479 if (!fBlendFormula.modifiesDst()) {
480 if (!doesStencilWrite) {
481 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
482 }
483 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
484 GrXferProcessor::kIgnoreCoverage_OptFlag |
485 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
486 } else {
487 if (!fBlendFormula.usesInputColor()) {
488 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
489 }
ethannicholasde4166a2015-11-30 08:57:38 -0800490 if (optimizations.fCoveragePOI.isSolidWhite()) {
cdalton6fd158e2015-05-27 15:08:33 -0700491 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
492 }
ethannicholasde4166a2015-11-30 08:57:38 -0800493 if (optimizations.fColorPOI.allStagesMultiplyInput() &&
egdaniel723b0502015-09-15 09:31:40 -0700494 fBlendFormula.canTweakAlphaForCoverage() &&
ethannicholasde4166a2015-11-30 08:57:38 -0800495 !optimizations.fCoveragePOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700496 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
497 }
498 }
bungemanc33db932015-05-22 17:55:26 -0700499 return optFlags;
500}
501
cdalton6fd158e2015-05-27 15:08:33 -0700502///////////////////////////////////////////////////////////////////////////////
503
504class ShaderPDXferProcessor : public GrXferProcessor {
505public:
cdalton86ae0a92015-06-08 15:11:04 -0700506 ShaderPDXferProcessor(const DstTexture* dstTexture,
507 bool hasMixedSamples,
508 SkXfermode::Mode xfermode)
509 : INHERITED(dstTexture, true, hasMixedSamples)
510 , fXfermode(xfermode) {
511 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700512 }
513
cdalton6fd158e2015-05-27 15:08:33 -0700514 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700515
egdaniel57d3b032015-11-13 11:57:27 -0800516 GrGLSLXferProcessor* createGLSLInstance() const override;
cdalton6fd158e2015-05-27 15:08:33 -0700517
518 SkXfermode::Mode getXfermode() const { return fXfermode; }
519
520private:
ethannicholasde4166a2015-11-30 08:57:38 -0800521 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*,
egdaniel56cf6dc2015-11-30 10:15:58 -0800522 const GrCaps&) const override {
bsalomon7765a472015-07-08 11:26:37 -0700523 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700524 }
525
egdaniel57d3b032015-11-13 11:57:27 -0800526 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdalton6fd158e2015-05-27 15:08:33 -0700527
528 bool onIsEqual(const GrXferProcessor& xpBase) const override {
529 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
530 return fXfermode == xp.fXfermode;
531 }
532
533 const SkXfermode::Mode fXfermode;
534
535 typedef GrXferProcessor INHERITED;
536};
537
538///////////////////////////////////////////////////////////////////////////////
539
egdanielfa4cc8b2015-11-13 08:34:52 -0800540class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
cdalton6fd158e2015-05-27 15:08:33 -0700541public:
542 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
543 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
544 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800545 }
egdaniel87509242014-12-17 13:37:13 -0800546
cdalton6fd158e2015-05-27 15:08:33 -0700547private:
egdaniel7ea439b2015-12-03 09:20:44 -0800548 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
549 GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800550 const char* srcColor,
egdanielf34b2932015-12-01 13:54:06 -0800551 const char* srcCoverage,
egdaniel4ca2e602015-11-18 08:01:26 -0800552 const char* dstColor,
553 const char* outColor,
egdanielf34b2932015-12-01 13:54:06 -0800554 const char* outColorSecondary,
egdaniel4ca2e602015-11-18 08:01:26 -0800555 const GrXferProcessor& proc) override {
cdaltonedbb31f2015-06-08 12:14:44 -0700556 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
egdaniel95131432014-12-09 11:15:43 -0800557
egdaniel4ca2e602015-11-18 08:01:26 -0800558 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdanielf34b2932015-12-01 13:54:06 -0800559
560 // Apply coverage.
561 if (xp.dstReadUsesMixedSamples()) {
562 if (srcCoverage) {
563 fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage);
564 fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage);
565 } else {
566 fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary);
567 }
568 } else if (srcCoverage) {
569 fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
570 outColor, srcCoverage, outColor, srcCoverage, dstColor);
571 }
egdaniel95131432014-12-09 11:15:43 -0800572 }
573
egdaniel018fb622015-10-28 07:26:40 -0700574 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700575
egdanielfa4cc8b2015-11-13 08:34:52 -0800576 typedef GrGLSLXferProcessor INHERITED;
cdalton6fd158e2015-05-27 15:08:33 -0700577};
bungemanc33db932015-05-22 17:55:26 -0700578
cdalton6fd158e2015-05-27 15:08:33 -0700579///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700580
egdaniel57d3b032015-11-13 11:57:27 -0800581void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
582 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700583 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700584}
585
egdaniel57d3b032015-11-13 11:57:27 -0800586GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700587 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800588}
589
egdaniel378092f2014-12-03 10:40:13 -0800590///////////////////////////////////////////////////////////////////////////////
591
egdaniel0d5fd112015-05-12 06:11:35 -0700592class PDLCDXferProcessor : public GrXferProcessor {
593public:
cdalton6fd158e2015-05-27 15:08:33 -0700594 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700595
596 ~PDLCDXferProcessor() override;
597
598 const char* name() const override { return "Porter Duff LCD"; }
599
egdaniel57d3b032015-11-13 11:57:27 -0800600 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700601
egdaniel0d5fd112015-05-12 06:11:35 -0700602private:
603 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
604
ethannicholasde4166a2015-11-30 08:57:38 -0800605 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdaniel0d5fd112015-05-12 06:11:35 -0700606 bool doesStencilWrite,
607 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800608 const GrCaps& caps) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700609
egdaniel57d3b032015-11-13 11:57:27 -0800610 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700611
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
egdanielfa4cc8b2015-11-13 08:34:52 -0800635class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
egdaniel0d5fd112015-05-12 06:11:35 -0700636public:
637 GLPDLCDXferProcessor(const GrProcessor&) {}
638
639 virtual ~GLPDLCDXferProcessor() {}
640
641 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
642 GrProcessorKeyBuilder* b) {}
643
644private:
cdaltonedbb31f2015-06-08 12:14:44 -0700645 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel4ca2e602015-11-18 08:01:26 -0800646 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
egdaniel56cf6dc2015-11-30 10:15:58 -0800647 SkASSERT(args.fInputCoverage);
egdaniel4ca2e602015-11-18 08:01:26 -0800648 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
649 args.fInputCoverage);
egdaniel0d5fd112015-05-12 06:11:35 -0700650 }
651
egdaniel018fb622015-10-28 07:26:40 -0700652 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {};
egdaniel0d5fd112015-05-12 06:11:35 -0700653
egdanielfa4cc8b2015-11-13 08:34:52 -0800654 typedef GrGLSLXferProcessor INHERITED;
egdaniel0d5fd112015-05-12 06:11:35 -0700655};
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) {
halcanary96fcdcc2015-08-27 07:41:13 -0700668 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700669 }
670
671 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700672 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700673 }
674
bsalomonae4738f2015-09-15 15:33:27 -0700675 GrColor blendConstant = GrUnpremulColor(colorPOI.color());
egdaniel0d5fd112015-05-12 06:11:35 -0700676 uint8_t alpha = GrColorUnpackA(blendConstant);
677 blendConstant |= (0xff << GrColor_SHIFT_A);
678
halcanary385fe4d2015-08-26 13:07:48 -0700679 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700680}
681
682PDLCDXferProcessor::~PDLCDXferProcessor() {
683}
684
egdaniel57d3b032015-11-13 11:57:27 -0800685void PDLCDXferProcessor::onGetGLSLProcessorKey(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
egdaniel57d3b032015-11-13 11:57:27 -0800690GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700691 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700692}
693
694GrXferProcessor::OptFlags
ethannicholasde4166a2015-11-30 08:57:38 -0800695PDLCDXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdaniel0d5fd112015-05-12 06:11:35 -0700696 bool doesStencilWrite,
697 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800698 const GrCaps& caps) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700699 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
700 // value of the blend the constant. We should already have valid blend coeff's if we are at
701 // a point where we have RGB coverage. We don't need any color stages since the known color
702 // output is already baked into the blendConstant.
703 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
704 return GrXferProcessor::kOverrideColor_OptFlag;
705}
706
707///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700708
egdanielf2342722015-11-20 15:12:59 -0800709GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
cdalton6fd158e2015-05-27 15:08:33 -0700710 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700711 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdanielf2342722015-11-20 15:12:59 -0800712 this->initClassID<GrPorterDuffXPFactory>();
egdaniel915187b2014-12-05 12:58:28 -0800713}
714
egdanielf2342722015-11-20 15:12:59 -0800715GrXPFactory* 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);
cdalton6fd158e2015-05-27 15:08:33 -0700731
egdanielf2342722015-11-20 15:12:59 -0800732 static GrPorterDuffXPFactory* gFactories[] = {
cdalton6fd158e2015-05-27 15:08:33 -0700733 &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) {
halcanary96fcdcc2015-08-27 07:41:13 -0700740 return nullptr;
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*
egdanielf2342722015-11-20 15:12:59 -0800746GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800747 const GrPipelineOptimizations& optimizations,
cdalton86ae0a92015-06-08 15:11:04 -0700748 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700749 const DstTexture* dstTexture) const {
egdaniel723b0502015-09-15 09:31:40 -0700750 BlendFormula blendFormula;
ethannicholasde4166a2015-11-30 08:57:38 -0800751 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700752 if (SkXfermode::kSrcOver_Mode == fXfermode &&
ethannicholasde4166a2015-11-30 08:57:38 -0800753 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdaniele73f1f62015-09-22 10:10:55 -0700754 !caps.shaderCaps()->dualSourceBlendingSupport() &&
755 !caps.shaderCaps()->dstReadInShaderSupport()) {
756 // If we don't have dual source blending or in shader dst reads, we fall back to this
757 // trick for rendering SrcOver LCD text instead of doing a dst copy.
egdaniel723b0502015-09-15 09:31:40 -0700758 SkASSERT(!dstTexture || !dstTexture->texture());
ethannicholasde4166a2015-11-30 08:57:38 -0800759 return PDLCDXferProcessor::Create(fXfermode, optimizations.fColorPOI);
egdaniel723b0502015-09-15 09:31:40 -0700760 }
ethannicholasde4166a2015-11-30 08:57:38 -0800761 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode);
egdaniel723b0502015-09-15 09:31:40 -0700762 } else {
ethannicholasde4166a2015-11-30 08:57:38 -0800763 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
764 hasMixedSamples, fXfermode);
egdaniel95131432014-12-09 11:15:43 -0800765 }
cdalton6fd158e2015-05-27 15:08:33 -0700766
cdalton6fd158e2015-05-27 15:08:33 -0700767 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700768 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700769 }
770
771 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700772 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800773}
774
egdanielf2342722015-11-20 15:12:59 -0800775void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
cdalton1fa45722015-06-02 10:43:39 -0700776 InvariantBlendedColor* blendedColor) const {
777 // Find the blended color info based on the formula that does not have coverage.
778 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
779 if (colorFormula.usesDstColor()) {
780 blendedColor->fWillBlendWithDst = true;
781 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800782 return;
egdaniel95131432014-12-09 11:15:43 -0800783 }
784
cdalton1fa45722015-06-02 10:43:39 -0700785 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700786
cdalton1fa45722015-06-02 10:43:39 -0700787 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700788
cdalton1fa45722015-06-02 10:43:39 -0700789 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800790 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700791 blendedColor->fKnownColor = 0;
792 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700793 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800794
795 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700796 blendedColor->fKnownColor = colorPOI.color();
797 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700798 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800799
cdalton1fa45722015-06-02 10:43:39 -0700800 default:
801 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
802 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800803 }
egdaniel95131432014-12-09 11:15:43 -0800804}
805
egdanielf2342722015-11-20 15:12:59 -0800806bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800807 const GrPipelineOptimizations& optimizations,
cdalton86ae0a92015-06-08 15:11:04 -0700808 bool hasMixedSamples) const {
809 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
810 return false;
bungemanc33db932015-05-22 17:55:26 -0700811 }
egdaniel723b0502015-09-15 09:31:40 -0700812
813 // When we have four channel coverage we always need to read the dst in order to correctly
814 // blend. The one exception is when we are using srcover mode and we know the input color into
815 // the XP.
ethannicholasde4166a2015-11-30 08:57:38 -0800816 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700817 if (SkXfermode::kSrcOver_Mode == fXfermode &&
ethannicholasde4166a2015-11-30 08:57:38 -0800818 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdaniele73f1f62015-09-22 10:10:55 -0700819 !caps.shaderCaps()->dstReadInShaderSupport()) {
egdaniel723b0502015-09-15 09:31:40 -0700820 return false;
821 }
ethannicholasde4166a2015-11-30 08:57:38 -0800822 return get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode).hasSecondaryOutput();
cdalton86ae0a92015-06-08 15:11:04 -0700823 }
cdalton6fd158e2015-05-27 15:08:33 -0700824 // We fallback on the shader XP when the blend formula would use dual source blending but we
825 // don't have support for it.
ethannicholasde4166a2015-11-30 08:57:38 -0800826 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, hasMixedSamples,
827 fXfermode).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800828}
829
egdanielf2342722015-11-20 15:12:59 -0800830GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
egdanielc2304142014-12-11 13:15:13 -0800831
egdanielf2342722015-11-20 15:12:59 -0800832const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700833 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
egdanielf2342722015-11-20 15:12:59 -0800834 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800835}
egdaniel95131432014-12-09 11:15:43 -0800836
egdanielf2342722015-11-20 15:12:59 -0800837void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
838 int* outPrimary,
839 int* outSecondary) {
cdalton6fd158e2015-05-27 15:08:33 -0700840 if (!!strcmp(xp->name(), "Porter Duff")) {
841 *outPrimary = *outSecondary = -1;
842 return;
843 }
844 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
845 *outPrimary = blendFormula.fPrimaryOutputType;
846 *outSecondary = blendFormula.fSecondaryOutputType;
847}
egdanielc4b72722015-11-23 13:20:41 -0800848
849
850////////////////////////////////////////////////////////////////////////////////////////////////
851// SrcOver Global functions
852////////////////////////////////////////////////////////////////////////////////////////////////
bsalomon2047b782015-12-21 13:12:54 -0800853const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
854 static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
855 kISA_GrBlendCoeff);
856 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
857 return gSrcOverXP;
858}
egdanielc4b72722015-11-23 13:20:41 -0800859
860GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
861 const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800862 const GrPipelineOptimizations& optimizations,
egdanielc4b72722015-11-23 13:20:41 -0800863 bool hasMixedSamples,
864 const GrXferProcessor::DstTexture* dstTexture) {
egdaniel56cf6dc2015-11-30 10:15:58 -0800865 if (!optimizations.fCoveragePOI.isFourChannelOutput() &&
866 !(optimizations.fCoveragePOI.isSolidWhite() &&
867 !hasMixedSamples &&
868 optimizations.fColorPOI.isOpaque())) {
bsalomon2047b782015-12-21 13:12:54 -0800869 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
870 // We don't simply return the address of that XP here because our caller would have to unref
871 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
872 // safe.
873 return nullptr;
egdaniel56cf6dc2015-11-30 10:15:58 -0800874 }
875
egdanielc4b72722015-11-23 13:20:41 -0800876 BlendFormula blendFormula;
ethannicholasde4166a2015-11-30 08:57:38 -0800877 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
878 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdanielc4b72722015-11-23 13:20:41 -0800879 !caps.shaderCaps()->dualSourceBlendingSupport() &&
880 !caps.shaderCaps()->dstReadInShaderSupport()) {
881 // If we don't have dual source blending or in shader dst reads, we fall
882 // back to this trick for rendering SrcOver LCD text instead of doing a
883 // dst copy.
884 SkASSERT(!dstTexture || !dstTexture->texture());
ethannicholasde4166a2015-11-30 08:57:38 -0800885 return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, optimizations.fColorPOI);
egdanielc4b72722015-11-23 13:20:41 -0800886 }
ethannicholasde4166a2015-11-30 08:57:38 -0800887 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, SkXfermode::kSrcOver_Mode);
egdanielc4b72722015-11-23 13:20:41 -0800888 } else {
ethannicholasde4166a2015-11-30 08:57:38 -0800889 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
890 hasMixedSamples, SkXfermode::kSrcOver_Mode);
egdanielc4b72722015-11-23 13:20:41 -0800891 }
892
893 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
894 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
895 }
896
897 SkASSERT(!dstTexture || !dstTexture->texture());
898 return new PorterDuffXferProcessor(blendFormula);
899}
900
901bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800902 const GrPipelineOptimizations& optimizations,
egdanielc4b72722015-11-23 13:20:41 -0800903 bool hasMixedSamples) {
904 if (caps.shaderCaps()->dstReadInShaderSupport() ||
905 caps.shaderCaps()->dualSourceBlendingSupport()) {
906 return false;
907 }
908
909 // When we have four channel coverage we always need to read the dst in order to correctly
910 // blend. The one exception is when we are using srcover mode and we know the input color
911 // into the XP.
ethannicholasde4166a2015-11-30 08:57:38 -0800912 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
913 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdanielc4b72722015-11-23 13:20:41 -0800914 !caps.shaderCaps()->dstReadInShaderSupport()) {
915 return false;
916 }
ethannicholasde4166a2015-11-30 08:57:38 -0800917 return get_lcd_blend_formula(optimizations.fCoveragePOI,
918 SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
egdanielc4b72722015-11-23 13:20:41 -0800919 }
920 // We fallback on the shader XP when the blend formula would use dual source blending but we
921 // don't have support for it.
ethannicholasde4166a2015-11-30 08:57:38 -0800922 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
egdanielc4b72722015-11-23 13:20:41 -0800923 hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
924}
925