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