blob: 94d3dd67a93ae8df8da4e06b53d41286eddae558 [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"
bungeman221524d2016-01-05 14:59:40 -080022#include <utility>
egdaniel378092f2014-12-03 10:40:13 -080023
cdalton6fd158e2015-05-27 15:08:33 -070024/**
25 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
26 */
27struct BlendFormula {
28public:
29 /**
30 * Values the shader can write to primary and secondary outputs. These must all be modulated by
31 * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
egdaniel95131432014-12-09 11:15:43 -080032 */
cdalton6fd158e2015-05-27 15:08:33 -070033 enum OutputType {
34 kNone_OutputType, //<! 0
35 kCoverage_OutputType, //<! inputCoverage
36 kModulate_OutputType, //<! inputColor * inputCoverage
egdaniel723b0502015-09-15 09:31:40 -070037 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
cdalton6fd158e2015-05-27 15:08:33 -070038 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
39 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
40
41 kLast_OutputType = kISCModulate_OutputType
42 };
43
44 enum Properties {
45 kModifiesDst_Property = 1,
46 kUsesDstColor_Property = 1 << 1,
47 kUsesInputColor_Property = 1 << 2,
48 kCanTweakAlphaForCoverage_Property = 1 << 3,
49
50 kLast_Property = kCanTweakAlphaForCoverage_Property
51 };
52
53 BlendFormula& operator =(const BlendFormula& other) {
54 fData = other.fData;
55 return *this;
56 }
57
58 bool operator ==(const BlendFormula& other) const {
59 return fData == other.fData;
60 }
61
62 bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
63 bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
64 bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
65 bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
66 bool canTweakAlphaForCoverage() const {
67 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
68 }
69
70 /**
71 * Deduce the properties of a compile-time constant BlendFormula.
72 */
73 template<OutputType PrimaryOut, OutputType SecondaryOut,
74 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
bungeman221524d2016-01-05 14:59:40 -080075 struct get_properties : std::integral_constant<Properties, static_cast<Properties>(
cdalton6fd158e2015-05-27 15:08:33 -070076
77 (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
78 kModifiesDst_Property : 0) |
79
80 (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
81 kUsesDstColor_Property : 0) |
82
83 ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
84 (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
85 kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
86
87 (kModulate_OutputType == PrimaryOut &&
88 kNone_OutputType == SecondaryOut &&
89 GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
90 kCanTweakAlphaForCoverage_Property : 0))> {
91
92 // The provided formula should already be optimized.
93 GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
94 !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
95 GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
96 GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
97 !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
98 GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
99 GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
100 };
101
102 union {
103 struct {
104 // We allot the enums one more bit than they require because MSVC seems to sign-extend
105 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
106 OutputType fPrimaryOutputType : 4;
107 OutputType fSecondaryOutputType : 4;
108 GrBlendEquation fBlendEquation : 6;
109 GrBlendCoeff fSrcCoeff : 6;
110 GrBlendCoeff fDstCoeff : 6;
111 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
112 };
113 uint32_t fData;
114 };
115
116 GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
117 GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
118 GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
119 GR_STATIC_ASSERT(kLast_Property < (1 << 6));
120};
121
122GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
123
124GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
125
126/**
127 * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
128 */
129#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
130 {{{PRIMARY_OUT, \
131 SECONDARY_OUT, \
132 BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
133 BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
134 BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
135
136/**
137 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
138 * Porter Duff formula.
139 */
140#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
141 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
142 BlendFormula::kNone_OutputType, \
143 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
144
145/**
egdaniel723b0502015-09-15 09:31:40 -0700146 * Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
147 * LCD dst-out.
148 */
149#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
150 INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
151 BlendFormula::kNone_OutputType, \
152 kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
153
154/**
cdalton6fd158e2015-05-27 15:08:33 -0700155 * When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
156 * the primary output type to none.
157 */
158#define DST_CLEAR_FORMULA \
159 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
160 BlendFormula::kNone_OutputType, \
161 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
162
163/**
164 * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
165 * so we can set the primary output type to none.
166 */
167#define NO_DST_WRITE_FORMULA \
168 INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
169 BlendFormula::kNone_OutputType, \
170 kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
171
172/**
173 * When there is coverage, the equation with f=coverage is:
174 *
175 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
176 *
177 * This can be rewritten as:
178 *
179 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
180 *
181 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
182 * HW dst coeff with IS2C.
183 *
184 * Xfer modes: dst-atop (Sa!=1)
185 */
186#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
187 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
188 ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
189 kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
190
191/**
192 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
193 *
194 * D' = f * D * dstCoeff + (1-f) * D
195 *
196 * This can be rewritten as:
197 *
198 * D' = D - D * [f * (1 - dstCoeff)]
199 *
200 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
201 * subtract HW blend equation with coeffs of (DC, One).
202 *
203 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
204 */
205#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
206 INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
207 BlendFormula::kNone_OutputType, \
208 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
209
210/**
211 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
212 *
213 * D' = f * S * srcCoeff + (1-f) * D
214 *
215 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
216 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
217 *
218 * Xfer modes (Sa!=1): src, src-in, src-out
219 */
220#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
221 INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
222 BlendFormula::kCoverage_OutputType, \
223 kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
224
225/**
226 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
227 * with and without an opaque input color. Optimization properties are deduced at compile time so we
228 * can make runtime decisions quickly. RGB coverage is not supported.
229 */
230static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
231
232 /*>> No coverage, input color unknown <<*/ {{
233
234 /* clear */ DST_CLEAR_FORMULA,
235 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
236 /* dst */ NO_DST_WRITE_FORMULA,
237 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
238 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
239 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
240 /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
241 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
242 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
243 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
244 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
245 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
246 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
247 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
248 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
249
250 }, /*>> Has coverage, input color unknown <<*/ {
251
252 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
253 /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
254 /* dst */ NO_DST_WRITE_FORMULA,
255 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
256 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
257 /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
258 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
259 /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
260 /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
261 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
262 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
263 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
264 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
265 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
266 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
267
268 }}, /*>> No coverage, input color opaque <<*/ {{
269
270 /* clear */ DST_CLEAR_FORMULA,
271 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
272 /* dst */ NO_DST_WRITE_FORMULA,
273 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
274 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
275 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
276 /* dst-in */ NO_DST_WRITE_FORMULA,
277 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
278 /* dst-out */ DST_CLEAR_FORMULA,
279 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
280 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
281 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
282 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
283 /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
284 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
285
286 }, /*>> Has coverage, input color opaque <<*/ {
287
288 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
289 /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
290 /* dst */ NO_DST_WRITE_FORMULA,
291 /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
292 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
293 /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
294 /* dst-in */ NO_DST_WRITE_FORMULA,
295 /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
296 /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
297 /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
298 /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
299 /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
300 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
301 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
302 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
303}}};
304
egdaniel723b0502015-09-15 09:31:40 -0700305static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
306 /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
307 /* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
308 /* dst */ NO_DST_WRITE_FORMULA,
309 /* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
310 /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
311 /* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
312 /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
313 /* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
314 /* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
315 /* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
316 /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
317 /* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
318 /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
319 /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
320 /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
321};
322
cdalton86ae0a92015-06-08 15:11:04 -0700323static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
324 const GrProcOptInfo& coveragePOI,
325 bool hasMixedSamples,
326 SkXfermode::Mode xfermode) {
cdalton6fd158e2015-05-27 15:08:33 -0700327 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
328 SkASSERT(!coveragePOI.isFourChannelOutput());
329
cdalton86ae0a92015-06-08 15:11:04 -0700330 bool conflatesCoverage = !coveragePOI.isSolidWhite() || hasMixedSamples;
331 return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
egdaniel95131432014-12-09 11:15:43 -0800332}
333
egdaniel723b0502015-09-15 09:31:40 -0700334static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
335 SkXfermode::Mode xfermode) {
336 SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
337 SkASSERT(coveragePOI.isFourChannelOutput());
338
339 return gLCDBlendTable[xfermode];
340}
341
cdalton6fd158e2015-05-27 15:08:33 -0700342///////////////////////////////////////////////////////////////////////////////
343
egdaniel41d4f092015-02-09 07:51:00 -0800344class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800345public:
cdalton86ae0a92015-06-08 15:11:04 -0700346 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
347 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800348 }
egdaniel378092f2014-12-03 10:40:13 -0800349
mtklein36352bf2015-03-25 18:17:31 -0700350 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800351
egdaniel57d3b032015-11-13 11:57:27 -0800352 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800353
cdalton6fd158e2015-05-27 15:08:33 -0700354 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700355
356private:
ethannicholasde4166a2015-11-30 08:57:38 -0800357 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdanielc19cdc22015-05-10 08:45:18 -0700358 bool doesStencilWrite,
359 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800360 const GrCaps& caps) const override;
egdanielc19cdc22015-05-10 08:45:18 -0700361
egdaniel57d3b032015-11-13 11:57:27 -0800362 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700363
cdaltonedbb31f2015-06-08 12:14:44 -0700364 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
365
cdaltonf4f2b442015-04-23 09:40:23 -0700366 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700367 blendInfo->fEquation = fBlendFormula.fBlendEquation;
368 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
369 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
370 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800371 }
372
mtklein36352bf2015-03-25 18:17:31 -0700373 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800374 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700375 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800376 }
377
cdalton6fd158e2015-05-27 15:08:33 -0700378 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800379
380 typedef GrXferProcessor INHERITED;
381};
382
383///////////////////////////////////////////////////////////////////////////////
384
egdaniel2d721d32015-11-11 13:06:05 -0800385static void append_color_output(const PorterDuffXferProcessor& xp,
egdaniel4ca2e602015-11-18 08:01:26 -0800386 GrGLSLXPFragmentBuilder* fragBuilder,
cdalton6fd158e2015-05-27 15:08:33 -0700387 BlendFormula::OutputType outputType, const char* output,
388 const char* inColor, const char* inCoverage) {
389 switch (outputType) {
390 case BlendFormula::kNone_OutputType:
egdaniel4ca2e602015-11-18 08:01:26 -0800391 fragBuilder->codeAppendf("%s = vec4(0.0);", output);
cdalton6fd158e2015-05-27 15:08:33 -0700392 break;
393 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700394 // We can have a coverage formula while not reading coverage if there are mixed samples.
egdaniel56cf6dc2015-11-30 10:15:58 -0800395 if (inCoverage) {
396 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
397 } else {
398 fragBuilder->codeAppendf("%s = vec4(1.0);", output);
399 }
cdalton6fd158e2015-05-27 15:08:33 -0700400 break;
401 case BlendFormula::kModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800402 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800403 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700404 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800405 fragBuilder->codeAppendf("%s = %s;", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700406 }
407 break;
egdaniel723b0502015-09-15 09:31:40 -0700408 case BlendFormula::kSAModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800409 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800410 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
egdaniel723b0502015-09-15 09:31:40 -0700411 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800412 fragBuilder->codeAppendf("%s = %s;", output, inColor);
egdaniel723b0502015-09-15 09:31:40 -0700413 }
414 break;
cdalton6fd158e2015-05-27 15:08:33 -0700415 case BlendFormula::kISAModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800416 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800417 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700418 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800419 fragBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700420 }
421 break;
422 case BlendFormula::kISCModulate_OutputType:
egdaniel56cf6dc2015-11-30 10:15:58 -0800423 if (inCoverage) {
egdaniel4ca2e602015-11-18 08:01:26 -0800424 fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700425 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800426 fragBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700427 }
428 break;
429 default:
430 SkFAIL("Unsupported output type.");
431 break;
egdaniel3ad65702015-02-17 11:15:47 -0800432 }
433}
434
egdanielfa4cc8b2015-11-13 08:34:52 -0800435class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
egdaniel41d4f092015-02-09 07:51:00 -0800436public:
cdalton6fd158e2015-05-27 15:08:33 -0700437 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800438 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
egdaniel56cf6dc2015-11-30 10:15:58 -0800439 b->add32(xp.getBlendFormula().fPrimaryOutputType |
440 (xp.getBlendFormula().fSecondaryOutputType << 3));
cdalton6fd158e2015-05-27 15:08:33 -0700441 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
bsalomon50785a32015-02-06 07:02:37 -0800442 };
443
444private:
cdaltonedbb31f2015-06-08 12:14:44 -0700445 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800446 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel4ca2e602015-11-18 08:01:26 -0800447 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
bungemanc33db932015-05-22 17:55:26 -0700448
cdalton6fd158e2015-05-27 15:08:33 -0700449 BlendFormula blendFormula = xp.getBlendFormula();
450 if (blendFormula.hasSecondaryOutput()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800451 append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700452 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800453 }
egdaniel4ca2e602015-11-18 08:01:26 -0800454 append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700455 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800456 }
457
egdaniel018fb622015-10-28 07:26:40 -0700458 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800459
egdanielfa4cc8b2015-11-13 08:34:52 -0800460 typedef GrGLSLXferProcessor INHERITED;
egdaniel378092f2014-12-03 10:40:13 -0800461};
462
463///////////////////////////////////////////////////////////////////////////////
464
egdaniel57d3b032015-11-13 11:57:27 -0800465void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
466 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700467 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800468}
469
egdaniel57d3b032015-11-13 11:57:27 -0800470GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700471 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800472}
473
egdaniel95131432014-12-09 11:15:43 -0800474GrXferProcessor::OptFlags
ethannicholasde4166a2015-11-30 08:57:38 -0800475PorterDuffXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdanielc19cdc22015-05-10 08:45:18 -0700476 bool doesStencilWrite,
477 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800478 const GrCaps& caps) const {
bsalomon7765a472015-07-08 11:26:37 -0700479 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700480 if (!fBlendFormula.modifiesDst()) {
481 if (!doesStencilWrite) {
482 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
483 }
484 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
485 GrXferProcessor::kIgnoreCoverage_OptFlag |
486 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
487 } else {
488 if (!fBlendFormula.usesInputColor()) {
489 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
490 }
ethannicholasde4166a2015-11-30 08:57:38 -0800491 if (optimizations.fCoveragePOI.isSolidWhite()) {
cdalton6fd158e2015-05-27 15:08:33 -0700492 optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
493 }
ethannicholasde4166a2015-11-30 08:57:38 -0800494 if (optimizations.fColorPOI.allStagesMultiplyInput() &&
egdaniel723b0502015-09-15 09:31:40 -0700495 fBlendFormula.canTweakAlphaForCoverage() &&
ethannicholasde4166a2015-11-30 08:57:38 -0800496 !optimizations.fCoveragePOI.isFourChannelOutput()) {
cdalton6fd158e2015-05-27 15:08:33 -0700497 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
498 }
499 }
bungemanc33db932015-05-22 17:55:26 -0700500 return optFlags;
501}
502
cdalton6fd158e2015-05-27 15:08:33 -0700503///////////////////////////////////////////////////////////////////////////////
504
505class ShaderPDXferProcessor : public GrXferProcessor {
506public:
cdalton86ae0a92015-06-08 15:11:04 -0700507 ShaderPDXferProcessor(const DstTexture* dstTexture,
508 bool hasMixedSamples,
509 SkXfermode::Mode xfermode)
510 : INHERITED(dstTexture, true, hasMixedSamples)
511 , fXfermode(xfermode) {
512 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700513 }
514
cdalton6fd158e2015-05-27 15:08:33 -0700515 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700516
egdaniel57d3b032015-11-13 11:57:27 -0800517 GrGLSLXferProcessor* createGLSLInstance() const override;
cdalton6fd158e2015-05-27 15:08:33 -0700518
519 SkXfermode::Mode getXfermode() const { return fXfermode; }
520
521private:
ethannicholasde4166a2015-11-30 08:57:38 -0800522 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations&, bool, GrColor*,
egdaniel56cf6dc2015-11-30 10:15:58 -0800523 const GrCaps&) const override {
bsalomon7765a472015-07-08 11:26:37 -0700524 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700525 }
526
egdaniel57d3b032015-11-13 11:57:27 -0800527 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
cdalton6fd158e2015-05-27 15:08:33 -0700528
529 bool onIsEqual(const GrXferProcessor& xpBase) const override {
530 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
531 return fXfermode == xp.fXfermode;
532 }
533
534 const SkXfermode::Mode fXfermode;
535
536 typedef GrXferProcessor INHERITED;
537};
538
539///////////////////////////////////////////////////////////////////////////////
540
egdanielfa4cc8b2015-11-13 08:34:52 -0800541class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
cdalton6fd158e2015-05-27 15:08:33 -0700542public:
543 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
544 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
545 b->add32(xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800546 }
egdaniel87509242014-12-17 13:37:13 -0800547
cdalton6fd158e2015-05-27 15:08:33 -0700548private:
egdaniel7ea439b2015-12-03 09:20:44 -0800549 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
550 GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800551 const char* srcColor,
egdanielf34b2932015-12-01 13:54:06 -0800552 const char* srcCoverage,
egdaniel4ca2e602015-11-18 08:01:26 -0800553 const char* dstColor,
554 const char* outColor,
egdanielf34b2932015-12-01 13:54:06 -0800555 const char* outColorSecondary,
egdaniel4ca2e602015-11-18 08:01:26 -0800556 const GrXferProcessor& proc) override {
cdaltonedbb31f2015-06-08 12:14:44 -0700557 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
egdaniel95131432014-12-09 11:15:43 -0800558
egdaniel4ca2e602015-11-18 08:01:26 -0800559 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdanielf34b2932015-12-01 13:54:06 -0800560
561 // Apply coverage.
562 if (xp.dstReadUsesMixedSamples()) {
563 if (srcCoverage) {
564 fragBuilder->codeAppendf("%s *= %s;", outColor, srcCoverage);
565 fragBuilder->codeAppendf("%s = %s;", outColorSecondary, srcCoverage);
566 } else {
567 fragBuilder->codeAppendf("%s = vec4(1.0);", outColorSecondary);
568 }
569 } else if (srcCoverage) {
570 fragBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;",
571 outColor, srcCoverage, outColor, srcCoverage, dstColor);
572 }
egdaniel95131432014-12-09 11:15:43 -0800573 }
574
egdaniel018fb622015-10-28 07:26:40 -0700575 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700576
egdanielfa4cc8b2015-11-13 08:34:52 -0800577 typedef GrGLSLXferProcessor INHERITED;
cdalton6fd158e2015-05-27 15:08:33 -0700578};
bungemanc33db932015-05-22 17:55:26 -0700579
cdalton6fd158e2015-05-27 15:08:33 -0700580///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700581
egdaniel57d3b032015-11-13 11:57:27 -0800582void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps&,
583 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700584 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700585}
586
egdaniel57d3b032015-11-13 11:57:27 -0800587GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700588 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800589}
590
egdaniel378092f2014-12-03 10:40:13 -0800591///////////////////////////////////////////////////////////////////////////////
592
egdaniel0d5fd112015-05-12 06:11:35 -0700593class PDLCDXferProcessor : public GrXferProcessor {
594public:
cdalton6fd158e2015-05-27 15:08:33 -0700595 static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700596
597 ~PDLCDXferProcessor() override;
598
599 const char* name() const override { return "Porter Duff LCD"; }
600
egdaniel57d3b032015-11-13 11:57:27 -0800601 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700602
egdaniel0d5fd112015-05-12 06:11:35 -0700603private:
604 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
605
ethannicholasde4166a2015-11-30 08:57:38 -0800606 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdaniel0d5fd112015-05-12 06:11:35 -0700607 bool doesStencilWrite,
608 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800609 const GrCaps& caps) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700610
egdaniel57d3b032015-11-13 11:57:27 -0800611 void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700612
613 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
614 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
615 blendInfo->fDstBlend = kISC_GrBlendCoeff;
616 blendInfo->fBlendConstant = fBlendConstant;
617 }
618
619 bool onIsEqual(const GrXferProcessor& xpBase) const override {
620 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
621 if (fBlendConstant != xp.fBlendConstant ||
622 fAlpha != xp.fAlpha) {
623 return false;
624 }
625 return true;
626 }
627
628 GrColor fBlendConstant;
629 uint8_t fAlpha;
630
631 typedef GrXferProcessor INHERITED;
632};
633
634///////////////////////////////////////////////////////////////////////////////
635
egdanielfa4cc8b2015-11-13 08:34:52 -0800636class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
egdaniel0d5fd112015-05-12 06:11:35 -0700637public:
638 GLPDLCDXferProcessor(const GrProcessor&) {}
639
640 virtual ~GLPDLCDXferProcessor() {}
641
642 static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
643 GrProcessorKeyBuilder* b) {}
644
645private:
cdaltonedbb31f2015-06-08 12:14:44 -0700646 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel4ca2e602015-11-18 08:01:26 -0800647 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
egdaniel56cf6dc2015-11-30 10:15:58 -0800648 SkASSERT(args.fInputCoverage);
egdaniel4ca2e602015-11-18 08:01:26 -0800649 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
650 args.fInputCoverage);
egdaniel0d5fd112015-05-12 06:11:35 -0700651 }
652
egdaniel018fb622015-10-28 07:26:40 -0700653 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {};
egdaniel0d5fd112015-05-12 06:11:35 -0700654
egdanielfa4cc8b2015-11-13 08:34:52 -0800655 typedef GrGLSLXferProcessor INHERITED;
egdaniel0d5fd112015-05-12 06:11:35 -0700656};
657
658///////////////////////////////////////////////////////////////////////////////
659
660PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
661 : fBlendConstant(blendConstant)
662 , fAlpha(alpha) {
663 this->initClassID<PDLCDXferProcessor>();
664}
665
cdalton6fd158e2015-05-27 15:08:33 -0700666GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
egdaniel0d5fd112015-05-12 06:11:35 -0700667 const GrProcOptInfo& colorPOI) {
cdalton6fd158e2015-05-27 15:08:33 -0700668 if (SkXfermode::kSrcOver_Mode != xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700669 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700670 }
671
672 if (kRGBA_GrColorComponentFlags != colorPOI.validFlags()) {
halcanary96fcdcc2015-08-27 07:41:13 -0700673 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700674 }
675
bsalomonae4738f2015-09-15 15:33:27 -0700676 GrColor blendConstant = GrUnpremulColor(colorPOI.color());
egdaniel0d5fd112015-05-12 06:11:35 -0700677 uint8_t alpha = GrColorUnpackA(blendConstant);
678 blendConstant |= (0xff << GrColor_SHIFT_A);
679
halcanary385fe4d2015-08-26 13:07:48 -0700680 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700681}
682
683PDLCDXferProcessor::~PDLCDXferProcessor() {
684}
685
egdaniel57d3b032015-11-13 11:57:27 -0800686void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
687 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700688 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700689}
690
egdaniel57d3b032015-11-13 11:57:27 -0800691GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700692 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700693}
694
695GrXferProcessor::OptFlags
ethannicholasde4166a2015-11-30 08:57:38 -0800696PDLCDXferProcessor::onGetOptimizations(const GrPipelineOptimizations& optimizations,
egdaniel0d5fd112015-05-12 06:11:35 -0700697 bool doesStencilWrite,
698 GrColor* overrideColor,
egdaniel56cf6dc2015-11-30 10:15:58 -0800699 const GrCaps& caps) const {
egdaniel0d5fd112015-05-12 06:11:35 -0700700 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
701 // value of the blend the constant. We should already have valid blend coeff's if we are at
702 // a point where we have RGB coverage. We don't need any color stages since the known color
703 // output is already baked into the blendConstant.
704 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
705 return GrXferProcessor::kOverrideColor_OptFlag;
706}
707
708///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700709
egdanielf2342722015-11-20 15:12:59 -0800710GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
cdalton6fd158e2015-05-27 15:08:33 -0700711 : fXfermode(xfermode) {
cdalton1fa45722015-06-02 10:43:39 -0700712 SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
egdanielf2342722015-11-20 15:12:59 -0800713 this->initClassID<GrPorterDuffXPFactory>();
egdaniel915187b2014-12-05 12:58:28 -0800714}
715
egdanielf2342722015-11-20 15:12:59 -0800716GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
717 static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
718 static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
719 static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
720 static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
721 static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
722 static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
723 static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
724 static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
725 static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
726 static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
727 static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
728 static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
729 static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
730 static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
731 static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
cdalton6fd158e2015-05-27 15:08:33 -0700732
egdanielf2342722015-11-20 15:12:59 -0800733 static GrPorterDuffXPFactory* gFactories[] = {
cdalton6fd158e2015-05-27 15:08:33 -0700734 &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
735 &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
736 &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
737 };
738 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
739
740 if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700741 return nullptr;
egdanielc016fb82014-12-03 11:41:54 -0800742 }
cdalton6fd158e2015-05-27 15:08:33 -0700743 return SkRef(gFactories[xfermode]);
egdanielc016fb82014-12-03 11:41:54 -0800744}
745
bsalomon50785a32015-02-06 07:02:37 -0800746GrXferProcessor*
egdanielf2342722015-11-20 15:12:59 -0800747GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800748 const GrPipelineOptimizations& optimizations,
cdalton86ae0a92015-06-08 15:11:04 -0700749 bool hasMixedSamples,
bsalomon6a44c6a2015-05-26 09:49:05 -0700750 const DstTexture* dstTexture) const {
egdaniel723b0502015-09-15 09:31:40 -0700751 BlendFormula blendFormula;
ethannicholasde4166a2015-11-30 08:57:38 -0800752 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700753 if (SkXfermode::kSrcOver_Mode == fXfermode &&
ethannicholasde4166a2015-11-30 08:57:38 -0800754 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdaniele73f1f62015-09-22 10:10:55 -0700755 !caps.shaderCaps()->dualSourceBlendingSupport() &&
756 !caps.shaderCaps()->dstReadInShaderSupport()) {
757 // If we don't have dual source blending or in shader dst reads, we fall back to this
758 // trick for rendering SrcOver LCD text instead of doing a dst copy.
egdaniel723b0502015-09-15 09:31:40 -0700759 SkASSERT(!dstTexture || !dstTexture->texture());
ethannicholasde4166a2015-11-30 08:57:38 -0800760 return PDLCDXferProcessor::Create(fXfermode, optimizations.fColorPOI);
egdaniel723b0502015-09-15 09:31:40 -0700761 }
ethannicholasde4166a2015-11-30 08:57:38 -0800762 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode);
egdaniel723b0502015-09-15 09:31:40 -0700763 } else {
ethannicholasde4166a2015-11-30 08:57:38 -0800764 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
765 hasMixedSamples, fXfermode);
egdaniel95131432014-12-09 11:15:43 -0800766 }
cdalton6fd158e2015-05-27 15:08:33 -0700767
cdalton6fd158e2015-05-27 15:08:33 -0700768 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -0700769 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
cdalton6fd158e2015-05-27 15:08:33 -0700770 }
771
772 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700773 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800774}
775
egdanielf2342722015-11-20 15:12:59 -0800776void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
cdalton1fa45722015-06-02 10:43:39 -0700777 InvariantBlendedColor* blendedColor) const {
778 // Find the blended color info based on the formula that does not have coverage.
779 BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
780 if (colorFormula.usesDstColor()) {
781 blendedColor->fWillBlendWithDst = true;
782 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800783 return;
egdaniel95131432014-12-09 11:15:43 -0800784 }
785
cdalton1fa45722015-06-02 10:43:39 -0700786 blendedColor->fWillBlendWithDst = false;
bungemanc33db932015-05-22 17:55:26 -0700787
cdalton1fa45722015-06-02 10:43:39 -0700788 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
bungemanc33db932015-05-22 17:55:26 -0700789
cdalton1fa45722015-06-02 10:43:39 -0700790 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800791 case kZero_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700792 blendedColor->fKnownColor = 0;
793 blendedColor->fKnownColorFlags = kRGBA_GrColorComponentFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700794 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800795
796 case kOne_GrBlendCoeff:
cdalton1fa45722015-06-02 10:43:39 -0700797 blendedColor->fKnownColor = colorPOI.color();
798 blendedColor->fKnownColorFlags = colorPOI.validFlags();
cdalton6fd158e2015-05-27 15:08:33 -0700799 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800800
cdalton1fa45722015-06-02 10:43:39 -0700801 default:
802 blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
803 return;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800804 }
egdaniel95131432014-12-09 11:15:43 -0800805}
806
egdanielf2342722015-11-20 15:12:59 -0800807bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800808 const GrPipelineOptimizations& optimizations,
cdalton86ae0a92015-06-08 15:11:04 -0700809 bool hasMixedSamples) const {
810 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
811 return false;
bungemanc33db932015-05-22 17:55:26 -0700812 }
egdaniel723b0502015-09-15 09:31:40 -0700813
814 // When we have four channel coverage we always need to read the dst in order to correctly
815 // blend. The one exception is when we are using srcover mode and we know the input color into
816 // the XP.
ethannicholasde4166a2015-11-30 08:57:38 -0800817 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
egdaniel723b0502015-09-15 09:31:40 -0700818 if (SkXfermode::kSrcOver_Mode == fXfermode &&
ethannicholasde4166a2015-11-30 08:57:38 -0800819 kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdaniele73f1f62015-09-22 10:10:55 -0700820 !caps.shaderCaps()->dstReadInShaderSupport()) {
egdaniel723b0502015-09-15 09:31:40 -0700821 return false;
822 }
ethannicholasde4166a2015-11-30 08:57:38 -0800823 return get_lcd_blend_formula(optimizations.fCoveragePOI, fXfermode).hasSecondaryOutput();
cdalton86ae0a92015-06-08 15:11:04 -0700824 }
cdalton6fd158e2015-05-27 15:08:33 -0700825 // We fallback on the shader XP when the blend formula would use dual source blending but we
826 // don't have support for it.
ethannicholasde4166a2015-11-30 08:57:38 -0800827 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, hasMixedSamples,
828 fXfermode).hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800829}
830
egdanielf2342722015-11-20 15:12:59 -0800831GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
egdanielc2304142014-12-11 13:15:13 -0800832
egdanielf2342722015-11-20 15:12:59 -0800833const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700834 SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
egdanielf2342722015-11-20 15:12:59 -0800835 return GrPorterDuffXPFactory::Create(mode);
egdanielc2304142014-12-11 13:15:13 -0800836}
egdaniel95131432014-12-09 11:15:43 -0800837
egdanielf2342722015-11-20 15:12:59 -0800838void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
839 int* outPrimary,
840 int* outSecondary) {
cdalton6fd158e2015-05-27 15:08:33 -0700841 if (!!strcmp(xp->name(), "Porter Duff")) {
842 *outPrimary = *outSecondary = -1;
843 return;
844 }
845 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
846 *outPrimary = blendFormula.fPrimaryOutputType;
847 *outSecondary = blendFormula.fSecondaryOutputType;
848}
egdanielc4b72722015-11-23 13:20:41 -0800849
850
851////////////////////////////////////////////////////////////////////////////////////////////////
852// SrcOver Global functions
853////////////////////////////////////////////////////////////////////////////////////////////////
bsalomon2047b782015-12-21 13:12:54 -0800854const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
855 static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
856 kISA_GrBlendCoeff);
857 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
858 return gSrcOverXP;
859}
egdanielc4b72722015-11-23 13:20:41 -0800860
861GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
862 const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800863 const GrPipelineOptimizations& optimizations,
egdanielc4b72722015-11-23 13:20:41 -0800864 bool hasMixedSamples,
865 const GrXferProcessor::DstTexture* dstTexture) {
egdaniel56cf6dc2015-11-30 10:15:58 -0800866 if (!optimizations.fCoveragePOI.isFourChannelOutput() &&
867 !(optimizations.fCoveragePOI.isSolidWhite() &&
868 !hasMixedSamples &&
869 optimizations.fColorPOI.isOpaque())) {
bsalomon2047b782015-12-21 13:12:54 -0800870 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
871 // We don't simply return the address of that XP here because our caller would have to unref
872 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
873 // safe.
874 return nullptr;
egdaniel56cf6dc2015-11-30 10:15:58 -0800875 }
876
egdanielc4b72722015-11-23 13:20:41 -0800877 BlendFormula blendFormula;
ethannicholasde4166a2015-11-30 08:57:38 -0800878 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
879 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdanielc4b72722015-11-23 13:20:41 -0800880 !caps.shaderCaps()->dualSourceBlendingSupport() &&
881 !caps.shaderCaps()->dstReadInShaderSupport()) {
882 // If we don't have dual source blending or in shader dst reads, we fall
883 // back to this trick for rendering SrcOver LCD text instead of doing a
884 // dst copy.
885 SkASSERT(!dstTexture || !dstTexture->texture());
ethannicholasde4166a2015-11-30 08:57:38 -0800886 return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, optimizations.fColorPOI);
egdanielc4b72722015-11-23 13:20:41 -0800887 }
ethannicholasde4166a2015-11-30 08:57:38 -0800888 blendFormula = get_lcd_blend_formula(optimizations.fCoveragePOI, SkXfermode::kSrcOver_Mode);
egdanielc4b72722015-11-23 13:20:41 -0800889 } else {
ethannicholasde4166a2015-11-30 08:57:38 -0800890 blendFormula = get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
891 hasMixedSamples, SkXfermode::kSrcOver_Mode);
egdanielc4b72722015-11-23 13:20:41 -0800892 }
893
894 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
895 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
896 }
897
898 SkASSERT(!dstTexture || !dstTexture->texture());
899 return new PorterDuffXferProcessor(blendFormula);
900}
901
902bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
ethannicholasde4166a2015-11-30 08:57:38 -0800903 const GrPipelineOptimizations& optimizations,
egdanielc4b72722015-11-23 13:20:41 -0800904 bool hasMixedSamples) {
905 if (caps.shaderCaps()->dstReadInShaderSupport() ||
906 caps.shaderCaps()->dualSourceBlendingSupport()) {
907 return false;
908 }
909
910 // When we have four channel coverage we always need to read the dst in order to correctly
911 // blend. The one exception is when we are using srcover mode and we know the input color
912 // into the XP.
ethannicholasde4166a2015-11-30 08:57:38 -0800913 if (optimizations.fCoveragePOI.isFourChannelOutput()) {
914 if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() &&
egdanielc4b72722015-11-23 13:20:41 -0800915 !caps.shaderCaps()->dstReadInShaderSupport()) {
916 return false;
917 }
ethannicholasde4166a2015-11-30 08:57:38 -0800918 return get_lcd_blend_formula(optimizations.fCoveragePOI,
919 SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
egdanielc4b72722015-11-23 13:20:41 -0800920 }
921 // We fallback on the shader XP when the blend formula would use dual source blending but we
922 // don't have support for it.
ethannicholasde4166a2015-11-30 08:57:38 -0800923 return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI,
egdanielc4b72722015-11-23 13:20:41 -0800924 hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
925}
926