1 /*
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
8 #include "src/gpu/effects/GrPorterDuffXferProcessor.h"
9
10 #include "include/gpu/GrTypes.h"
11 #include "include/private/SkMacros.h"
12 #include "include/private/SkTo.h"
13 #include "src/gpu/GrBlend.h"
14 #include "src/gpu/GrCaps.h"
15 #include "src/gpu/GrPipeline.h"
16 #include "src/gpu/GrProcessor.h"
17 #include "src/gpu/GrProcessorAnalysis.h"
18 #include "src/gpu/GrXferProcessor.h"
19 #include "src/gpu/glsl/GrGLSLBlend.h"
20 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
21 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
22 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
23
24 /**
25 * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
26 */
27 class BlendFormula {
28 public:
29 /**
30 * Values the shader can write to primary and secondary outputs. These are all modulated by
31 * coverage. The XP will ignore the multiplies when not using coverage.
32 */
33 enum OutputType {
34 kNone_OutputType, //<! 0
35 kCoverage_OutputType, //<! inputCoverage
36 kModulate_OutputType, //<! inputColor * inputCoverage
37 kSAModulate_OutputType, //<! inputColor.a * inputCoverage
38 kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
39 kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
40
41 kLast_OutputType = kISCModulate_OutputType
42 };
43
BlendFormula(OutputType primaryOut,OutputType secondaryOut,GrBlendEquation equation,GrBlendCoeff srcCoeff,GrBlendCoeff dstCoeff)44 constexpr BlendFormula(OutputType primaryOut, OutputType secondaryOut, GrBlendEquation equation,
45 GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff)
46 : fPrimaryOutputType(primaryOut)
47 , fSecondaryOutputType(secondaryOut)
48 , fBlendEquation(equation)
49 , fSrcCoeff(srcCoeff)
50 , fDstCoeff(dstCoeff)
51 , fProps(GetProperties(primaryOut, secondaryOut, equation, srcCoeff, dstCoeff)) {}
52
53 BlendFormula(const BlendFormula&) = default;
54 BlendFormula& operator=(const BlendFormula&) = default;
55
operator ==(const BlendFormula & that) const56 bool operator==(const BlendFormula& that) const {
57 return fPrimaryOutputType == that.fPrimaryOutputType &&
58 fSecondaryOutputType == that. fSecondaryOutputType &&
59 fBlendEquation == that.fBlendEquation &&
60 fSrcCoeff == that.fSrcCoeff &&
61 fDstCoeff == that.fDstCoeff &&
62 fProps == that.fProps;
63 }
64
hasSecondaryOutput() const65 bool hasSecondaryOutput() const {
66 return kNone_OutputType != fSecondaryOutputType;
67 }
modifiesDst() const68 bool modifiesDst() const {
69 return SkToBool(fProps & kModifiesDst_Property);
70 }
unaffectedByDst() const71 bool unaffectedByDst() const {
72 return SkToBool(fProps & kUnaffectedByDst_Property);
73 }
74 // We don't always fully optimize the blend formula (e.g., for opaque src-over), so we include
75 // an "IfOpaque" variant to help set AnalysisProperties::kUnaffectedByDstValue in those cases.
unaffectedByDstIfOpaque() const76 bool unaffectedByDstIfOpaque() const {
77 return SkToBool(fProps & kUnaffectedByDstIfOpaque_Property);
78 }
usesInputColor() const79 bool usesInputColor() const {
80 return SkToBool(fProps & kUsesInputColor_Property);
81 }
canTweakAlphaForCoverage() const82 bool canTweakAlphaForCoverage() const {
83 return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
84 }
85
equation() const86 GrBlendEquation equation() const {
87 return fBlendEquation;
88 }
89
srcCoeff() const90 GrBlendCoeff srcCoeff() const {
91 return fSrcCoeff;
92 }
93
dstCoeff() const94 GrBlendCoeff dstCoeff() const {
95 return fDstCoeff;
96 }
97
primaryOutput() const98 OutputType primaryOutput() const {
99 return fPrimaryOutputType;
100 }
101
secondaryOutput() const102 OutputType secondaryOutput() const {
103 return fSecondaryOutputType;
104 }
105
106 private:
107 enum Properties {
108 kModifiesDst_Property = 1 << 0,
109 kUnaffectedByDst_Property = 1 << 1,
110 kUnaffectedByDstIfOpaque_Property = 1 << 2,
111 kUsesInputColor_Property = 1 << 3,
112 kCanTweakAlphaForCoverage_Property = 1 << 4,
113
114 kLast_Property = kCanTweakAlphaForCoverage_Property
115 };
116 SK_DECL_BITFIELD_OPS_FRIENDS(Properties)
117
118 /**
119 * Deduce the properties of a BlendFormula.
120 */
121 static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut,
122 GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff,
123 GrBlendCoeff DstCoeff);
124
125 struct {
126 // We allot the enums one more bit than they require because MSVC seems to sign-extend
127 // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
128 OutputType fPrimaryOutputType : 4;
129 OutputType fSecondaryOutputType : 4;
130 GrBlendEquation fBlendEquation : 6;
131 GrBlendCoeff fSrcCoeff : 6;
132 GrBlendCoeff fDstCoeff : 6;
133 Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
134 };
135
136 static_assert(kLast_OutputType < (1 << 3));
137 static_assert(kLast_GrBlendEquation < (1 << 5));
138 static_assert(kLast_GrBlendCoeff < (1 << 5));
139 static_assert(kLast_Property < (1 << 6));
140 };
141
142 static_assert(4 == sizeof(BlendFormula));
143
SK_MAKE_BITFIELD_OPS(BlendFormula::Properties)144 SK_MAKE_BITFIELD_OPS(BlendFormula::Properties)
145
146 constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut,
147 OutputType SecondaryOut,
148 GrBlendEquation BlendEquation,
149 GrBlendCoeff SrcCoeff,
150 GrBlendCoeff DstCoeff) {
151 return
152 // The provided formula should already be optimized before a BlendFormula is constructed.
153 // Assert that here while setting up the properties in the constexpr constructor.
154 SkASSERT((kNone_OutputType == PrimaryOut) == !GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)),
155 SkASSERT(!GrBlendCoeffRefsSrc2(SrcCoeff)),
156 SkASSERT((kNone_OutputType == SecondaryOut) == !GrBlendCoeffRefsSrc2(DstCoeff)),
157 SkASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut),
158 SkASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut),
159
160 static_cast<Properties>(
161 (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) |
162 (!GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff, false/*srcColorIsOpaque*/)
163 ? kUnaffectedByDst_Property
164 : 0) |
165 (!GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff, true/*srcColorIsOpaque*/)
166 ? kUnaffectedByDstIfOpaque_Property
167 : 0) |
168 ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) ||
169 (SecondaryOut >= kModulate_OutputType &&
170 GrBlendCoeffRefsSrc2(DstCoeff))
171 ? kUsesInputColor_Property
172 : 0) | // We assert later that SrcCoeff doesn't ref src2.
173 ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
174 kNone_OutputType == SecondaryOut &&
175 GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff)
176 ? kCanTweakAlphaForCoverage_Property
177 : 0));
178 }
179
180 /**
181 * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
182 * Porter Duff formula.
183 */
MakeCoeffFormula(GrBlendCoeff srcCoeff,GrBlendCoeff dstCoeff)184 static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
185 // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none.
186 return (kZero_GrBlendCoeff == srcCoeff &&
187 (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff))
188 ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType,
189 kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff)
190 : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType,
191 kAdd_GrBlendEquation, srcCoeff, dstCoeff);
192 }
193
194 /**
195 * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in
196 * LCD dst-out.
197 */
MakeSAModulateFormula(GrBlendCoeff srcCoeff,GrBlendCoeff dstCoeff)198 static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
199 return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType,
200 kAdd_GrBlendEquation, srcCoeff, dstCoeff);
201 }
202
203 /**
204 * When there is coverage, the equation with f=coverage is:
205 *
206 * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
207 *
208 * This can be rewritten as:
209 *
210 * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
211 *
212 * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
213 * HW dst coeff with IS2C.
214 *
215 * Xfer modes: dst-atop (Sa!=1)
216 */
MakeCoverageFormula(BlendFormula::OutputType oneMinusDstCoeffModulateOutput,GrBlendCoeff srcCoeff)217 static constexpr BlendFormula MakeCoverageFormula(
218 BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) {
219 return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput,
220 kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff);
221 }
222
223 /**
224 * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
225 *
226 * D' = f * D * dstCoeff + (1-f) * D
227 *
228 * This can be rewritten as:
229 *
230 * D' = D - D * [f * (1 - dstCoeff)]
231 *
232 * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
233 * subtract HW blend equation with coeffs of (DC, One).
234 *
235 * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
236 */
MakeCoverageSrcCoeffZeroFormula(BlendFormula::OutputType oneMinusDstCoeffModulateOutput)237 static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula(
238 BlendFormula::OutputType oneMinusDstCoeffModulateOutput) {
239 return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType,
240 kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff);
241 }
242
243 /**
244 * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
245 *
246 * D' = f * S * srcCoeff + (1-f) * D
247 *
248 * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
249 * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
250 *
251 * Xfer modes (Sa!=1): src, src-in, src-out
252 */
MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff)253 static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) {
254 return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType,
255 kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff);
256 }
257
258 /**
259 * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
260 * with and without an opaque input color. Optimization properties are deduced at compile time so we
261 * can make runtime decisions quickly. RGB coverage is not supported.
262 */
263 static constexpr BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
264 /*>> No coverage, input color unknown <<*/ {{
265
266 /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
267 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff),
268 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
269 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
270 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
271 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
272 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff),
273 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
274 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
275 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
276 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
277 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
278 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
279 /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
280 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
281
282 }, /*>> Has coverage, input color unknown <<*/ {
283
284 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
285 /* src */ MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff),
286 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
287 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
288 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
289 /* src-in */ MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff),
290 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
291 /* src-out */ MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff),
292 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
293 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
294 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
295 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
296 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
297 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
298 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
299
300 }}, /*>> No coverage, input color opaque <<*/ {{
301
302 /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
303 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff),
304 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
305 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff), // see comment below
306 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
307 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
308 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
309 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
310 /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
311 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
312 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
313 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
314 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
315 /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
316 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
317
318 }, /*>> Has coverage, input color opaque <<*/ {
319
320 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
321 /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
322 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
323 /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
324 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
325 /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
326 /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
327 /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
328 /* dst-out */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
329 /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
330 /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
331 /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
332 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
333 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
334 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
335 }}};
336 // In the above table src-over is not optimized to src mode when the color is opaque because we
337 // found no advantage to doing so. Also, we are using a global src-over XP in most cases which is
338 // not specialized for opaque input. For GPUs where dropping to src (and thus able to disable
339 // blending) is an advantage we change the blend mode to src before getitng the blend formula from
340 // this table.
341 static constexpr BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
342 /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
343 /* src */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
344 /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
345 /* src-over */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
346 /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
347 /* src-in */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
348 /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
349 /* src-out */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
350 /* dst-out */ MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff),
351 /* src-atop */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
352 /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
353 /* xor */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
354 /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
355 /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
356 /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
357 };
358
get_blend_formula(bool isOpaque,bool hasCoverage,SkBlendMode xfermode)359 static BlendFormula get_blend_formula(bool isOpaque,
360 bool hasCoverage,
361 SkBlendMode xfermode) {
362 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
363 return gBlendTable[isOpaque][hasCoverage][(int)xfermode];
364 }
365
get_lcd_blend_formula(SkBlendMode xfermode)366 static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) {
367 SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
368
369 return gLCDBlendTable[(int)xfermode];
370 }
371
372 ///////////////////////////////////////////////////////////////////////////////
373
374 class PorterDuffXferProcessor : public GrXferProcessor {
375 public:
PorterDuffXferProcessor(BlendFormula blendFormula,GrProcessorAnalysisCoverage coverage)376 PorterDuffXferProcessor(BlendFormula blendFormula, GrProcessorAnalysisCoverage coverage)
377 : INHERITED(kPorterDuffXferProcessor_ClassID, /*willReadDstColor=*/false, coverage)
378 , fBlendFormula(blendFormula) {
379 }
380
name() const381 const char* name() const override { return "Porter Duff"; }
382
383 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
384
getBlendFormula() const385 BlendFormula getBlendFormula() const { return fBlendFormula; }
386
387 private:
388 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
389
onHasSecondaryOutput() const390 bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
391
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const392 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
393 blendInfo->fEquation = fBlendFormula.equation();
394 blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
395 blendInfo->fDstBlend = fBlendFormula.dstCoeff();
396 blendInfo->fWriteColor = fBlendFormula.modifiesDst();
397 }
398
onIsEqual(const GrXferProcessor & xpBase) const399 bool onIsEqual(const GrXferProcessor& xpBase) const override {
400 const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
401 return fBlendFormula == xp.fBlendFormula;
402 }
403
404 const BlendFormula fBlendFormula;
405
406 using INHERITED = GrXferProcessor;
407 };
408
409 ///////////////////////////////////////////////////////////////////////////////
410
append_color_output(const PorterDuffXferProcessor & xp,GrGLSLXPFragmentBuilder * fragBuilder,BlendFormula::OutputType outputType,const char * output,const char * inColor,const char * inCoverage)411 static void append_color_output(const PorterDuffXferProcessor& xp,
412 GrGLSLXPFragmentBuilder* fragBuilder,
413 BlendFormula::OutputType outputType, const char* output,
414 const char* inColor, const char* inCoverage) {
415 SkASSERT(inCoverage);
416 SkASSERT(inColor);
417 switch (outputType) {
418 case BlendFormula::kNone_OutputType:
419 fragBuilder->codeAppendf("%s = half4(0.0);", output);
420 break;
421 case BlendFormula::kCoverage_OutputType:
422 fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
423 break;
424 case BlendFormula::kModulate_OutputType:
425 fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
426 break;
427 case BlendFormula::kSAModulate_OutputType:
428 fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
429 break;
430 case BlendFormula::kISAModulate_OutputType:
431 fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
432 break;
433 case BlendFormula::kISCModulate_OutputType:
434 fragBuilder->codeAppendf("%s = (half4(1.0) - %s) * %s;", output, inColor, inCoverage);
435 break;
436 default:
437 SK_ABORT("Unsupported output type.");
438 break;
439 }
440 }
441
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const442 void PorterDuffXferProcessor::onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
443 b->add32(fBlendFormula.primaryOutput() | (fBlendFormula.secondaryOutput() << 3));
444 static_assert(BlendFormula::kLast_OutputType < 8);
445 }
446
makeProgramImpl() const447 std::unique_ptr<GrXferProcessor::ProgramImpl> PorterDuffXferProcessor::makeProgramImpl() const {
448 class Impl : public ProgramImpl {
449 private:
450 void emitOutputsForBlendState(const EmitArgs& args) override {
451 const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
452 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
453
454 const BlendFormula& blendFormula = xp.fBlendFormula;
455 if (blendFormula.hasSecondaryOutput()) {
456 append_color_output(xp,
457 fragBuilder,
458 blendFormula.secondaryOutput(),
459 args.fOutputSecondary,
460 args.fInputColor,
461 args.fInputCoverage);
462 }
463 append_color_output(xp,
464 fragBuilder,
465 blendFormula.primaryOutput(),
466 args.fOutputPrimary,
467 args.fInputColor,
468 args.fInputCoverage);
469 }
470 };
471
472 return std::make_unique<Impl>();
473 }
474
475 ///////////////////////////////////////////////////////////////////////////////
476
477 class ShaderPDXferProcessor : public GrXferProcessor {
478 public:
ShaderPDXferProcessor(SkBlendMode xfermode,GrProcessorAnalysisCoverage coverage)479 ShaderPDXferProcessor(SkBlendMode xfermode, GrProcessorAnalysisCoverage coverage)
480 : INHERITED(kShaderPDXferProcessor_ClassID, /*willReadDstColor=*/true, coverage)
481 , fXfermode(xfermode) {
482 }
483
name() const484 const char* name() const override { return "Porter Duff Shader"; }
485
486 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
487
488 private:
489 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
490
onIsEqual(const GrXferProcessor & xpBase) const491 bool onIsEqual(const GrXferProcessor& xpBase) const override {
492 const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
493 return fXfermode == xp.fXfermode;
494 }
495
496 const SkBlendMode fXfermode;
497
498 using INHERITED = GrXferProcessor;
499 };
500
501 ///////////////////////////////////////////////////////////////////////////////
502
503
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder * b) const504 void ShaderPDXferProcessor::onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
505 b->add32(static_cast<int>(fXfermode));
506 }
507
makeProgramImpl() const508 std::unique_ptr<GrXferProcessor::ProgramImpl> ShaderPDXferProcessor::makeProgramImpl() const {
509 class Impl : public ProgramImpl {
510 private:
511 void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
512 GrGLSLUniformHandler* uniformHandler,
513 const char* srcColor,
514 const char* srcCoverage,
515 const char* dstColor,
516 const char* outColor,
517 const char* outColorSecondary,
518 const GrXferProcessor& proc) override {
519 const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
520
521 GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.fXfermode);
522
523 // Apply coverage.
524 DefaultCoverageModulation(fragBuilder,
525 srcCoverage,
526 dstColor,
527 outColor,
528 outColorSecondary,
529 xp);
530 }
531 };
532
533 return std::make_unique<Impl>();
534 }
535
536 ///////////////////////////////////////////////////////////////////////////////
537
538 class PDLCDXferProcessor : public GrXferProcessor {
539 public:
540 static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
541 const GrProcessorAnalysisColor& inputColor);
542
name() const543 const char* name() const override { return "Porter Duff LCD"; }
544
545 std::unique_ptr<ProgramImpl> makeProgramImpl() const override;
546
547 private:
548 PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha);
549
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const550 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
551
onGetBlendInfo(GrXferProcessor::BlendInfo * blendInfo) const552 void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
553 blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
554 blendInfo->fDstBlend = kISC_GrBlendCoeff;
555 blendInfo->fBlendConstant = fBlendConstant;
556 }
557
onIsEqual(const GrXferProcessor & xpBase) const558 bool onIsEqual(const GrXferProcessor& xpBase) const override {
559 const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
560 if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) {
561 return false;
562 }
563 return true;
564 }
565
566 SkPMColor4f fBlendConstant;
567 float fAlpha;
568
569 using INHERITED = GrXferProcessor;
570 };
571
PDLCDXferProcessor(const SkPMColor4f & blendConstant,float alpha)572 PDLCDXferProcessor::PDLCDXferProcessor(const SkPMColor4f& blendConstant, float alpha)
573 : INHERITED(kPDLCDXferProcessor_ClassID, /*willReadDstColor=*/false,
574 GrProcessorAnalysisCoverage::kLCD)
575 , fBlendConstant(blendConstant)
576 , fAlpha(alpha) {
577 }
578
Make(SkBlendMode mode,const GrProcessorAnalysisColor & color)579 sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
580 const GrProcessorAnalysisColor& color) {
581 if (SkBlendMode::kSrcOver != mode) {
582 return nullptr;
583 }
584 SkPMColor4f blendConstantPM;
585 if (!color.isConstant(&blendConstantPM)) {
586 return nullptr;
587 }
588 SkColor4f blendConstantUPM = blendConstantPM.unpremul();
589 float alpha = blendConstantUPM.fA;
590 blendConstantPM = { blendConstantUPM.fR, blendConstantUPM.fG, blendConstantUPM.fB, 1 };
591 return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstantPM, alpha));
592 }
593
makeProgramImpl() const594 std::unique_ptr<GrXferProcessor::ProgramImpl> PDLCDXferProcessor::makeProgramImpl() const {
595 class Impl : public ProgramImpl {
596 private:
597 void emitOutputsForBlendState(const EmitArgs& args) override {
598 const char* alpha;
599 fAlphaUniform = args.fUniformHandler->addUniform(nullptr,
600 kFragment_GrShaderFlag,
601 kHalf_GrSLType,
602 "alpha",
603 &alpha);
604 GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
605 // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
606 // value of the src color. We know that there are no color stages (or we wouldn't have
607 // created this xp) and the r,g, and b channels of the op's input color are baked into
608 // the blend constant.
609 SkASSERT(args.fInputCoverage);
610 fragBuilder->codeAppendf("%s = %s * %s;",
611 args.fOutputPrimary,
612 alpha, args.fInputCoverage);
613 }
614
615 void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override {
616 float alpha = xp.cast<PDLCDXferProcessor>().fAlpha;
617 if (fLastAlpha != alpha) {
618 pdm.set1f(fAlphaUniform, alpha);
619 fLastAlpha = alpha;
620 }
621 }
622
623 GrGLSLUniformHandler::UniformHandle fAlphaUniform;
624 float fLastAlpha = SK_FloatNaN;
625 };
626
627 return std::make_unique<Impl>();
628 }
629
630 ///////////////////////////////////////////////////////////////////////////////
631
GrPorterDuffXPFactory(SkBlendMode xfermode)632 constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
633 : fBlendMode(xfermode) {}
634
Get(SkBlendMode blendMode)635 const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
636 SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
637
638 static constexpr const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
639 static constexpr const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
640 static constexpr const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
641 static constexpr const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
642 static constexpr const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
643 static constexpr const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
644 static constexpr const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
645 static constexpr const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
646 static constexpr const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
647 static constexpr const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
648 static constexpr const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
649 static constexpr const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
650 static constexpr const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
651 static constexpr const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
652 static constexpr const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
653
654 switch (blendMode) {
655 case SkBlendMode::kClear:
656 return &gClearPDXPF;
657 case SkBlendMode::kSrc:
658 return &gSrcPDXPF;
659 case SkBlendMode::kDst:
660 return &gDstPDXPF;
661 case SkBlendMode::kSrcOver:
662 return &gSrcOverPDXPF;
663 case SkBlendMode::kDstOver:
664 return &gDstOverPDXPF;
665 case SkBlendMode::kSrcIn:
666 return &gSrcInPDXPF;
667 case SkBlendMode::kDstIn:
668 return &gDstInPDXPF;
669 case SkBlendMode::kSrcOut:
670 return &gSrcOutPDXPF;
671 case SkBlendMode::kDstOut:
672 return &gDstOutPDXPF;
673 case SkBlendMode::kSrcATop:
674 return &gSrcATopPDXPF;
675 case SkBlendMode::kDstATop:
676 return &gDstATopPDXPF;
677 case SkBlendMode::kXor:
678 return &gXorPDXPF;
679 case SkBlendMode::kPlus:
680 return &gPlusPDXPF;
681 case SkBlendMode::kModulate:
682 return &gModulatePDXPF;
683 case SkBlendMode::kScreen:
684 return &gScreenPDXPF;
685 default:
686 SK_ABORT("Unexpected blend mode.");
687 }
688 }
689
makeXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps,GrClampType clampType) const690 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
691 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
692 const GrCaps& caps, GrClampType clampType) const {
693 bool isLCD = coverage == GrProcessorAnalysisCoverage::kLCD;
694 // See comment in MakeSrcOverXferProcessor about color.isOpaque here
695 if (isLCD &&
696 SkBlendMode::kSrcOver == fBlendMode && color.isConstant() && /*color.isOpaque() &&*/
697 !caps.shaderCaps()->dualSourceBlendingSupport() &&
698 !caps.shaderCaps()->dstReadInShaderSupport()) {
699 // If we don't have dual source blending or in shader dst reads, we fall back to this
700 // trick for rendering SrcOver LCD text instead of doing a dst copy.
701 return PDLCDXferProcessor::Make(fBlendMode, color);
702 }
703 BlendFormula blendFormula = [&](){
704 if (isLCD) {
705 return get_lcd_blend_formula(fBlendMode);
706 }
707 if (fBlendMode == SkBlendMode::kSrcOver && color.isOpaque() &&
708 coverage == GrProcessorAnalysisCoverage::kNone &&
709 caps.shouldCollapseSrcOverToSrcWhenAble())
710 {
711 return get_blend_formula(true, false, SkBlendMode::kSrc);
712 }
713 return get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage,
714 fBlendMode);
715 }();
716
717 // Skia always saturates after the kPlus blend mode, so it requires shader-based blending when
718 // pixels aren't guaranteed to automatically be normalized (i.e. any floating point config).
719 if ((blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) ||
720 (isLCD && (SkBlendMode::kSrcOver != fBlendMode /*|| !color.isOpaque()*/)) ||
721 (GrClampType::kAuto != clampType && SkBlendMode::kPlus == fBlendMode)) {
722 return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(fBlendMode, coverage));
723 }
724 return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
725 }
726
analysis_properties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType,SkBlendMode mode)727 static inline GrXPFactory::AnalysisProperties analysis_properties(
728 const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage,
729 const GrCaps& caps, GrClampType clampType, SkBlendMode mode) {
730 using AnalysisProperties = GrXPFactory::AnalysisProperties;
731 AnalysisProperties props = AnalysisProperties::kNone;
732 bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
733 bool isLCD = GrProcessorAnalysisCoverage::kLCD == coverage;
734 BlendFormula formula = [&](){
735 if (isLCD) {
736 return gLCDBlendTable[(int)mode];
737 }
738 return get_blend_formula(color.isOpaque(), hasCoverage, mode);
739 }();
740
741 if (formula.canTweakAlphaForCoverage() && !isLCD) {
742 props |= AnalysisProperties::kCompatibleWithCoverageAsAlpha;
743 }
744
745 if (isLCD) {
746 // See comment in MakeSrcOverXferProcessor about color.isOpaque here
747 if (SkBlendMode::kSrcOver == mode && color.isConstant() && /*color.isOpaque() &&*/
748 !caps.shaderCaps()->dualSourceBlendingSupport() &&
749 !caps.shaderCaps()->dstReadInShaderSupport()) {
750 props |= AnalysisProperties::kIgnoresInputColor;
751 } else {
752 // For LCD blending, if the color is not opaque we must read the dst in shader even if
753 // we have dual source blending. The opaqueness check must be done after blending so for
754 // simplicity we only allow src-over to not take the dst read path (though src, src-in,
755 // and DstATop would also work). We also fall into the dst read case for src-over if we
756 // do not have dual source blending.
757 if (SkBlendMode::kSrcOver != mode ||
758 /*!color.isOpaque() ||*/ // See comment in MakeSrcOverXferProcessor about isOpaque.
759 (formula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport())) {
760 props |= AnalysisProperties::kReadsDstInShader;
761 }
762 }
763 } else {
764 // With dual-source blending we never need the destination color in the shader.
765 if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
766 if (formula.hasSecondaryOutput()) {
767 props |= AnalysisProperties::kReadsDstInShader;
768 }
769 }
770 }
771
772 if (GrClampType::kAuto != clampType && SkBlendMode::kPlus == mode) {
773 props |= AnalysisProperties::kReadsDstInShader;
774 }
775
776 if (!formula.modifiesDst() || !formula.usesInputColor()) {
777 props |= AnalysisProperties::kIgnoresInputColor;
778 }
779 if (formula.unaffectedByDst() || (formula.unaffectedByDstIfOpaque() && color.isOpaque() &&
780 !hasCoverage)) {
781 props |= AnalysisProperties::kUnaffectedByDstValue;
782 }
783 return props;
784 }
785
analysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType) const786 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
787 const GrProcessorAnalysisColor& color,
788 const GrProcessorAnalysisCoverage& coverage,
789 const GrCaps& caps,
790 GrClampType clampType) const {
791 return analysis_properties(color, coverage, caps, clampType, fBlendMode);
792 }
793
794 GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
795
796 #if GR_TEST_UTILS
TestGet(GrProcessorTestData * d)797 const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
798 SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
799 return GrPorterDuffXPFactory::Get(mode);
800 }
801 #endif
802
TestGetXPOutputTypes(const GrXferProcessor * xp,int * outPrimary,int * outSecondary)803 void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
804 int* outPrimary,
805 int* outSecondary) {
806 if (!!strcmp(xp->name(), "Porter Duff")) {
807 *outPrimary = *outSecondary = -1;
808 return;
809 }
810 BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
811 *outPrimary = blendFormula.primaryOutput();
812 *outSecondary = blendFormula.secondaryOutput();
813 }
814
815 ////////////////////////////////////////////////////////////////////////////////////////////////
816 // SrcOver Global functions
817 ////////////////////////////////////////////////////////////////////////////////////////////////
SimpleSrcOverXP()818 const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
819 static BlendFormula gSrcOverBlendFormula =
820 MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
821 static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula,
822 GrProcessorAnalysisCoverage::kSingleChannel);
823 return gSrcOverXP;
824 }
825
MakeSrcOverXferProcessor(const GrProcessorAnalysisColor & color,GrProcessorAnalysisCoverage coverage,const GrCaps & caps)826 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
827 const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
828 const GrCaps& caps) {
829 // We want to not make an xfer processor if possible. Thus for the simple case where we are not
830 // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
831 // the general case where we convert a src-over blend that has solid coverage and an opaque
832 // color to src-mode, which allows disabling of blending.
833 if (coverage != GrProcessorAnalysisCoverage::kLCD) {
834 if (color.isOpaque() && coverage == GrProcessorAnalysisCoverage::kNone &&
835 caps.shouldCollapseSrcOverToSrcWhenAble()) {
836 BlendFormula blendFormula = get_blend_formula(true, false, SkBlendMode::kSrc);
837 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
838 }
839 // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
840 // We don't simply return the address of that XP here because our caller would have to unref
841 // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
842 // safe.
843 return nullptr;
844 }
845
846 // Currently up the stack Skia is requiring that the dst is opaque or that the client has said
847 // the opaqueness doesn't matter. Thus for src-over we don't need to worry about the src color
848 // being opaque or not. This allows us to use faster code paths as well as avoid various bugs
849 // that occur with dst reads in the shader blending. For now we disable the check for
850 // opaqueness, but in the future we should pass down the knowledge about dst opaqueness and make
851 // the correct decision here.
852 //
853 // This also fixes a chrome bug on macs where we are getting random fuzziness when doing
854 // blending in the shader for non opaque sources.
855 if (color.isConstant() && /*color.isOpaque() &&*/
856 !caps.shaderCaps()->dualSourceBlendingSupport() &&
857 !caps.shaderCaps()->dstReadInShaderSupport()) {
858 // If we don't have dual source blending or in shader dst reads, we fall
859 // back to this trick for rendering SrcOver LCD text instead of doing a
860 // dst copy.
861 return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color);
862 }
863
864 BlendFormula blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
865 // See comment above regarding why the opaque check is commented out here.
866 if (/*!color.isOpaque() ||*/
867 (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport())) {
868 return sk_sp<GrXferProcessor>(new ShaderPDXferProcessor(SkBlendMode::kSrcOver, coverage));
869 }
870 return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula, coverage));
871 }
872
MakeNoCoverageXP(SkBlendMode blendmode)873 sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
874 BlendFormula formula = get_blend_formula(false, false, blendmode);
875 return sk_make_sp<PorterDuffXferProcessor>(formula, GrProcessorAnalysisCoverage::kNone);
876 }
877
SrcOverAnalysisProperties(const GrProcessorAnalysisColor & color,const GrProcessorAnalysisCoverage & coverage,const GrCaps & caps,GrClampType clampType)878 GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
879 const GrProcessorAnalysisColor& color,
880 const GrProcessorAnalysisCoverage& coverage,
881 const GrCaps& caps,
882 GrClampType clampType) {
883 return analysis_properties(color, coverage, caps, clampType, SkBlendMode::kSrcOver);
884 }
885