blob: 6b7d0ba025c4230cadb6ed64809dbeea6fbe0589 [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 */
Mike Reedd4706732016-11-15 16:44:34 -0500230static const BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
cdalton6fd158e2015-05-27 15:08:33 -0700231
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
Mike Reedd4706732016-11-15 16:44:34 -0500305static const BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
egdaniel723b0502015-09-15 09:31:40 -0700306 /* 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
Brian Salomon5be6c952017-01-20 19:06:29 +0000323static BlendFormula get_blend_formula(bool isOpaque,
324 bool hasCoverage,
cdalton86ae0a92015-06-08 15:11:04 -0700325 bool hasMixedSamples,
Mike Reed7d954ad2016-10-28 15:42:34 -0400326 SkBlendMode xfermode) {
327 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
Brian Salomon5be6c952017-01-20 19:06:29 +0000328 bool conflatesCoverage = hasCoverage || hasMixedSamples;
329 return gBlendTable[isOpaque][conflatesCoverage][(int)xfermode];
egdaniel95131432014-12-09 11:15:43 -0800330}
331
Brian Salomon5be6c952017-01-20 19:06:29 +0000332static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400333 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
egdaniel723b0502015-09-15 09:31:40 -0700334
Mike Reed7d954ad2016-10-28 15:42:34 -0400335 return gLCDBlendTable[(int)xfermode];
egdaniel723b0502015-09-15 09:31:40 -0700336}
337
cdalton6fd158e2015-05-27 15:08:33 -0700338///////////////////////////////////////////////////////////////////////////////
339
egdaniel41d4f092015-02-09 07:51:00 -0800340class PorterDuffXferProcessor : public GrXferProcessor {
egdaniel378092f2014-12-03 10:40:13 -0800341public:
cdalton86ae0a92015-06-08 15:11:04 -0700342 PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
343 this->initClassID<PorterDuffXferProcessor>();
egdaniel41d4f092015-02-09 07:51:00 -0800344 }
egdaniel378092f2014-12-03 10:40:13 -0800345
mtklein36352bf2015-03-25 18:17:31 -0700346 const char* name() const override { return "Porter Duff"; }
egdaniel41d4f092015-02-09 07:51:00 -0800347
egdaniel57d3b032015-11-13 11:57:27 -0800348 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel41d4f092015-02-09 07:51:00 -0800349
cdalton6fd158e2015-05-27 15:08:33 -0700350 BlendFormula getBlendFormula() const { return fBlendFormula; }
cdaltonf4f2b442015-04-23 09:40:23 -0700351
352private:
Brian Salomon92aee3d2016-12-21 09:20:25 -0500353 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineAnalysis&,
egdanielc19cdc22015-05-10 08:45:18 -0700354 bool doesStencilWrite,
355 GrColor* overrideColor,
Brian Salomon92aee3d2016-12-21 09:20:25 -0500356 const GrCaps&) const override;
egdanielc19cdc22015-05-10 08:45:18 -0700357
Brian Salomon94efbf52016-11-29 13:43:05 -0500358 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
cdaltonf4f2b442015-04-23 09:40:23 -0700359
cdaltonedbb31f2015-06-08 12:14:44 -0700360 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
361
cdaltonf4f2b442015-04-23 09:40:23 -0700362 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
cdalton6fd158e2015-05-27 15:08:33 -0700363 blendInfo->fEquation = fBlendFormula.fBlendEquation;
364 blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
365 blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
366 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
egdaniel41d4f092015-02-09 07:51:00 -0800367 }
368
mtklein36352bf2015-03-25 18:17:31 -0700369 bool onIsEqual(const GrXferProcessor& xpBase) const override {
egdaniel41d4f092015-02-09 07:51:00 -0800370 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
cdalton6fd158e2015-05-27 15:08:33 -0700371 return fBlendFormula == xp.fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800372 }
373
cdalton6fd158e2015-05-27 15:08:33 -0700374 const BlendFormula fBlendFormula;
egdaniel41d4f092015-02-09 07:51:00 -0800375
376 typedef GrXferProcessor INHERITED;
377};
378
379///////////////////////////////////////////////////////////////////////////////
380
egdaniel2d721d32015-11-11 13:06:05 -0800381static void append_color_output(const PorterDuffXferProcessor& xp,
egdaniel4ca2e602015-11-18 08:01:26 -0800382 GrGLSLXPFragmentBuilder* fragBuilder,
cdalton6fd158e2015-05-27 15:08:33 -0700383 BlendFormula::OutputType outputType, const char* output,
384 const char* inColor, const char* inCoverage) {
Brian Salomon8c852be2017-01-04 10:44:42 -0500385 SkASSERT(inCoverage);
386 SkASSERT(inColor);
cdalton6fd158e2015-05-27 15:08:33 -0700387 switch (outputType) {
388 case BlendFormula::kNone_OutputType:
egdaniel4ca2e602015-11-18 08:01:26 -0800389 fragBuilder->codeAppendf("%s = vec4(0.0);", output);
cdalton6fd158e2015-05-27 15:08:33 -0700390 break;
391 case BlendFormula::kCoverage_OutputType:
cdalton86ae0a92015-06-08 15:11:04 -0700392 // We can have a coverage formula while not reading coverage if there are mixed samples.
Brian Salomon8c852be2017-01-04 10:44:42 -0500393 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700394 break;
395 case BlendFormula::kModulate_OutputType:
Brian Salomon8c852be2017-01-04 10:44:42 -0500396 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700397 break;
egdaniel723b0502015-09-15 09:31:40 -0700398 case BlendFormula::kSAModulate_OutputType:
Brian Salomon8c852be2017-01-04 10:44:42 -0500399 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
egdaniel723b0502015-09-15 09:31:40 -0700400 break;
cdalton6fd158e2015-05-27 15:08:33 -0700401 case BlendFormula::kISAModulate_OutputType:
Brian Salomon8c852be2017-01-04 10:44:42 -0500402 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700403 break;
404 case BlendFormula::kISCModulate_OutputType:
Brian Salomon8c852be2017-01-04 10:44:42 -0500405 fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
cdalton6fd158e2015-05-27 15:08:33 -0700406 break;
407 default:
408 SkFAIL("Unsupported output type.");
409 break;
egdaniel3ad65702015-02-17 11:15:47 -0800410 }
411}
412
egdanielfa4cc8b2015-11-13 08:34:52 -0800413class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
egdaniel41d4f092015-02-09 07:51:00 -0800414public:
cdalton6fd158e2015-05-27 15:08:33 -0700415 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
egdaniel41d4f092015-02-09 07:51:00 -0800416 const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
egdaniel56cf6dc2015-11-30 10:15:58 -0800417 b->add32(xp.getBlendFormula().fPrimaryOutputType |
418 (xp.getBlendFormula().fSecondaryOutputType << 3));
cdalton6fd158e2015-05-27 15:08:33 -0700419 GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400420 }
bsalomon50785a32015-02-06 07:02:37 -0800421
422private:
cdaltonedbb31f2015-06-08 12:14:44 -0700423 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel41d4f092015-02-09 07:51:00 -0800424 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
egdaniel4ca2e602015-11-18 08:01:26 -0800425 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
bungemanc33db932015-05-22 17:55:26 -0700426
cdalton6fd158e2015-05-27 15:08:33 -0700427 BlendFormula blendFormula = xp.getBlendFormula();
428 if (blendFormula.hasSecondaryOutput()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800429 append_color_output(xp, fragBuilder, blendFormula.fSecondaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700430 args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
egdanielc2304142014-12-11 13:15:13 -0800431 }
egdaniel4ca2e602015-11-18 08:01:26 -0800432 append_color_output(xp, fragBuilder, blendFormula.fPrimaryOutputType,
cdalton6fd158e2015-05-27 15:08:33 -0700433 args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
egdaniel378092f2014-12-03 10:40:13 -0800434 }
435
egdaniel018fb622015-10-28 07:26:40 -0700436 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel378092f2014-12-03 10:40:13 -0800437
egdanielfa4cc8b2015-11-13 08:34:52 -0800438 typedef GrGLSLXferProcessor INHERITED;
egdaniel378092f2014-12-03 10:40:13 -0800439};
440
441///////////////////////////////////////////////////////////////////////////////
442
Brian Salomon94efbf52016-11-29 13:43:05 -0500443void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
egdaniel57d3b032015-11-13 11:57:27 -0800444 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700445 GLPorterDuffXferProcessor::GenKey(*this, b);
joshualitteb2a6762014-12-04 11:35:33 -0800446}
447
egdaniel57d3b032015-11-13 11:57:27 -0800448GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700449 return new GLPorterDuffXferProcessor;
egdaniel378092f2014-12-03 10:40:13 -0800450}
451
Brian Salomon92aee3d2016-12-21 09:20:25 -0500452GrXferProcessor::OptFlags PorterDuffXferProcessor::onGetOptimizations(
453 const GrPipelineAnalysis& analysis,
454 bool doesStencilWrite,
455 GrColor* overrideColor,
456 const GrCaps& caps) const {
bsalomon7765a472015-07-08 11:26:37 -0700457 GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700458 if (!fBlendFormula.modifiesDst()) {
459 if (!doesStencilWrite) {
460 optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
461 }
462 optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
cdalton6fd158e2015-05-27 15:08:33 -0700463 GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
464 } else {
465 if (!fBlendFormula.usesInputColor()) {
466 optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
467 }
Brian Salomonf3b995b2017-02-15 10:22:23 -0500468 if (analysis.fColorPOI.allProcessorsCompatibleWithCoverageAsAlpha() &&
Brian Salomoneb628292017-02-15 14:12:26 -0500469 analysis.fCoveragePOI.allProcessorsCompatibleWithCoverageAsAlpha() &&
470 fBlendFormula.canTweakAlphaForCoverage()) {
cdalton6fd158e2015-05-27 15:08:33 -0700471 optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
472 }
473 }
bungemanc33db932015-05-22 17:55:26 -0700474 return optFlags;
475}
476
cdalton6fd158e2015-05-27 15:08:33 -0700477///////////////////////////////////////////////////////////////////////////////
478
479class ShaderPDXferProcessor : public GrXferProcessor {
480public:
cdalton86ae0a92015-06-08 15:11:04 -0700481 ShaderPDXferProcessor(const DstTexture* dstTexture,
482 bool hasMixedSamples,
Mike Reed7d954ad2016-10-28 15:42:34 -0400483 SkBlendMode xfermode)
cdalton86ae0a92015-06-08 15:11:04 -0700484 : INHERITED(dstTexture, true, hasMixedSamples)
485 , fXfermode(xfermode) {
486 this->initClassID<ShaderPDXferProcessor>();
bungemanc33db932015-05-22 17:55:26 -0700487 }
488
cdalton6fd158e2015-05-27 15:08:33 -0700489 const char* name() const override { return "Porter Duff Shader"; }
cdalton6fd158e2015-05-27 15:08:33 -0700490
egdaniel57d3b032015-11-13 11:57:27 -0800491 GrGLSLXferProcessor* createGLSLInstance() const override;
cdalton6fd158e2015-05-27 15:08:33 -0700492
Mike Reed7d954ad2016-10-28 15:42:34 -0400493 SkBlendMode getXfermode() const { return fXfermode; }
cdalton6fd158e2015-05-27 15:08:33 -0700494
495private:
Brian Salomon92aee3d2016-12-21 09:20:25 -0500496 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineAnalysis&, bool, GrColor*,
egdaniel56cf6dc2015-11-30 10:15:58 -0800497 const GrCaps&) const override {
bsalomon7765a472015-07-08 11:26:37 -0700498 return kNone_OptFlags;
cdalton6fd158e2015-05-27 15:08:33 -0700499 }
500
Brian Salomon94efbf52016-11-29 13:43:05 -0500501 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
cdalton6fd158e2015-05-27 15:08:33 -0700502
503 bool onIsEqual(const GrXferProcessor& xpBase) const override {
504 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
505 return fXfermode == xp.fXfermode;
506 }
507
Mike Reed7d954ad2016-10-28 15:42:34 -0400508 const SkBlendMode fXfermode;
cdalton6fd158e2015-05-27 15:08:33 -0700509
510 typedef GrXferProcessor INHERITED;
511};
512
513///////////////////////////////////////////////////////////////////////////////
514
egdanielfa4cc8b2015-11-13 08:34:52 -0800515class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
cdalton6fd158e2015-05-27 15:08:33 -0700516public:
517 static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
518 const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
Mike Reed7d954ad2016-10-28 15:42:34 -0400519 b->add32((int)xp.getXfermode());
egdaniel3ad65702015-02-17 11:15:47 -0800520 }
egdaniel87509242014-12-17 13:37:13 -0800521
cdalton6fd158e2015-05-27 15:08:33 -0700522private:
egdaniel7ea439b2015-12-03 09:20:44 -0800523 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
524 GrGLSLUniformHandler* uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800525 const char* srcColor,
egdanielf34b2932015-12-01 13:54:06 -0800526 const char* srcCoverage,
egdaniel4ca2e602015-11-18 08:01:26 -0800527 const char* dstColor,
528 const char* outColor,
egdanielf34b2932015-12-01 13:54:06 -0800529 const char* outColorSecondary,
egdaniel4ca2e602015-11-18 08:01:26 -0800530 const GrXferProcessor& proc) override {
cdaltonedbb31f2015-06-08 12:14:44 -0700531 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
egdaniel95131432014-12-09 11:15:43 -0800532
egdaniel4ca2e602015-11-18 08:01:26 -0800533 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
egdanielf34b2932015-12-01 13:54:06 -0800534
535 // Apply coverage.
robertphillipsf42fca42016-01-27 05:00:04 -0800536 INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
537 outColorSecondary, xp);
egdaniel95131432014-12-09 11:15:43 -0800538 }
539
egdaniel018fb622015-10-28 07:26:40 -0700540 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
bungemanc33db932015-05-22 17:55:26 -0700541
egdanielfa4cc8b2015-11-13 08:34:52 -0800542 typedef GrGLSLXferProcessor INHERITED;
cdalton6fd158e2015-05-27 15:08:33 -0700543};
bungemanc33db932015-05-22 17:55:26 -0700544
cdalton6fd158e2015-05-27 15:08:33 -0700545///////////////////////////////////////////////////////////////////////////////
bungemanc33db932015-05-22 17:55:26 -0700546
Brian Salomon94efbf52016-11-29 13:43:05 -0500547void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
egdaniel57d3b032015-11-13 11:57:27 -0800548 GrProcessorKeyBuilder* b) const {
cdalton6fd158e2015-05-27 15:08:33 -0700549 GLShaderPDXferProcessor::GenKey(*this, b);
bungemanc33db932015-05-22 17:55:26 -0700550}
551
egdaniel57d3b032015-11-13 11:57:27 -0800552GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700553 return new GLShaderPDXferProcessor;
egdanielc2304142014-12-11 13:15:13 -0800554}
555
egdaniel378092f2014-12-03 10:40:13 -0800556///////////////////////////////////////////////////////////////////////////////
557
egdaniel0d5fd112015-05-12 06:11:35 -0700558class PDLCDXferProcessor : public GrXferProcessor {
559public:
Mike Reed7d954ad2016-10-28 15:42:34 -0400560 static GrXferProcessor* Create(SkBlendMode xfermode, const GrProcOptInfo& colorPOI);
egdaniel0d5fd112015-05-12 06:11:35 -0700561
562 ~PDLCDXferProcessor() override;
563
564 const char* name() const override { return "Porter Duff LCD"; }
565
egdaniel57d3b032015-11-13 11:57:27 -0800566 GrGLSLXferProcessor* createGLSLInstance() const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700567
egdaniel0d5fd112015-05-12 06:11:35 -0700568private:
569 PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
570
Brian Salomon92aee3d2016-12-21 09:20:25 -0500571 GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineAnalysis&,
egdaniel0d5fd112015-05-12 06:11:35 -0700572 bool doesStencilWrite,
573 GrColor* overrideColor,
Brian Salomon92aee3d2016-12-21 09:20:25 -0500574 const GrCaps&) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700575
Brian Salomon94efbf52016-11-29 13:43:05 -0500576 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
egdaniel0d5fd112015-05-12 06:11:35 -0700577
578 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
579 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
580 blendInfo->fDstBlend = kISC_GrBlendCoeff;
581 blendInfo->fBlendConstant = fBlendConstant;
582 }
583
584 bool onIsEqual(const GrXferProcessor& xpBase) const override {
585 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
586 if (fBlendConstant != xp.fBlendConstant ||
587 fAlpha != xp.fAlpha) {
588 return false;
589 }
590 return true;
591 }
592
593 GrColor fBlendConstant;
594 uint8_t fAlpha;
595
596 typedef GrXferProcessor INHERITED;
597};
598
599///////////////////////////////////////////////////////////////////////////////
600
egdanielfa4cc8b2015-11-13 08:34:52 -0800601class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
egdaniel0d5fd112015-05-12 06:11:35 -0700602public:
603 GLPDLCDXferProcessor(const GrProcessor&) {}
604
605 virtual ~GLPDLCDXferProcessor() {}
606
Brian Salomon94efbf52016-11-29 13:43:05 -0500607 static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps,
egdaniel0d5fd112015-05-12 06:11:35 -0700608 GrProcessorKeyBuilder* b) {}
609
610private:
cdaltonedbb31f2015-06-08 12:14:44 -0700611 void emitOutputsForBlendState(const EmitArgs& args) override {
egdaniel4ca2e602015-11-18 08:01:26 -0800612 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
egdaniel56cf6dc2015-11-30 10:15:58 -0800613 SkASSERT(args.fInputCoverage);
egdaniel4ca2e602015-11-18 08:01:26 -0800614 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
615 args.fInputCoverage);
egdaniel0d5fd112015-05-12 06:11:35 -0700616 }
617
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400618 void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
egdaniel0d5fd112015-05-12 06:11:35 -0700619
egdanielfa4cc8b2015-11-13 08:34:52 -0800620 typedef GrGLSLXferProcessor INHERITED;
egdaniel0d5fd112015-05-12 06:11:35 -0700621};
622
623///////////////////////////////////////////////////////////////////////////////
624
625PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
626 : fBlendConstant(blendConstant)
627 , fAlpha(alpha) {
628 this->initClassID<PDLCDXferProcessor>();
629}
630
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500631GrXferProcessor* PDLCDXferProcessor::Create(SkBlendMode xfermode, const GrProcOptInfo& colorPOI) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400632 if (SkBlendMode::kSrcOver != xfermode) {
halcanary96fcdcc2015-08-27 07:41:13 -0700633 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700634 }
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500635 GrColor blendConstant;
636 if (!colorPOI.hasKnownOutputColor(&blendConstant)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700637 return nullptr;
egdaniel0d5fd112015-05-12 06:11:35 -0700638 }
egdaniel0d5fd112015-05-12 06:11:35 -0700639 uint8_t alpha = GrColorUnpackA(blendConstant);
640 blendConstant |= (0xff << GrColor_SHIFT_A);
halcanary385fe4d2015-08-26 13:07:48 -0700641 return new PDLCDXferProcessor(blendConstant, alpha);
egdaniel0d5fd112015-05-12 06:11:35 -0700642}
643
644PDLCDXferProcessor::~PDLCDXferProcessor() {
645}
646
Brian Salomon94efbf52016-11-29 13:43:05 -0500647void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800648 GrProcessorKeyBuilder* b) const {
egdanielcc252972015-05-12 12:03:28 -0700649 GLPDLCDXferProcessor::GenKey(*this, caps, b);
egdaniel0d5fd112015-05-12 06:11:35 -0700650}
651
egdaniel57d3b032015-11-13 11:57:27 -0800652GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700653 return new GLPDLCDXferProcessor(*this);
egdaniel0d5fd112015-05-12 06:11:35 -0700654}
655
Brian Salomon92aee3d2016-12-21 09:20:25 -0500656GrXferProcessor::OptFlags PDLCDXferProcessor::onGetOptimizations(const GrPipelineAnalysis&,
657 bool doesStencilWrite,
658 GrColor* overrideColor,
659 const GrCaps& caps) const {
660 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
661 // value of the blend the constant. We should already have valid blend coeff's if we are at
662 // a point where we have RGB coverage. We don't need any color stages since the known color
663 // output is already baked into the blendConstant.
664 *overrideColor = GrColorPackRGBA(fAlpha, fAlpha, fAlpha, fAlpha);
665 return GrXferProcessor::kOverrideColor_OptFlag;
egdaniel0d5fd112015-05-12 06:11:35 -0700666}
667
668///////////////////////////////////////////////////////////////////////////////
cdalton6fd158e2015-05-27 15:08:33 -0700669
Brian Salomona1633922017-01-09 11:46:10 -0500670constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
671 : fBlendMode(xfermode) {}
egdaniel915187b2014-12-05 12:58:28 -0800672
Brian Salomona1633922017-01-09 11:46:10 -0500673const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
674 SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
cdalton6fd158e2015-05-27 15:08:33 -0700675
Brian Salomona1633922017-01-09 11:46:10 -0500676 // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are
677 // null.
678#ifdef SK_BUILD_FOR_WIN
679#define _CONSTEXPR_
680#else
681#define _CONSTEXPR_ constexpr
682#endif
683 static _CONSTEXPR_ const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
684 static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
685 static _CONSTEXPR_ const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
686 static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
687 static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
688 static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
689 static _CONSTEXPR_ const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
690 static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
691 static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
692 static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
693 static _CONSTEXPR_ const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
694 static _CONSTEXPR_ const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
695 static _CONSTEXPR_ const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
696 static _CONSTEXPR_ const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
697 static _CONSTEXPR_ const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
698#undef _CONSTEXPR_
cdalton6fd158e2015-05-27 15:08:33 -0700699
Brian Salomona1633922017-01-09 11:46:10 -0500700 switch (blendMode) {
701 case SkBlendMode::kClear:
702 return &gClearPDXPF;
703 case SkBlendMode::kSrc:
704 return &gSrcPDXPF;
705 case SkBlendMode::kDst:
706 return &gDstPDXPF;
707 case SkBlendMode::kSrcOver:
708 return &gSrcOverPDXPF;
709 case SkBlendMode::kDstOver:
710 return &gDstOverPDXPF;
711 case SkBlendMode::kSrcIn:
712 return &gSrcInPDXPF;
713 case SkBlendMode::kDstIn:
714 return &gDstInPDXPF;
715 case SkBlendMode::kSrcOut:
716 return &gSrcOutPDXPF;
717 case SkBlendMode::kDstOut:
718 return &gDstOutPDXPF;
719 case SkBlendMode::kSrcATop:
720 return &gSrcATopPDXPF;
721 case SkBlendMode::kDstATop:
722 return &gDstATopPDXPF;
723 case SkBlendMode::kXor:
724 return &gXorPDXPF;
725 case SkBlendMode::kPlus:
726 return &gPlusPDXPF;
727 case SkBlendMode::kModulate:
728 return &gModulatePDXPF;
729 case SkBlendMode::kScreen:
730 return &gScreenPDXPF;
731 default:
732 SkFAIL("Unexpected blend mode.");
733 return nullptr;
egdanielc016fb82014-12-03 11:41:54 -0800734 }
735}
736
Brian Salomon92aee3d2016-12-21 09:20:25 -0500737GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
738 const GrPipelineAnalysis& analysis,
739 bool hasMixedSamples,
740 const DstTexture* dstTexture) const {
741 if (analysis.fUsesPLSDstRead) {
Brian Salomona1633922017-01-09 11:46:10 -0500742 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fBlendMode);
ethannicholas22793252016-01-30 09:59:10 -0800743 }
egdaniel723b0502015-09-15 09:31:40 -0700744 BlendFormula blendFormula;
Brian Salomonaab259e2017-01-17 10:44:34 -0500745 if (analysis.fCoveragePOI.isLCDCoverage()) {
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500746 if (SkBlendMode::kSrcOver == fBlendMode && analysis.fColorPOI.hasKnownOutputColor() &&
egdaniele73f1f62015-09-22 10:10:55 -0700747 !caps.shaderCaps()->dualSourceBlendingSupport() &&
748 !caps.shaderCaps()->dstReadInShaderSupport()) {
749 // If we don't have dual source blending or in shader dst reads, we fall back to this
750 // trick for rendering SrcOver LCD text instead of doing a dst copy.
egdaniel723b0502015-09-15 09:31:40 -0700751 SkASSERT(!dstTexture || !dstTexture->texture());
Brian Salomona1633922017-01-09 11:46:10 -0500752 return PDLCDXferProcessor::Create(fBlendMode, analysis.fColorPOI);
egdaniel723b0502015-09-15 09:31:40 -0700753 }
Brian Salomon5be6c952017-01-20 19:06:29 +0000754 blendFormula = get_lcd_blend_formula(fBlendMode);
egdaniel723b0502015-09-15 09:31:40 -0700755 } else {
Brian Salomon5be6c952017-01-20 19:06:29 +0000756 blendFormula = get_blend_formula(analysis.fColorPOI.isOpaque(),
757 !analysis.fCoveragePOI.isSolidWhite(), hasMixedSamples,
Brian Salomona1633922017-01-09 11:46:10 -0500758 fBlendMode);
egdaniel95131432014-12-09 11:15:43 -0800759 }
cdalton6fd158e2015-05-27 15:08:33 -0700760
cdalton6fd158e2015-05-27 15:08:33 -0700761 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
Brian Salomona1633922017-01-09 11:46:10 -0500762 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fBlendMode);
cdalton6fd158e2015-05-27 15:08:33 -0700763 }
764
765 SkASSERT(!dstTexture || !dstTexture->texture());
halcanary385fe4d2015-08-26 13:07:48 -0700766 return new PorterDuffXferProcessor(blendFormula);
egdaniel378092f2014-12-03 10:40:13 -0800767}
Brian Salomon9a514982017-02-14 10:28:22 -0500768bool GrPorterDuffXPFactory::isPreCoverageBlendedColorConstant(const GrProcOptInfo& colorInput,
769 GrColor* color) const {
770 BlendFormula colorFormula = gBlendTable[colorInput.isOpaque()][0][(int)fBlendMode];
cdalton1fa45722015-06-02 10:43:39 -0700771 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
Brian Salomon9a514982017-02-14 10:28:22 -0500772 if (colorFormula.usesDstColor()) {
773 return false;
774 }
cdalton1fa45722015-06-02 10:43:39 -0700775 switch (colorFormula.fSrcCoeff) {
egdaniel9e4ecdc2014-12-18 12:44:55 -0800776 case kZero_GrBlendCoeff:
Brian Salomon9a514982017-02-14 10:28:22 -0500777 *color = GrColor_TRANSPARENT_BLACK;
778 return true;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800779 case kOne_GrBlendCoeff:
Brian Salomon9a514982017-02-14 10:28:22 -0500780 return colorInput.hasKnownOutputColor(color);
cdalton1fa45722015-06-02 10:43:39 -0700781 default:
Brian Salomon9a514982017-02-14 10:28:22 -0500782 return false;
egdaniel9e4ecdc2014-12-18 12:44:55 -0800783 }
egdaniel95131432014-12-09 11:15:43 -0800784}
785
Brian Salomon9a514982017-02-14 10:28:22 -0500786bool GrPorterDuffXPFactory::willReadsDst(const GrProcOptInfo& colorInput,
787 const GrProcOptInfo& coverageInput) const {
788 BlendFormula colorFormula = gBlendTable[colorInput.isOpaque()][0][(int)fBlendMode];
789 SkASSERT(kAdd_GrBlendEquation == colorFormula.fBlendEquation);
790 return (colorFormula.usesDstColor() || !coverageInput.isSolidWhite());
791}
792
793bool GrPorterDuffXPFactory::willReadDstInShader(const GrCaps& caps, ColorType colorType,
794 CoverageType coverageType) const {
cdalton86ae0a92015-06-08 15:11:04 -0700795 if (caps.shaderCaps()->dualSourceBlendingSupport()) {
796 return false;
bungemanc33db932015-05-22 17:55:26 -0700797 }
halcanary9d524f22016-03-29 09:03:52 -0700798
egdaniel723b0502015-09-15 09:31:40 -0700799 // When we have four channel coverage we always need to read the dst in order to correctly
800 // blend. The one exception is when we are using srcover mode and we know the input color into
801 // the XP.
Brian Salomon5be6c952017-01-20 19:06:29 +0000802 if (CoverageType::kLCD == coverageType) {
803 if (SkBlendMode::kSrcOver == fBlendMode && ColorTypeIsConstant(colorType) &&
egdaniele73f1f62015-09-22 10:10:55 -0700804 !caps.shaderCaps()->dstReadInShaderSupport()) {
egdaniel723b0502015-09-15 09:31:40 -0700805 return false;
806 }
Brian Salomon5be6c952017-01-20 19:06:29 +0000807 return get_lcd_blend_formula(fBlendMode).hasSecondaryOutput();
cdalton86ae0a92015-06-08 15:11:04 -0700808 }
cdalton3ccf2e72016-05-06 09:41:16 -0700809
cdalton6fd158e2015-05-27 15:08:33 -0700810 // We fallback on the shader XP when the blend formula would use dual source blending but we
811 // don't have support for it.
cdalton3ccf2e72016-05-06 09:41:16 -0700812 static const bool kHasMixedSamples = false;
813 SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending.
Brian Salomon5be6c952017-01-20 19:06:29 +0000814 auto formula = get_blend_formula(ColorTypeIsOpaque(colorType),
815 CoverageType::kSingleChannel == coverageType, kHasMixedSamples,
Brian Salomona1633922017-01-09 11:46:10 -0500816 fBlendMode);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500817 return formula.hasSecondaryOutput();
bsalomon50785a32015-02-06 07:02:37 -0800818}
819
egdanielf2342722015-11-20 15:12:59 -0800820GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
egdanielc2304142014-12-11 13:15:13 -0800821
Hal Canary6f6961e2017-01-31 13:50:44 -0500822#if GR_TEST_UTILS
Brian Salomona1633922017-01-09 11:46:10 -0500823const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400824 SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
Brian Salomona1633922017-01-09 11:46:10 -0500825 return GrPorterDuffXPFactory::Get(mode);
egdanielc2304142014-12-11 13:15:13 -0800826}
Hal Canary6f6961e2017-01-31 13:50:44 -0500827#endif
egdaniel95131432014-12-09 11:15:43 -0800828
egdanielf2342722015-11-20 15:12:59 -0800829void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
830 int* outPrimary,
831 int* outSecondary) {
cdalton6fd158e2015-05-27 15:08:33 -0700832 if (!!strcmp(xp->name(), "Porter Duff")) {
833 *outPrimary = *outSecondary = -1;
834 return;
835 }
836 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
837 *outPrimary = blendFormula.fPrimaryOutputType;
838 *outSecondary = blendFormula.fSecondaryOutputType;
839}
egdanielc4b72722015-11-23 13:20:41 -0800840
egdanielc4b72722015-11-23 13:20:41 -0800841////////////////////////////////////////////////////////////////////////////////////////////////
842// SrcOver Global functions
843////////////////////////////////////////////////////////////////////////////////////////////////
bsalomon2047b782015-12-21 13:12:54 -0800844const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
845 static BlendFormula gSrcOverBlendFormula = COEFF_FORMULA(kOne_GrBlendCoeff,
846 kISA_GrBlendCoeff);
847 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
848 return gSrcOverXP;
849}
egdanielc4b72722015-11-23 13:20:41 -0800850
851GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
852 const GrCaps& caps,
Brian Salomon92aee3d2016-12-21 09:20:25 -0500853 const GrPipelineAnalysis& analysis,
egdanielc4b72722015-11-23 13:20:41 -0800854 bool hasMixedSamples,
855 const GrXferProcessor::DstTexture* dstTexture) {
Brian Salomon92aee3d2016-12-21 09:20:25 -0500856 if (analysis.fUsesPLSDstRead) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400857 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkBlendMode::kSrcOver);
ethannicholas22793252016-01-30 09:59:10 -0800858 }
egdanielabe795e2016-08-18 15:21:55 -0700859
860 // We want to not make an xfer processor if possible. Thus for the simple case where we are not
861 // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
862 // the general case where we convert a src-over blend that has solid coverage and an opaque
863 // color to src-mode, which allows disabling of blending.
Brian Salomonaab259e2017-01-17 10:44:34 -0500864 if (!analysis.fCoveragePOI.isLCDCoverage()) {
bsalomon2047b782015-12-21 13:12:54 -0800865 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
866 // We don't simply return the address of that XP here because our caller would have to unref
867 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
868 // safe.
869 return nullptr;
egdaniel56cf6dc2015-11-30 10:15:58 -0800870 }
871
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500872 if (analysis.fColorPOI.hasKnownOutputColor() &&
egdanielabe795e2016-08-18 15:21:55 -0700873 !caps.shaderCaps()->dualSourceBlendingSupport() &&
874 !caps.shaderCaps()->dstReadInShaderSupport()) {
875 // If we don't have dual source blending or in shader dst reads, we fall
876 // back to this trick for rendering SrcOver LCD text instead of doing a
877 // dst copy.
878 SkASSERT(!dstTexture || !dstTexture->texture());
Brian Salomon92aee3d2016-12-21 09:20:25 -0500879 return PDLCDXferProcessor::Create(SkBlendMode::kSrcOver, analysis.fColorPOI);
egdanielc4b72722015-11-23 13:20:41 -0800880 }
881
egdanielabe795e2016-08-18 15:21:55 -0700882 BlendFormula blendFormula;
Brian Salomon5be6c952017-01-20 19:06:29 +0000883 blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
egdanielc4b72722015-11-23 13:20:41 -0800884 if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
Mike Reed7d954ad2016-10-28 15:42:34 -0400885 return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkBlendMode::kSrcOver);
egdanielc4b72722015-11-23 13:20:41 -0800886 }
887
888 SkASSERT(!dstTexture || !dstTexture->texture());
889 return new PorterDuffXferProcessor(blendFormula);
890}
891
csmartdalton119fb2b2017-02-08 14:41:05 -0500892sk_sp<GrXferProcessor> GrPorterDuffXPFactory::CreateNoCoverageXP(SkBlendMode blendmode) {
893 BlendFormula formula = get_blend_formula(false, false, false, blendmode);
894 return sk_make_sp<PorterDuffXferProcessor>(formula);
895}
896
Brian Salomon9a514982017-02-14 10:28:22 -0500897bool GrPorterDuffXPFactory::WillSrcOverReadDst(const GrProcOptInfo& colorInput,
898 const GrProcOptInfo& coverageInput) {
899 return !coverageInput.isSolidWhite() || !colorInput.isOpaque();
900}
901
902bool GrPorterDuffXPFactory::IsSrcOverPreCoverageBlendedColorConstant(
903 const GrProcOptInfo& colorInput, GrColor* color) {
904 if (!colorInput.isOpaque()) {
905 return false;
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500906 }
Brian Salomon9a514982017-02-14 10:28:22 -0500907 return colorInput.hasKnownOutputColor(color);
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500908}
909
egdanielc4b72722015-11-23 13:20:41 -0800910bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps,
Brian Salomon92aee3d2016-12-21 09:20:25 -0500911 const GrPipelineAnalysis& analysis) {
egdanielc4b72722015-11-23 13:20:41 -0800912 if (caps.shaderCaps()->dstReadInShaderSupport() ||
913 caps.shaderCaps()->dualSourceBlendingSupport()) {
914 return false;
915 }
916
917 // When we have four channel coverage we always need to read the dst in order to correctly
918 // blend. The one exception is when we are using srcover mode and we know the input color
919 // into the XP.
Brian Salomonaab259e2017-01-17 10:44:34 -0500920 if (analysis.fCoveragePOI.isLCDCoverage()) {
Brian Salomoneec6f7b2017-02-10 14:29:38 -0500921 if (analysis.fColorPOI.hasKnownOutputColor() &&
egdanielc4b72722015-11-23 13:20:41 -0800922 !caps.shaderCaps()->dstReadInShaderSupport()) {
923 return false;
924 }
Brian Salomon5be6c952017-01-20 19:06:29 +0000925 auto formula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500926 return formula.hasSecondaryOutput();
egdanielc4b72722015-11-23 13:20:41 -0800927 }
cdalton3ccf2e72016-05-06 09:41:16 -0700928
egdanielc4b72722015-11-23 13:20:41 -0800929 // We fallback on the shader XP when the blend formula would use dual source blending but we
930 // don't have support for it.
cdalton3ccf2e72016-05-06 09:41:16 -0700931 static const bool kHasMixedSamples = false;
Brian Salomon5be6c952017-01-20 19:06:29 +0000932 bool isOpaque = analysis.fColorPOI.isOpaque();
933 bool hasCoverage = !analysis.fCoveragePOI.isSolidWhite();
cdalton3ccf2e72016-05-06 09:41:16 -0700934 SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending.
Brian Salomon5be6c952017-01-20 19:06:29 +0000935 auto formula =
936 get_blend_formula(isOpaque, hasCoverage, kHasMixedSamples, SkBlendMode::kSrcOver);
Brian Salomon92aee3d2016-12-21 09:20:25 -0500937 return formula.hasSecondaryOutput();
egdanielc4b72722015-11-23 13:20:41 -0800938}