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