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