Line data Source code
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 "effects/GrPorterDuffXferProcessor.h"
9 :
10 : #include "GrBlend.h"
11 : #include "GrCaps.h"
12 : #include "GrPipeline.h"
13 : #include "GrProcessor.h"
14 : #include "GrProcessorAnalysis.h"
15 : #include "GrTypes.h"
16 : #include "GrXferProcessor.h"
17 : #include "glsl/GrGLSLBlend.h"
18 : #include "glsl/GrGLSLFragmentShaderBuilder.h"
19 : #include "glsl/GrGLSLProgramDataManager.h"
20 : #include "glsl/GrGLSLUniformHandler.h"
21 : #include "glsl/GrGLSLXferProcessor.h"
22 :
23 : /**
24 : * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
25 : */
26 : class BlendFormula {
27 : public:
28 : /**
29 : * Values the shader can write to primary and secondary outputs. These must all be modulated by
30 : * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
31 : */
32 : enum OutputType {
33 : kNone_OutputType, //<! 0
34 : kCoverage_OutputType, //<! inputCoverage
35 : kModulate_OutputType, //<! inputColor * inputCoverage
36 : kSAModulate_OutputType, //<! inputColor.a * inputCoverage
37 : kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
38 : kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
39 :
40 : kLast_OutputType = kISCModulate_OutputType
41 : };
42 :
43 0 : BlendFormula() = default;
44 :
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 0 : BlendFormula& operator=(const BlendFormula& other) {
55 0 : SkDEBUGCODE(other.validatePreoptimized());
56 0 : fData = other.fData;
57 0 : return *this;
58 : }
59 :
60 0 : bool operator==(const BlendFormula& other) const {
61 0 : SkDEBUGCODE(this->validatePreoptimized());
62 0 : SkDEBUGCODE(other.validatePreoptimized());
63 0 : return fData == other.fData;
64 : }
65 :
66 0 : bool hasSecondaryOutput() const {
67 0 : SkDEBUGCODE(this->validatePreoptimized());
68 0 : return kNone_OutputType != fSecondaryOutputType;
69 : }
70 0 : bool modifiesDst() const {
71 0 : SkDEBUGCODE(this->validatePreoptimized());
72 0 : return SkToBool(fProps & kModifiesDst_Property);
73 : }
74 0 : bool usesDstColor() const {
75 0 : SkDEBUGCODE(this->validatePreoptimized());
76 0 : return SkToBool(fProps & kUsesDstColor_Property);
77 : }
78 0 : bool usesInputColor() const {
79 0 : SkDEBUGCODE(this->validatePreoptimized());
80 0 : return SkToBool(fProps & kUsesInputColor_Property);
81 : }
82 0 : bool canTweakAlphaForCoverage() const {
83 0 : SkDEBUGCODE(this->validatePreoptimized());
84 0 : return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
85 : }
86 :
87 0 : GrBlendEquation equation() const {
88 0 : SkDEBUGCODE(this->validatePreoptimized());
89 0 : return fBlendEquation;
90 : }
91 :
92 0 : GrBlendCoeff srcCoeff() const {
93 0 : SkDEBUGCODE(this->validatePreoptimized());
94 0 : return fSrcCoeff;
95 : }
96 :
97 0 : GrBlendCoeff dstCoeff() const {
98 0 : SkDEBUGCODE(this->validatePreoptimized());
99 0 : return fDstCoeff;
100 : }
101 :
102 0 : OutputType primaryOutput() const {
103 0 : SkDEBUGCODE(this->validatePreoptimized());
104 0 : return fPrimaryOutputType;
105 : }
106 :
107 0 : OutputType secondaryOutput() const {
108 0 : SkDEBUGCODE(this->validatePreoptimized());
109 0 : return fSecondaryOutputType;
110 : }
111 :
112 : private:
113 : enum Properties {
114 : kModifiesDst_Property = 1,
115 : kUsesDstColor_Property = 1 << 1,
116 : kUsesInputColor_Property = 1 << 2,
117 : kCanTweakAlphaForCoverage_Property = 1 << 3,
118 :
119 : kLast_Property = kCanTweakAlphaForCoverage_Property
120 : };
121 : GR_DECL_BITFIELD_OPS_FRIENDS(Properties)
122 :
123 : #ifdef SK_DEBUG
124 0 : void validatePreoptimized() const {
125 : // The provided formula should already be optimized before a BlendFormula is constructed.
126 : // Preferably these asserts would be done statically in the constexpr constructor, but this
127 : // is not allowed in C++11.
128 0 : SkASSERT((kNone_OutputType == fPrimaryOutputType) ==
129 : !GrBlendCoeffsUseSrcColor(fSrcCoeff, fDstCoeff));
130 0 : SkASSERT(!GrBlendCoeffRefsSrc2(fSrcCoeff));
131 0 : SkASSERT((kNone_OutputType == fSecondaryOutputType) == !GrBlendCoeffRefsSrc2(fDstCoeff));
132 0 : SkASSERT(fPrimaryOutputType != fSecondaryOutputType ||
133 : kNone_OutputType == fPrimaryOutputType);
134 0 : SkASSERT(kNone_OutputType != fPrimaryOutputType ||
135 : kNone_OutputType == fSecondaryOutputType);
136 0 : }
137 : #endif
138 :
139 : /**
140 : * Deduce the properties of a BlendFormula.
141 : */
142 : static constexpr Properties GetProperties(OutputType PrimaryOut, OutputType SecondaryOut,
143 : GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff,
144 : GrBlendCoeff DstCoeff);
145 :
146 : union {
147 : struct {
148 : // We allot the enums one more bit than they require because MSVC seems to sign-extend
149 : // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
150 : OutputType fPrimaryOutputType : 4;
151 : OutputType fSecondaryOutputType : 4;
152 : GrBlendEquation fBlendEquation : 6;
153 : GrBlendCoeff fSrcCoeff : 6;
154 : GrBlendCoeff fDstCoeff : 6;
155 : Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
156 : };
157 : uint32_t fData;
158 : };
159 :
160 : GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
161 : GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
162 : GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
163 : GR_STATIC_ASSERT(kLast_Property < (1 << 6));
164 : };
165 :
166 : GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
167 :
168 0 : GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
169 :
170 : constexpr BlendFormula::Properties BlendFormula::GetProperties(OutputType PrimaryOut,
171 : OutputType SecondaryOut,
172 : GrBlendEquation BlendEquation,
173 : GrBlendCoeff SrcCoeff,
174 : GrBlendCoeff DstCoeff) {
175 : return static_cast<Properties>(
176 : (GrBlendModifiesDst(BlendEquation, SrcCoeff, DstCoeff) ? kModifiesDst_Property : 0) |
177 : (GrBlendCoeffsUseDstColor(SrcCoeff, DstCoeff) ? kUsesDstColor_Property : 0) |
178 : ((PrimaryOut >= kModulate_OutputType && GrBlendCoeffsUseSrcColor(SrcCoeff, DstCoeff)) ||
179 : (SecondaryOut >= kModulate_OutputType &&
180 : GrBlendCoeffRefsSrc2(DstCoeff))
181 : ? kUsesInputColor_Property
182 : : 0) | // We assert later that SrcCoeff doesn't ref src2.
183 : ((kModulate_OutputType == PrimaryOut || kNone_OutputType == PrimaryOut) &&
184 : kNone_OutputType == SecondaryOut &&
185 : GrBlendAllowsCoverageAsAlpha(BlendEquation, SrcCoeff, DstCoeff)
186 : ? kCanTweakAlphaForCoverage_Property
187 : : 0));
188 : }
189 :
190 : /**
191 : * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
192 : * Porter Duff formula.
193 : */
194 : static constexpr BlendFormula MakeCoeffFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
195 : // When the coeffs are (Zero, Zero) or (Zero, One) we set the primary output to none.
196 : return (kZero_GrBlendCoeff == srcCoeff &&
197 : (kZero_GrBlendCoeff == dstCoeff || kOne_GrBlendCoeff == dstCoeff))
198 : ? BlendFormula(BlendFormula::kNone_OutputType, BlendFormula::kNone_OutputType,
199 : kAdd_GrBlendEquation, kZero_GrBlendCoeff, dstCoeff)
200 : : BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kNone_OutputType,
201 : kAdd_GrBlendEquation, srcCoeff, dstCoeff);
202 : }
203 :
204 : /**
205 : * Basic coeff formula similar to MakeCoeffFormula but we will make the src f*Sa. This is used in
206 : * LCD dst-out.
207 : */
208 : static constexpr BlendFormula MakeSAModulateFormula(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
209 : return BlendFormula(BlendFormula::kSAModulate_OutputType, BlendFormula::kNone_OutputType,
210 : kAdd_GrBlendEquation, srcCoeff, dstCoeff);
211 : }
212 :
213 : /**
214 : * When there is coverage, the equation with f=coverage is:
215 : *
216 : * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
217 : *
218 : * This can be rewritten as:
219 : *
220 : * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
221 : *
222 : * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
223 : * HW dst coeff with IS2C.
224 : *
225 : * Xfer modes: dst-atop (Sa!=1)
226 : */
227 : static constexpr BlendFormula MakeCoverageFormula(
228 : BlendFormula::OutputType oneMinusDstCoeffModulateOutput, GrBlendCoeff srcCoeff) {
229 : return BlendFormula(BlendFormula::kModulate_OutputType, oneMinusDstCoeffModulateOutput,
230 : kAdd_GrBlendEquation, srcCoeff, kIS2C_GrBlendCoeff);
231 : }
232 :
233 : /**
234 : * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
235 : *
236 : * D' = f * D * dstCoeff + (1-f) * D
237 : *
238 : * This can be rewritten as:
239 : *
240 : * D' = D - D * [f * (1 - dstCoeff)]
241 : *
242 : * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
243 : * subtract HW blend equation with coeffs of (DC, One).
244 : *
245 : * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
246 : */
247 : static constexpr BlendFormula MakeCoverageSrcCoeffZeroFormula(
248 : BlendFormula::OutputType oneMinusDstCoeffModulateOutput) {
249 : return BlendFormula(oneMinusDstCoeffModulateOutput, BlendFormula::kNone_OutputType,
250 : kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff);
251 : }
252 :
253 : /**
254 : * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
255 : *
256 : * D' = f * S * srcCoeff + (1-f) * D
257 : *
258 : * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
259 : * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
260 : *
261 : * Xfer modes (Sa!=1): src, src-in, src-out
262 : */
263 : static constexpr BlendFormula MakeCoverageDstCoeffZeroFormula(GrBlendCoeff srcCoeff) {
264 : return BlendFormula(BlendFormula::kModulate_OutputType, BlendFormula::kCoverage_OutputType,
265 : kAdd_GrBlendEquation, srcCoeff, kIS2A_GrBlendCoeff);
266 : }
267 :
268 : // Older GCC won't like the constexpr arrays because of
269 : // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61484.
270 : // MSVC crashes with an internal compiler error.
271 : #if !defined(__clang__) && ((defined(__GNUC__) && __GNUC__ < 5) || defined(_MSC_VER))
272 : # define MAYBE_CONSTEXPR const
273 : #else
274 : # define MAYBE_CONSTEXPR constexpr
275 : #endif
276 :
277 : /**
278 : * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
279 : * with and without an opaque input color. Optimization properties are deduced at compile time so we
280 : * can make runtime decisions quickly. RGB coverage is not supported.
281 : */
282 : static MAYBE_CONSTEXPR BlendFormula gBlendTable[2][2][(int)SkBlendMode::kLastCoeffMode + 1] = {
283 : /*>> No coverage, input color unknown <<*/ {{
284 :
285 : /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
286 : /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_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 */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
291 : /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kSA_GrBlendCoeff),
292 : /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
293 : /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
294 : /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
295 : /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
296 : /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
297 : /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
298 : /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
299 : /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
300 :
301 : }, /*>> Has coverage, input color unknown <<*/ {
302 :
303 : /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
304 : /* src */ MakeCoverageDstCoeffZeroFormula(kOne_GrBlendCoeff),
305 : /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
306 : /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
307 : /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
308 : /* src-in */ MakeCoverageDstCoeffZeroFormula(kDA_GrBlendCoeff),
309 : /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
310 : /* src-out */ MakeCoverageDstCoeffZeroFormula(kIDA_GrBlendCoeff),
311 : /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kISA_GrBlendCoeff),
312 : /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
313 : /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
314 : /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
315 : /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
316 : /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
317 : /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
318 :
319 : }}, /*>> No coverage, input color opaque <<*/ {{
320 :
321 : /* clear */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
322 : /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff),
323 : /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
324 : /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kZero_GrBlendCoeff),
325 : /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
326 : /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
327 : /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
328 : /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
329 : /* dst-out */ MakeCoeffFormula(kZero_GrBlendCoeff, kZero_GrBlendCoeff),
330 : /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kZero_GrBlendCoeff),
331 : /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
332 : /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
333 : /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
334 : /* modulate */ MakeCoeffFormula(kZero_GrBlendCoeff, kSC_GrBlendCoeff),
335 : /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
336 :
337 : }, /*>> Has coverage, input color opaque <<*/ {
338 :
339 : /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
340 : /* src */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
341 : /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
342 : /* src-over */ MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff),
343 : /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
344 : /* src-in */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
345 : /* dst-in */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
346 : /* src-out */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
347 : /* dst-out */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
348 : /* src-atop */ MakeCoeffFormula(kDA_GrBlendCoeff, kISA_GrBlendCoeff),
349 : /* dst-atop */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
350 : /* xor */ MakeCoeffFormula(kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
351 : /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
352 : /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
353 : /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
354 : }}};
355 :
356 : static MAYBE_CONSTEXPR BlendFormula gLCDBlendTable[(int)SkBlendMode::kLastCoeffMode + 1] = {
357 : /* clear */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kCoverage_OutputType),
358 : /* src */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
359 : /* dst */ MakeCoeffFormula(kZero_GrBlendCoeff, kOne_GrBlendCoeff),
360 : /* src-over */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
361 : /* dst-over */ MakeCoeffFormula(kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
362 : /* src-in */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
363 : /* dst-in */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISAModulate_OutputType),
364 : /* src-out */ MakeCoverageFormula(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
365 : /* dst-out */ MakeSAModulateFormula(kZero_GrBlendCoeff, kISC_GrBlendCoeff),
366 : /* src-atop */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
367 : /* dst-atop */ MakeCoverageFormula(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
368 : /* xor */ MakeCoverageFormula(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
369 : /* plus */ MakeCoeffFormula(kOne_GrBlendCoeff, kOne_GrBlendCoeff),
370 : /* modulate */ MakeCoverageSrcCoeffZeroFormula(BlendFormula::kISCModulate_OutputType),
371 : /* screen */ MakeCoeffFormula(kOne_GrBlendCoeff, kISC_GrBlendCoeff),
372 : };
373 :
374 : #undef MAYBE_CONSTEXPR
375 :
376 0 : static BlendFormula get_blend_formula(bool isOpaque,
377 : bool hasCoverage,
378 : bool hasMixedSamples,
379 : SkBlendMode xfermode) {
380 0 : SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
381 0 : bool conflatesCoverage = hasCoverage || hasMixedSamples;
382 0 : return gBlendTable[isOpaque][conflatesCoverage][(int)xfermode];
383 : }
384 :
385 0 : static BlendFormula get_lcd_blend_formula(SkBlendMode xfermode) {
386 0 : SkASSERT((unsigned)xfermode <= (unsigned)SkBlendMode::kLastCoeffMode);
387 :
388 0 : return gLCDBlendTable[(int)xfermode];
389 : }
390 :
391 : ///////////////////////////////////////////////////////////////////////////////
392 :
393 0 : class PorterDuffXferProcessor : public GrXferProcessor {
394 : public:
395 0 : PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
396 0 : this->initClassID<PorterDuffXferProcessor>();
397 0 : }
398 :
399 0 : const char* name() const override { return "Porter Duff"; }
400 :
401 : GrGLSLXferProcessor* createGLSLInstance() const override;
402 :
403 0 : BlendFormula getBlendFormula() const { return fBlendFormula; }
404 :
405 : private:
406 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
407 :
408 0 : bool onHasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
409 :
410 0 : void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
411 0 : blendInfo->fEquation = fBlendFormula.equation();
412 0 : blendInfo->fSrcBlend = fBlendFormula.srcCoeff();
413 0 : blendInfo->fDstBlend = fBlendFormula.dstCoeff();
414 0 : blendInfo->fWriteColor = fBlendFormula.modifiesDst();
415 0 : }
416 :
417 0 : bool onIsEqual(const GrXferProcessor& xpBase) const override {
418 0 : const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
419 0 : return fBlendFormula == xp.fBlendFormula;
420 : }
421 :
422 : const BlendFormula fBlendFormula;
423 :
424 : typedef GrXferProcessor INHERITED;
425 : };
426 :
427 : ///////////////////////////////////////////////////////////////////////////////
428 :
429 0 : static void append_color_output(const PorterDuffXferProcessor& xp,
430 : GrGLSLXPFragmentBuilder* fragBuilder,
431 : BlendFormula::OutputType outputType, const char* output,
432 : const char* inColor, const char* inCoverage) {
433 0 : SkASSERT(inCoverage);
434 0 : SkASSERT(inColor);
435 0 : switch (outputType) {
436 : case BlendFormula::kNone_OutputType:
437 0 : fragBuilder->codeAppendf("%s = vec4(0.0);", output);
438 0 : break;
439 : case BlendFormula::kCoverage_OutputType:
440 : // We can have a coverage formula while not reading coverage if there are mixed samples.
441 0 : fragBuilder->codeAppendf("%s = %s;", output, inCoverage);
442 0 : break;
443 : case BlendFormula::kModulate_OutputType:
444 0 : fragBuilder->codeAppendf("%s = %s * %s;", output, inColor, inCoverage);
445 0 : break;
446 : case BlendFormula::kSAModulate_OutputType:
447 0 : fragBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
448 0 : break;
449 : case BlendFormula::kISAModulate_OutputType:
450 0 : fragBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
451 0 : break;
452 : case BlendFormula::kISCModulate_OutputType:
453 0 : fragBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
454 0 : break;
455 : default:
456 0 : SkFAIL("Unsupported output type.");
457 0 : break;
458 : }
459 0 : }
460 :
461 0 : class GLPorterDuffXferProcessor : public GrGLSLXferProcessor {
462 : public:
463 0 : static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
464 0 : const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
465 0 : b->add32(xp.getBlendFormula().primaryOutput() |
466 0 : (xp.getBlendFormula().secondaryOutput() << 3));
467 : GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
468 0 : }
469 :
470 : private:
471 0 : void emitOutputsForBlendState(const EmitArgs& args) override {
472 0 : const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
473 0 : GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
474 :
475 0 : BlendFormula blendFormula = xp.getBlendFormula();
476 0 : if (blendFormula.hasSecondaryOutput()) {
477 0 : append_color_output(xp, fragBuilder, blendFormula.secondaryOutput(),
478 0 : args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
479 : }
480 0 : append_color_output(xp, fragBuilder, blendFormula.primaryOutput(), args.fOutputPrimary,
481 0 : args.fInputColor, args.fInputCoverage);
482 0 : }
483 :
484 0 : void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
485 :
486 : typedef GrGLSLXferProcessor INHERITED;
487 : };
488 :
489 : ///////////////////////////////////////////////////////////////////////////////
490 :
491 0 : void PorterDuffXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
492 : GrProcessorKeyBuilder* b) const {
493 0 : GLPorterDuffXferProcessor::GenKey(*this, b);
494 0 : }
495 :
496 0 : GrGLSLXferProcessor* PorterDuffXferProcessor::createGLSLInstance() const {
497 0 : return new GLPorterDuffXferProcessor;
498 : }
499 :
500 : ///////////////////////////////////////////////////////////////////////////////
501 :
502 0 : class ShaderPDXferProcessor : public GrXferProcessor {
503 : public:
504 0 : ShaderPDXferProcessor(bool hasMixedSamples, SkBlendMode xfermode)
505 0 : : INHERITED(true, hasMixedSamples), fXfermode(xfermode) {
506 0 : this->initClassID<ShaderPDXferProcessor>();
507 0 : }
508 :
509 0 : const char* name() const override { return "Porter Duff Shader"; }
510 :
511 : GrGLSLXferProcessor* createGLSLInstance() const override;
512 :
513 0 : SkBlendMode getXfermode() const { return fXfermode; }
514 :
515 : private:
516 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
517 :
518 0 : bool onIsEqual(const GrXferProcessor& xpBase) const override {
519 0 : const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
520 0 : return fXfermode == xp.fXfermode;
521 : }
522 :
523 : const SkBlendMode fXfermode;
524 :
525 : typedef GrXferProcessor INHERITED;
526 : };
527 :
528 : ///////////////////////////////////////////////////////////////////////////////
529 :
530 0 : class GLShaderPDXferProcessor : public GrGLSLXferProcessor {
531 : public:
532 0 : static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
533 0 : const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
534 0 : b->add32((int)xp.getXfermode());
535 0 : }
536 :
537 : private:
538 0 : void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
539 : GrGLSLUniformHandler* uniformHandler,
540 : const char* srcColor,
541 : const char* srcCoverage,
542 : const char* dstColor,
543 : const char* outColor,
544 : const char* outColorSecondary,
545 : const GrXferProcessor& proc) override {
546 0 : const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
547 :
548 0 : GrGLSLBlend::AppendMode(fragBuilder, srcColor, dstColor, outColor, xp.getXfermode());
549 :
550 : // Apply coverage.
551 0 : INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
552 0 : outColorSecondary, xp);
553 0 : }
554 :
555 0 : void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {}
556 :
557 : typedef GrGLSLXferProcessor INHERITED;
558 : };
559 :
560 : ///////////////////////////////////////////////////////////////////////////////
561 :
562 0 : void ShaderPDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&,
563 : GrProcessorKeyBuilder* b) const {
564 0 : GLShaderPDXferProcessor::GenKey(*this, b);
565 0 : }
566 :
567 0 : GrGLSLXferProcessor* ShaderPDXferProcessor::createGLSLInstance() const {
568 0 : return new GLShaderPDXferProcessor;
569 : }
570 :
571 : ///////////////////////////////////////////////////////////////////////////////
572 :
573 : class PDLCDXferProcessor : public GrXferProcessor {
574 : public:
575 : static sk_sp<const GrXferProcessor> Make(SkBlendMode mode,
576 : const GrProcessorAnalysisColor& inputColor);
577 :
578 : ~PDLCDXferProcessor() override;
579 :
580 0 : const char* name() const override { return "Porter Duff LCD"; }
581 :
582 : GrGLSLXferProcessor* createGLSLInstance() const override;
583 :
584 0 : uint8_t alpha() const { return fAlpha; }
585 :
586 : private:
587 : PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha);
588 :
589 : void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override;
590 :
591 0 : void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
592 0 : blendInfo->fSrcBlend = kConstC_GrBlendCoeff;
593 0 : blendInfo->fDstBlend = kISC_GrBlendCoeff;
594 0 : blendInfo->fBlendConstant = fBlendConstant;
595 0 : }
596 :
597 0 : bool onIsEqual(const GrXferProcessor& xpBase) const override {
598 0 : const PDLCDXferProcessor& xp = xpBase.cast<PDLCDXferProcessor>();
599 0 : if (fBlendConstant != xp.fBlendConstant || fAlpha != xp.fAlpha) {
600 0 : return false;
601 : }
602 0 : return true;
603 : }
604 :
605 : GrColor fBlendConstant;
606 : uint8_t fAlpha;
607 :
608 : typedef GrXferProcessor INHERITED;
609 : };
610 :
611 : ///////////////////////////////////////////////////////////////////////////////
612 :
613 : class GLPDLCDXferProcessor : public GrGLSLXferProcessor {
614 : public:
615 0 : GLPDLCDXferProcessor(const GrProcessor&) : fLastAlpha(SK_MaxU32) {}
616 :
617 0 : ~GLPDLCDXferProcessor() override {}
618 :
619 0 : static void GenKey(const GrProcessor& processor, const GrShaderCaps& caps,
620 0 : GrProcessorKeyBuilder* b) {}
621 :
622 : private:
623 0 : void emitOutputsForBlendState(const EmitArgs& args) override {
624 : const char* alpha;
625 0 : fAlphaUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
626 0 : kDefault_GrSLPrecision, "alpha", &alpha);
627 0 : GrGLSLXPFragmentBuilder* fragBuilder = args.fXPFragBuilder;
628 : // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
629 : // value of the src color. We know that there are no color stages (or we wouldn't have
630 : // created this xp) and the r,g, and b channels of the op's input color are baked into the
631 : // blend constant.
632 0 : SkASSERT(args.fInputCoverage);
633 0 : fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, alpha, args.fInputCoverage);
634 0 : }
635 :
636 0 : void onSetData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp) override {
637 0 : uint32_t alpha = SkToU32(xp.cast<PDLCDXferProcessor>().alpha());
638 0 : if (fLastAlpha != alpha) {
639 0 : pdm.set1f(fAlphaUniform, alpha / 255.f);
640 0 : fLastAlpha = alpha;
641 : }
642 0 : }
643 :
644 : GrGLSLUniformHandler::UniformHandle fAlphaUniform;
645 : uint32_t fLastAlpha;
646 : typedef GrGLSLXferProcessor INHERITED;
647 : };
648 :
649 : ///////////////////////////////////////////////////////////////////////////////
650 :
651 0 : PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
652 : : fBlendConstant(blendConstant)
653 0 : , fAlpha(alpha) {
654 0 : this->initClassID<PDLCDXferProcessor>();
655 0 : }
656 :
657 0 : sk_sp<const GrXferProcessor> PDLCDXferProcessor::Make(SkBlendMode mode,
658 : const GrProcessorAnalysisColor& color) {
659 0 : if (SkBlendMode::kSrcOver != mode) {
660 0 : return nullptr;
661 : }
662 : GrColor blendConstant;
663 0 : if (!color.isConstant(&blendConstant)) {
664 0 : return nullptr;
665 : }
666 0 : blendConstant = GrUnpremulColor(blendConstant);
667 0 : uint8_t alpha = GrColorUnpackA(blendConstant);
668 0 : blendConstant |= (0xff << GrColor_SHIFT_A);
669 0 : return sk_sp<GrXferProcessor>(new PDLCDXferProcessor(blendConstant, alpha));
670 : }
671 :
672 0 : PDLCDXferProcessor::~PDLCDXferProcessor() {
673 0 : }
674 :
675 0 : void PDLCDXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
676 : GrProcessorKeyBuilder* b) const {
677 0 : GLPDLCDXferProcessor::GenKey(*this, caps, b);
678 0 : }
679 :
680 0 : GrGLSLXferProcessor* PDLCDXferProcessor::createGLSLInstance() const {
681 0 : return new GLPDLCDXferProcessor(*this);
682 : }
683 :
684 : ///////////////////////////////////////////////////////////////////////////////
685 :
686 : constexpr GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkBlendMode xfermode)
687 : : fBlendMode(xfermode) {}
688 :
689 0 : const GrXPFactory* GrPorterDuffXPFactory::Get(SkBlendMode blendMode) {
690 0 : SkASSERT((unsigned)blendMode <= (unsigned)SkBlendMode::kLastCoeffMode);
691 :
692 : // If these objects are constructed as static constexpr by cl.exe (2015 SP2) the vtables are
693 : // null.
694 : #ifdef SK_BUILD_FOR_WIN
695 : #define _CONSTEXPR_
696 : #else
697 : #define _CONSTEXPR_ constexpr
698 : #endif
699 : static _CONSTEXPR_ const GrPorterDuffXPFactory gClearPDXPF(SkBlendMode::kClear);
700 : static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcPDXPF(SkBlendMode::kSrc);
701 : static _CONSTEXPR_ const GrPorterDuffXPFactory gDstPDXPF(SkBlendMode::kDst);
702 : static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOverPDXPF(SkBlendMode::kSrcOver);
703 : static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOverPDXPF(SkBlendMode::kDstOver);
704 : static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcInPDXPF(SkBlendMode::kSrcIn);
705 : static _CONSTEXPR_ const GrPorterDuffXPFactory gDstInPDXPF(SkBlendMode::kDstIn);
706 : static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcOutPDXPF(SkBlendMode::kSrcOut);
707 : static _CONSTEXPR_ const GrPorterDuffXPFactory gDstOutPDXPF(SkBlendMode::kDstOut);
708 : static _CONSTEXPR_ const GrPorterDuffXPFactory gSrcATopPDXPF(SkBlendMode::kSrcATop);
709 : static _CONSTEXPR_ const GrPorterDuffXPFactory gDstATopPDXPF(SkBlendMode::kDstATop);
710 : static _CONSTEXPR_ const GrPorterDuffXPFactory gXorPDXPF(SkBlendMode::kXor);
711 : static _CONSTEXPR_ const GrPorterDuffXPFactory gPlusPDXPF(SkBlendMode::kPlus);
712 : static _CONSTEXPR_ const GrPorterDuffXPFactory gModulatePDXPF(SkBlendMode::kModulate);
713 : static _CONSTEXPR_ const GrPorterDuffXPFactory gScreenPDXPF(SkBlendMode::kScreen);
714 : #undef _CONSTEXPR_
715 :
716 0 : switch (blendMode) {
717 : case SkBlendMode::kClear:
718 0 : return &gClearPDXPF;
719 : case SkBlendMode::kSrc:
720 0 : return &gSrcPDXPF;
721 : case SkBlendMode::kDst:
722 0 : return &gDstPDXPF;
723 : case SkBlendMode::kSrcOver:
724 0 : return &gSrcOverPDXPF;
725 : case SkBlendMode::kDstOver:
726 0 : return &gDstOverPDXPF;
727 : case SkBlendMode::kSrcIn:
728 0 : return &gSrcInPDXPF;
729 : case SkBlendMode::kDstIn:
730 0 : return &gDstInPDXPF;
731 : case SkBlendMode::kSrcOut:
732 0 : return &gSrcOutPDXPF;
733 : case SkBlendMode::kDstOut:
734 0 : return &gDstOutPDXPF;
735 : case SkBlendMode::kSrcATop:
736 0 : return &gSrcATopPDXPF;
737 : case SkBlendMode::kDstATop:
738 0 : return &gDstATopPDXPF;
739 : case SkBlendMode::kXor:
740 0 : return &gXorPDXPF;
741 : case SkBlendMode::kPlus:
742 0 : return &gPlusPDXPF;
743 : case SkBlendMode::kModulate:
744 0 : return &gModulatePDXPF;
745 : case SkBlendMode::kScreen:
746 0 : return &gScreenPDXPF;
747 : default:
748 0 : SkFAIL("Unexpected blend mode.");
749 0 : return nullptr;
750 : }
751 : }
752 :
753 0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::makeXferProcessor(
754 : const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
755 : bool hasMixedSamples, const GrCaps& caps) const {
756 0 : BlendFormula blendFormula;
757 0 : if (coverage == GrProcessorAnalysisCoverage::kLCD) {
758 0 : if (SkBlendMode::kSrcOver == fBlendMode && color.isConstant() &&
759 0 : !caps.shaderCaps()->dualSourceBlendingSupport() &&
760 0 : !caps.shaderCaps()->dstReadInShaderSupport()) {
761 : // If we don't have dual source blending or in shader dst reads, we fall back to this
762 : // trick for rendering SrcOver LCD text instead of doing a dst copy.
763 0 : return PDLCDXferProcessor::Make(fBlendMode, color);
764 : }
765 0 : blendFormula = get_lcd_blend_formula(fBlendMode);
766 : } else {
767 : blendFormula =
768 0 : get_blend_formula(color.isOpaque(), GrProcessorAnalysisCoverage::kNone != coverage,
769 0 : hasMixedSamples, fBlendMode);
770 : }
771 :
772 0 : if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
773 0 : return sk_sp<const GrXferProcessor>(new ShaderPDXferProcessor(hasMixedSamples, fBlendMode));
774 : }
775 0 : return sk_sp<const GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
776 : }
777 :
778 0 : static inline GrXPFactory::AnalysisProperties analysis_properties(
779 : const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage,
780 : const GrCaps& caps, SkBlendMode mode) {
781 : using AnalysisProperties = GrXPFactory::AnalysisProperties;
782 0 : AnalysisProperties props = AnalysisProperties::kNone;
783 0 : bool hasCoverage = GrProcessorAnalysisCoverage::kNone != coverage;
784 0 : auto formula = gBlendTable[color.isOpaque()][hasCoverage][(int)mode];
785 0 : if (formula.canTweakAlphaForCoverage()) {
786 0 : props |= AnalysisProperties::kCompatibleWithAlphaAsCoverage;
787 : }
788 : // With dual-source blending we never need the destination color in the shader.
789 0 : if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
790 : // Mixed samples implicity computes a fractional coverage from sample coverage. This could
791 : // affect the formula used. However, we don't expect to have mixed samples without dual
792 : // source blending.
793 0 : SkASSERT(!caps.usesMixedSamples());
794 0 : if (GrProcessorAnalysisCoverage::kLCD == coverage) {
795 : // Check for special case of srcover with a known color which can be done using the
796 : // blend constant.
797 0 : if (SkBlendMode::kSrcOver == mode && color.isConstant()) {
798 0 : props |= AnalysisProperties::kIgnoresInputColor;
799 : } else {
800 0 : if (get_lcd_blend_formula(mode).hasSecondaryOutput()) {
801 0 : props |= AnalysisProperties::kReadsDstInShader;
802 : }
803 : }
804 0 : } else if (formula.hasSecondaryOutput()) {
805 0 : props |= AnalysisProperties::kReadsDstInShader;
806 : }
807 : }
808 0 : if (!formula.modifiesDst() || !formula.usesInputColor()) {
809 0 : props |= AnalysisProperties::kIgnoresInputColor;
810 : }
811 : // Ignore the effect of coverage here for overlap stencil and cover property
812 0 : auto colorFormula = gBlendTable[color.isOpaque()][0][(int)mode];
813 0 : SkASSERT(kAdd_GrBlendEquation == colorFormula.equation());
814 0 : if (!colorFormula.usesDstColor()) {
815 0 : props |= AnalysisProperties::kCanCombineOverlappedStencilAndCover;
816 : }
817 0 : return props;
818 : }
819 :
820 0 : GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::analysisProperties(
821 : const GrProcessorAnalysisColor& color,
822 : const GrProcessorAnalysisCoverage& coverage,
823 : const GrCaps& caps) const {
824 0 : return analysis_properties(color, coverage, caps, fBlendMode);
825 : }
826 :
827 : GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
828 :
829 : #if GR_TEST_UTILS
830 0 : const GrXPFactory* GrPorterDuffXPFactory::TestGet(GrProcessorTestData* d) {
831 0 : SkBlendMode mode = SkBlendMode(d->fRandom->nextULessThan((int)SkBlendMode::kLastCoeffMode));
832 0 : return GrPorterDuffXPFactory::Get(mode);
833 : }
834 : #endif
835 :
836 0 : void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
837 : int* outPrimary,
838 : int* outSecondary) {
839 0 : if (!!strcmp(xp->name(), "Porter Duff")) {
840 0 : *outPrimary = *outSecondary = -1;
841 0 : return;
842 : }
843 0 : BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
844 0 : *outPrimary = blendFormula.primaryOutput();
845 0 : *outSecondary = blendFormula.secondaryOutput();
846 : }
847 :
848 : ////////////////////////////////////////////////////////////////////////////////////////////////
849 : // SrcOver Global functions
850 : ////////////////////////////////////////////////////////////////////////////////////////////////
851 0 : const GrXferProcessor& GrPorterDuffXPFactory::SimpleSrcOverXP() {
852 : static BlendFormula gSrcOverBlendFormula =
853 : MakeCoeffFormula(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
854 0 : static PorterDuffXferProcessor gSrcOverXP(gSrcOverBlendFormula);
855 0 : return gSrcOverXP;
856 : }
857 :
858 0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeSrcOverXferProcessor(
859 : const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage,
860 : bool hasMixedSamples, const GrCaps& caps) {
861 : // We want to not make an xfer processor if possible. Thus for the simple case where we are not
862 : // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from
863 : // the general case where we convert a src-over blend that has solid coverage and an opaque
864 : // color to src-mode, which allows disabling of blending.
865 0 : if (coverage != GrProcessorAnalysisCoverage::kLCD) {
866 : // We return nullptr here, which our caller interprets as meaning "use SimpleSrcOverXP".
867 : // We don't simply return the address of that XP here because our caller would have to unref
868 : // it and since it is a global object and GrProgramElement's ref-cnting system is not thread
869 : // safe.
870 0 : return nullptr;
871 : }
872 :
873 0 : if (color.isConstant() && !caps.shaderCaps()->dualSourceBlendingSupport() &&
874 0 : !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 0 : return PDLCDXferProcessor::Make(SkBlendMode::kSrcOver, color);
879 : }
880 :
881 0 : BlendFormula blendFormula;
882 0 : blendFormula = get_lcd_blend_formula(SkBlendMode::kSrcOver);
883 0 : if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
884 0 : return sk_sp<GrXferProcessor>(
885 0 : new ShaderPDXferProcessor(hasMixedSamples, SkBlendMode::kSrcOver));
886 : }
887 0 : return sk_sp<GrXferProcessor>(new PorterDuffXferProcessor(blendFormula));
888 : }
889 :
890 0 : sk_sp<const GrXferProcessor> GrPorterDuffXPFactory::MakeNoCoverageXP(SkBlendMode blendmode) {
891 0 : BlendFormula formula = get_blend_formula(false, false, false, blendmode);
892 0 : return sk_make_sp<PorterDuffXferProcessor>(formula);
893 : }
894 :
895 0 : GrXPFactory::AnalysisProperties GrPorterDuffXPFactory::SrcOverAnalysisProperties(
896 : const GrProcessorAnalysisColor& color,
897 : const GrProcessorAnalysisCoverage& coverage,
898 : const GrCaps& caps) {
899 0 : return analysis_properties(color, coverage, caps, SkBlendMode::kSrcOver);
900 : }
|